diff --git a/CMakeLists.txt b/CMakeLists.txt index 680a9515d7..88db091a81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -507,7 +507,7 @@ add_custom_target(gettext_make_pot COMMAND xgettext --keyword=L --keyword=_L --keyword=_u8L --keyword=L_CONTEXT:1,2c --keyword=_L_PLURAL:1,2 --add-comments=TRN --from-code=UTF-8 --no-location --debug --boost -f "${BBL_L18N_DIR}/list.txt" -o "${BBL_L18N_DIR}/BambuStudio.pot" - COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${BBL_L18N_DIR} + COMMAND hintsToPot ${SLIC3R_RESOURCES_DIR} ${BBL_L18N_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT "Generate pot file from strings in the source tree" ) diff --git a/bbl/i18n/BambuStudio.pot b/bbl/i18n/BambuStudio.pot index 7d7c2e4b3b..950f131fcf 100644 --- a/bbl/i18n/BambuStudio.pot +++ b/bbl/i18n/BambuStudio.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -27,6 +27,9 @@ msgstr "" msgid "Section view" msgstr "" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "" @@ -72,6 +75,9 @@ msgstr "" msgid "Smart fill angle" msgstr "" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "" @@ -87,6 +93,10 @@ msgstr "" msgid "Gap Fill" msgstr "" +#, possible-boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "" @@ -141,6 +151,12 @@ msgstr "" msgid "Height range" msgstr "" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "" @@ -333,9 +349,6 @@ msgstr "" msgid "Perform Recognition" msgstr "" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -354,15 +367,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -498,7 +502,7 @@ msgstr "" msgid "Choose one file (3mf):" msgstr "" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" @@ -578,6 +582,9 @@ msgstr "" msgid "Support" msgstr "" +msgid "Flush options" +msgstr "" + msgid "Speed" msgstr "" @@ -711,6 +718,18 @@ msgstr "" msgid "Scale an object to fit the build volume" msgstr "" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "" + +msgid "Flush into this object" +msgstr "" + +msgid "Flush into objects' support" +msgstr "" + msgid "Convert from inch" msgstr "" @@ -762,6 +781,9 @@ msgstr "" msgid "Add Primitive" msgstr "" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "" @@ -828,6 +850,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -915,6 +940,14 @@ msgstr "" msgid "Add Modifier" msgstr "" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "" @@ -1054,6 +1087,9 @@ msgstr "" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1066,6 +1102,15 @@ msgstr "" msgid "OK" msgstr "" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1087,7 +1132,7 @@ msgstr "" msgid "No printer" msgstr "" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1277,12 +1322,34 @@ msgid "Sending print configuration" msgstr "" #, possible-c-format, possible-boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "" @@ -1292,7 +1359,7 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" +msgid "Install successfully." msgstr "" msgid "Installing" @@ -1379,6 +1446,9 @@ msgstr "" msgid "SN" msgstr "" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "" @@ -1404,6 +1474,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "" @@ -1440,6 +1523,23 @@ msgid "" "last shutdown." msgstr "" +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "" @@ -1626,6 +1726,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1675,6 +1780,17 @@ msgid "" "No - Give up using spiral mode this time" msgstr "" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1812,6 +1928,9 @@ msgstr "" msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "" + msgid "parameter name" msgstr "" @@ -1876,6 +1995,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "" @@ -1885,6 +2010,9 @@ msgstr "" msgid "Generating geometry index data" msgstr "" +msgid "Display" +msgstr "" + msgid "up to" msgstr "" @@ -1900,13 +2028,10 @@ msgstr "" msgid "Color Scheme" msgstr "" -msgid "Percent" -msgstr "" - msgid "Time" msgstr "" -msgid "Display" +msgid "Percent" msgstr "" msgid "Layer Height (mm)" @@ -1930,13 +2055,10 @@ msgstr "" msgid "Used filament" msgstr "" -msgid "Filament N XX" +msgid "Flushed" msgstr "" -msgid "Color Print" -msgstr "" - -msgid "Comsumption" +msgid "Total" msgstr "" msgid "Travel" @@ -1966,18 +2088,12 @@ msgstr "" msgid "Extruder" msgstr "" -msgid "Filament 1" -msgstr "" - -msgid "Flushed filament" -msgstr "" - -msgid "Total" -msgstr "" - msgid "Filament change times" msgstr "" +msgid "Cost" +msgstr "" + msgid "Color change" msgstr "" @@ -1996,10 +2112,10 @@ msgstr "" msgid "Total Estimation" msgstr "" -msgid "Normal mode" +msgid "Time Estimation" msgstr "" -msgid "Cost" +msgid "Normal mode" msgstr "" msgid "Prepare time" @@ -2008,12 +2124,63 @@ msgstr "" msgid "Model printing time" msgstr "" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "" msgid "Switch to normal mode" msgstr "" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "" @@ -2125,6 +2292,18 @@ msgstr "" msgid "Calibration" msgstr "" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "" @@ -2146,10 +2325,22 @@ msgstr "" msgid "Calibrating" msgstr "" -msgid "Timelapse" +msgid "Auto-record Monitoring" msgstr "" -msgid "Monitoring Recording" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" msgstr "" msgid "ConnectPrinter(LAN)" @@ -2193,6 +2384,15 @@ msgstr "" msgid "Project" msgstr "" +msgid "Yes" +msgstr "" + +msgid "No" +msgstr "" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "" @@ -2202,16 +2402,25 @@ msgstr "" msgid "Slice plate" msgstr "" -msgid "Print all" -msgstr "" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" +msgid "Send" msgstr "" -msgid "Export Sliced File" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "" + +msgid "Send all" msgstr "" msgid "Keyboard Shortcuts" @@ -2226,17 +2435,23 @@ msgstr "" msgid "Show Configuration Folder" msgstr "" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "" +msgid "Open Network Test" +msgstr "" + #, possible-c-format, possible-boost-format msgid "&About %s" msgstr "" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2307,7 +2522,7 @@ msgstr "" msgid "Save current project as" msgstr "" -msgid "Import 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" msgstr "" msgid "Load a model" @@ -2331,7 +2546,10 @@ msgstr "" msgid "Export 3mf file without using some 3mf-extensions" msgstr "" -msgid "Export current Sliced file" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" msgstr "" msgid "Export G-code" @@ -2424,6 +2642,9 @@ msgstr "" msgid "Help" msgstr "" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "" @@ -2442,10 +2663,10 @@ msgstr "" msgid "Export toolpaths as OBJ" msgstr "" -msgid "Open &PrusaSlicer" +msgid "Open &Studio" msgstr "" -msgid "Open PrusaSlicer" +msgid "Open Studio" msgstr "" msgid "&Quit" @@ -2536,7 +2757,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, possible-c-format, possible-boost-format @@ -2553,6 +2777,27 @@ msgstr "" msgid "Stopped." msgstr "" +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "" @@ -2578,6 +2823,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "" + msgid "Switch to timelapse files." msgstr "" @@ -2605,7 +2853,7 @@ msgstr "" msgid "No printers." msgstr "" -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2621,6 +2869,12 @@ msgstr "" msgid "No files" msgstr "" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, possible-c-format, possible-boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2665,6 +2919,12 @@ msgstr "" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "" @@ -2692,10 +2952,10 @@ msgstr "" msgid "Lamp" msgstr "" -msgid "Part Cooling" +msgid "Aux" msgstr "" -msgid "Aux Cooling" +msgid "Cham" msgstr "" msgid "Bed" @@ -2707,6 +2967,12 @@ msgstr "" msgid "Debug Info" msgstr "" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "" @@ -2716,9 +2982,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, possible-c-format, possible-boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "" +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2734,6 +3029,9 @@ msgstr "" msgid "Ludicrous" msgstr "" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "" @@ -2752,10 +3050,7 @@ msgstr "" msgid "Failed to connect to the printer" msgstr "" -msgid "Yes" -msgstr "" - -msgid "No" +msgid "Don't show again" msgstr "" #, possible-c-format, possible-boost-format @@ -2860,7 +3155,7 @@ msgstr "" msgid "Warning:" msgstr "" -msgid "Export ok." +msgid "Export successfully." msgstr "" msgid " (Repair)" @@ -2890,9 +3185,6 @@ msgstr "" msgid "Range" msgstr "" -msgid "default" -msgstr "" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -2921,19 +3213,24 @@ msgctxt "Layers" msgid "Bottom" msgstr "" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." -msgstr "" - -msgid "Don't show again" +msgid "Auto-recovery from step loss" msgstr "" msgid "Global" @@ -3003,7 +3300,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3024,6 +3321,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "" @@ -3052,6 +3355,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, possible-c-format, possible-boost-format msgid "Loading file: %s" msgstr "" @@ -3158,9 +3467,6 @@ msgstr "" msgid "Another export job is running." msgstr "" -msgid "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3185,6 +3491,9 @@ msgstr "" msgid "Invalid data" msgstr "" +msgid "Slicing Canceled" +msgstr "" + #, possible-c-format, possible-boost-format msgid "Slicing Plate %d" msgstr "" @@ -3210,6 +3519,28 @@ msgstr "" msgid "Load project" msgstr "" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "" @@ -3267,6 +3598,12 @@ msgstr "" msgid "Save Sliced file as:" msgstr "" +#, possible-c-format, possible-boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3284,6 +3621,9 @@ msgstr "" msgid "Invalid number" msgstr "" +msgid "Select Bed Type" +msgstr "" + #, possible-boost-format msgid "Part name: %1%\n" msgstr "" @@ -3312,6 +3652,18 @@ msgstr "" msgid "Triangles: %1%\n" msgstr "" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "" @@ -3420,6 +3772,12 @@ msgstr "" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "" @@ -3531,6 +3889,15 @@ msgstr "" msgid "Project-inside presets" msgstr "" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "" @@ -3681,9 +4048,6 @@ msgstr "" msgid "Flow Calibration" msgstr "" -msgid "Send" -msgstr "" - msgid "send completed" msgstr "" @@ -3699,7 +4063,7 @@ msgstr "" msgid "Synchronizing device information time out" msgstr "" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "" msgid "" @@ -3749,10 +4113,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3761,18 +4138,49 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, possible-c-format, possible-boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "" msgid "Modifying the device name" msgstr "" -msgid "Send to Printer" +msgid "Send to Printer SD card" +msgstr "" + +msgid "Cannot send the print task when the upgrade is in progress" msgstr "" msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "" + +msgid "Engineering Plate" +msgstr "" + +msgid "High Temp Plate" +msgstr "" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "" @@ -3812,13 +4220,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -3837,6 +4245,9 @@ msgstr "" msgid "Precision" msgstr "" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "" @@ -3864,15 +4275,15 @@ msgstr "" msgid "Acceleration" msgstr "" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "" msgid "Prime tower" msgstr "" -msgid "Flush options" -msgstr "" - msgid "Special mode" msgstr "" @@ -3940,17 +4351,11 @@ msgid "" "filament does not support to print on the Engineering Plate" msgstr "" -msgid "High Temp Plate" -msgstr "" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" msgstr "" -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4151,9 +4556,17 @@ msgid "" "contains the following unsaved changes:" msgstr "" +#, possible-boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" msgid "Extruders count" @@ -4165,6 +4578,11 @@ msgstr "" msgid "Capabilities" msgstr "" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4246,16 +4664,27 @@ msgstr "" msgid "The configuration is up to date." msgstr "" -msgid "Auto-Calc" +msgid "Flushing volumes for filament change" msgstr "" -msgid "Flushing volumes for filament change" +msgid "Auto-Calc" msgstr "" msgid "Flushing volume (mm³) for each filament pair." msgstr "" -msgid "Flush multiplier" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, possible-c-format, possible-boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." msgstr "" msgid "unloaded" @@ -4529,7 +4958,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4541,13 +4970,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4567,6 +4996,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "" @@ -4803,12 +5235,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, possible-boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, possible-boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "" @@ -4881,6 +5307,11 @@ msgid "" "heights." msgstr "" +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "" @@ -4899,7 +5330,7 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "" #, possible-c-format, possible-boost-format -msgid "Plate %d: %s does not support filament %s.\n" +msgid "Plate %d: %s does not support filament %s\n" msgstr "" msgid "Generating skirt & brim" @@ -4926,6 +5357,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "" @@ -5083,12 +5520,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "" -msgid "Cool Plate" -msgstr "" - -msgid "Engineering Plate" -msgstr "" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "" @@ -5132,10 +5563,21 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "" +#, possible-c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" msgid "Bridge flow" @@ -5214,6 +5656,9 @@ msgstr "" msgid "Compatible machine" msgstr "" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "" @@ -5290,9 +5735,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5317,6 +5759,25 @@ msgstr "" msgid "End G-code when finish the printing of this filament" msgstr "" +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "" @@ -5341,6 +5802,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "" @@ -5389,9 +5856,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5448,16 +5912,30 @@ msgstr "" msgid "s" msgstr "" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" msgid "mm³/s" @@ -5577,6 +6055,12 @@ msgstr "" msgid "Adaptive Cubic" msgstr "" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5585,6 +6069,9 @@ msgid "" "surface quality" msgstr "" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5601,17 +6088,6 @@ msgid "" "can improve build plate adhension" msgstr "" -msgid "Adaptive layer height" -msgstr "" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" - msgid "Speed of initial layer except the solid infill part" msgstr "" @@ -5704,6 +6180,17 @@ msgstr "" msgid "Brass" msgstr "" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" @@ -6029,9 +6516,6 @@ msgid "" "avoid wrapping when print ABS" msgstr "" -msgid "Resolution" -msgstr "" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6165,9 +6649,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6192,6 +6673,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "" @@ -6212,10 +6710,10 @@ msgstr "" msgid "hybrid(auto)" msgstr "" -msgid "normal" +msgid "normal(manual)" msgstr "" -msgid "tree" +msgid "tree(manual)" msgstr "" msgid "Support/object xy distance" @@ -6250,9 +6748,15 @@ msgstr "" msgid "The z gap between the top support interface and object" msgstr "" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" msgid "Line width of support" @@ -6266,8 +6770,8 @@ msgid "" msgstr "" msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" msgid "Top interface layers" @@ -6318,6 +6822,12 @@ msgstr "" msgid "Spacing between support lines" msgstr "" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "" @@ -6371,14 +6881,6 @@ msgstr "" msgid "This setting specify the count of walls around tree support" msgstr "" -msgid "Tree support with infill" -msgstr "" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" - msgid "Nozzle temperature for layers after the initial one" msgstr "" @@ -6461,6 +6963,14 @@ msgstr "" msgid "Purging volumes" msgstr "" +msgid "Flush multiplier" +msgstr "" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "" @@ -6473,31 +6983,23 @@ msgstr "" msgid "Width of prime tower" msgstr "" -msgid "Flush into objects' infill" -msgstr "" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" -msgstr "" - -msgid "Flush into objects' support" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" -msgstr "" - -msgid "Flush into this object" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" msgid "X-Y hole compensation" @@ -6519,6 +7021,79 @@ msgid "" "assembling issue" msgstr "" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "" @@ -6534,12 +7109,30 @@ msgstr "" msgid "Export project as 3MF." msgstr "" +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 the plates: 0-all plates, i-plate i, others-invalid" msgstr "" msgid "Show command help." msgstr "" +msgid "UpToDate" +msgstr "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "" @@ -6552,6 +7145,12 @@ msgstr "" msgid "Export settings to a file." msgstr "" +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "" @@ -6567,12 +7166,6 @@ msgstr "" msgid "Orient the model" msgstr "" -msgid "Repair" -msgstr "" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "" - msgid "Scale the model by a float factor" msgstr "" @@ -6643,9 +7236,6 @@ msgstr "" msgid "Slicing mesh" msgstr "" -msgid " Object:" -msgstr "" - #, possible-c-format, possible-boost-format msgid "Support: generate toolpath at layer %d" msgstr "" @@ -6764,3 +7354,15 @@ msgstr "" #: resources/data/hints.ini: [hint:Set parameters for multiple objects] msgid "Set parameters for multiple objects\nDid you know that you can set slicing parameters for all selected objects at one time?" msgstr "" + +#: resources/data/hints.ini: [hint:Stack objects] +msgid "Stack objects\nDid you know that you can stack objects as a whole one?" +msgstr "" + +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "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?" +msgstr "" + +#: resources/data/hints.ini: [hint:Improve strength] +msgid "Improve strength\nDid you know that you can use more wall loops and higher sparse infill density to improve the strength of the model?" +msgstr "" diff --git a/bbl/i18n/de/BambuStudio_de.po b/bbl/i18n/de/BambuStudio_de.po index cda86a0ea0..8de39dc828 100644 --- a/bbl/i18n/de/BambuStudio_de.po +++ b/bbl/i18n/de/BambuStudio_de.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -22,6 +22,9 @@ msgstr "Alt + Mausrad" msgid "Section view" msgstr "Abschnittsansicht" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Strg + Mausrad" @@ -67,6 +70,9 @@ msgstr "Werkzeugtyp" msgid "Smart fill angle" msgstr "Intelligenter Füllwinkel" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Winkel für automatische Supports: " @@ -82,6 +88,10 @@ msgstr "Ausfüllen" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Markieren der Flächen entsprechend dem Überhangwinkel." @@ -139,6 +149,12 @@ msgstr "Eimerfüllung" msgid "Height range" msgstr "Höhenreichweite" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Shortcut Taste " @@ -335,9 +351,6 @@ msgstr "Gesichtserkennung" msgid "Perform Recognition" msgstr "Erkennung durchführen" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -356,15 +369,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -515,8 +519,8 @@ msgstr "Laden einer Modusansicht" msgid "Choose one file (3mf):" msgstr "Wählen sie eine Datei (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Wählen sie eine oder mer Dateien (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Wählen sie eine Datei (gcode/.gco/.g/.ngc/ngc):" @@ -599,6 +603,9 @@ msgstr "Füllung" msgid "Support" msgstr "Support" +msgid "Flush options" +msgstr "Optionen für die Druckdüsensäuberung" + msgid "Speed" msgstr "Geschwindigkeit" @@ -732,6 +739,18 @@ msgstr "Auf Druckvolumen skalieren" msgid "Scale an object to fit the build volume" msgstr "Objekt skalieren, dass es in den Druckraum passt" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Druckdüse in der Füllung der Objekte säubern" + +msgid "Flush into this object" +msgstr "Druckdüse in diesem Objekt säubern" + +msgid "Flush into objects' support" +msgstr "Druckdüse in der Supportstruktur des Objekts säubern" + msgid "Convert from inch" msgstr "Von Inch umrechnen" @@ -784,6 +803,9 @@ msgstr "Objekt spiegeln" msgid "Add Primitive" msgstr "Primitiv hinzufügen" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "Zu Objekten" @@ -851,6 +873,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -950,6 +975,16 @@ msgstr "Generisch" msgid "Add Modifier" msgstr "Modifizierer hinzufügen" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" +"Wechseln Sie in den objektbezogenen Einstellungsmodus, um die " +"Modifikatoreinstellungen zu bearbeiten." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "Das Löschen des letzten festen Teils ist nicht erlaubt." @@ -1095,6 +1130,9 @@ msgstr "Mehr" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1107,6 +1145,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1128,7 +1175,7 @@ msgstr "" msgid "No printer" msgstr "Kein Drucker" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1342,12 +1389,34 @@ msgid "Sending print configuration" msgstr "Druckkonfiguration senden" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "" @@ -1357,7 +1426,7 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" +msgid "Install successfully." msgstr "" msgid "Installing" @@ -1448,6 +1517,9 @@ msgstr "Der Eingabewert sollte größer als %1% und kleiner als %2% sein" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Bestätigen" @@ -1473,6 +1545,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "AMS Einstellungen" @@ -1523,6 +1608,23 @@ msgstr "" "Filament und verwendet weiterhin die vor dem letzten Herunterfahren " "aufgezeichneten Informationen." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Datei" @@ -1735,6 +1837,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1812,6 +1919,17 @@ msgstr "" "Ja - Diese Einstellungen ändern und den Spiralmodus automatisch aktivieren\n" "Nein - Verzichten Sie dieses Mal auf den Spiralmodus" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1963,6 +2081,9 @@ msgstr "Update fehlgeschlagen." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "Standard" + msgid "parameter name" msgstr "" @@ -2030,6 +2151,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "Laden von G-Codes" @@ -2039,6 +2166,9 @@ msgstr "Erzeugen von Geometrie-Eckpunktdaten" msgid "Generating geometry index data" msgstr "Erzeugung von Geometrie-Indexdaten" +msgid "Display" +msgstr "Anzeigen" + msgid "up to" msgstr "bis zu" @@ -2054,14 +2184,11 @@ msgstr "bis" msgid "Color Scheme" msgstr "Farbschema" -msgid "Percent" -msgstr "Prozent" - msgid "Time" msgstr "Zeit" -msgid "Display" -msgstr "Anzeigen" +msgid "Percent" +msgstr "Prozent" msgid "Layer Height (mm)" msgstr "Schichthöhe (mm)" @@ -2084,14 +2211,11 @@ msgstr "Volumetrische Flussrate (mm³/s)" msgid "Used filament" msgstr "Genutztes Filament" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Farbdruck" - -msgid "Comsumption" -msgstr "Verbrauch" +msgid "Total" +msgstr "Gesamt" msgid "Travel" msgstr "Eilgang" @@ -2120,18 +2244,12 @@ msgstr "bewegung" msgid "Extruder" msgstr "Extruder" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "gereinigtes Filament" - -msgid "Total" -msgstr "Gesamt" - msgid "Filament change times" msgstr "Filamentwechselzeiten" +msgid "Cost" +msgstr "Kosten" + msgid "Color change" msgstr "Farbwechsel" @@ -2150,24 +2268,75 @@ msgstr "Druckeinstellungen" msgid "Total Estimation" msgstr "Gesamtvorhersage" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Normaler Modus" -msgid "Cost" -msgstr "Kosten" - msgid "Prepare time" msgstr "Vorbereitungszeit" msgid "Model printing time" msgstr "Druckzeit des Modell" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Zum Leisemodus wechseln" msgid "Switch to normal mode" msgstr "Zum Normalen Modus wechseln" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Radius" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Reihenfolge" @@ -2279,6 +2448,18 @@ msgstr "" msgid "Calibration" msgstr "Kalibration" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Kalibrationsprogramm" @@ -2302,11 +2483,23 @@ msgstr "" msgid "Calibrating" msgstr "Kalibrieren" -msgid "Timelapse" -msgstr "Zeitraffer" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Überwachung der Aufzeichnung" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Auflösung" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Drucker anschließen (LAN)" @@ -2352,6 +2545,15 @@ msgstr "Gerät" msgid "Project" msgstr "Projekt" +msgid "Yes" +msgstr "Ja" + +msgid "No" +msgstr "Nein" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Slice" @@ -2361,17 +2563,26 @@ msgstr "Alle Slicen" msgid "Slice plate" msgstr "Druckplatte slicen" -msgid "Print all" -msgstr "Alle drucken" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Geslicete Datei exportieren" +msgid "Send" +msgstr "Senden" -msgid "Export Sliced File" -msgstr "Geslicete Datei exportieren" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Alle drucken" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Tastaturkürzel" @@ -2385,17 +2596,23 @@ msgstr "Einrichtungsassistent" msgid "Show Configuration Folder" msgstr "Konfigurationsordner anzeigen" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Prüfen auf Update" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&Über %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2466,32 +2683,35 @@ msgstr "Projekt speichern als" msgid "Save current project as" msgstr "Aktuelles Projekt speichern als" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Importiere 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Lade ein Modell" msgid "Import Configs" -msgstr "Import Configs" +msgstr "Konfigurationen importieren" msgid "Load configs" -msgstr "Load configs" +msgstr "Konfigurationen laden" msgid "Import" -msgstr "Import" +msgstr "Importieren" msgid "Export all objects as STL" msgstr "Alle Objekte als STL exportieren" msgid "Export Generic 3MF" -msgstr "Export Generic 3MF" +msgstr "Generisches 3MF exportieren" msgid "Export 3mf file without using some 3mf-extensions" -msgstr "Export 3mf file without using some 3mf-extensions" +msgstr "Exportieren einer 3mf-Datei ohne Verwendung von 3mf-Erweiterungen" -msgid "Export current Sliced file" -msgstr "Aktuelle geslicete Datei exportieren" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Exportiere G-Code" @@ -2500,7 +2720,7 @@ msgid "Export current plate as G-code" msgstr "" msgid "Export &Configs" -msgstr "Export &Configs" +msgstr "Exportieren &Konfigurieren" msgid "Export current configuration to files" msgstr "" @@ -2583,6 +2803,9 @@ msgstr "Ansicht" msgid "Help" msgstr "Hilfe" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "Öffne G-C&ode" @@ -2601,11 +2824,11 @@ msgstr "Werkzeugwege als OBJ expor&tieren" msgid "Export toolpaths as OBJ" msgstr "Werkzeugweg als OBJ exportieren" -msgid "Open &PrusaSlicer" -msgstr "Öffne &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "PrusaSlicer öffnen" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Beenden" @@ -2624,13 +2847,13 @@ msgid "&Help" msgstr "&Hilfe" msgid "Overwrite file" -msgstr "Overwrite file" +msgstr "Datei überschreiben" msgid "Yes to All" -msgstr "Yes to All" +msgstr "Ja zu allem" msgid "No to All" -msgstr "No to All" +msgstr "Nein zu allem" msgid "Choose a directory" msgstr "" @@ -2642,7 +2865,7 @@ msgstr[0] "" msgstr[1] "" msgid "Export result" -msgstr "Export Result" +msgstr "Ergebnis exportieren" msgid "Select profile to load:" msgstr "" @@ -2655,7 +2878,7 @@ msgstr[0] "" msgstr[1] "" msgid "Import result" -msgstr "Import result" +msgstr "Ergebnis importieren" msgid "File is missing" msgstr "Datei fehlt" @@ -2695,7 +2918,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2712,6 +2938,27 @@ msgstr "" msgid "Stopped." msgstr "Gestoppt." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Laufend..." @@ -2720,10 +2967,10 @@ msgid "Load failed [%d]!" msgstr "Laden fehlgeschlagen [%d]!" msgid "Year" -msgstr "Year" +msgstr "Jahr" msgid "Month" -msgstr "Month" +msgstr "Monat" msgid "All Files" msgstr "" @@ -2737,6 +2984,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Zeitraffer" + msgid "Switch to timelapse files." msgstr "" @@ -2762,23 +3012,29 @@ msgid "Batch manage files." msgstr "" msgid "No printers." -msgstr "No printers." +msgstr "Keine Drucker" -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." -msgstr "Connecting..." +msgstr "Verbinden..." #, c-format, boost-format msgid "Connect failed [%d]!" -msgstr "Connection failed [%d]!" +msgstr "Verbindung fehlgeschlagen [%d]!" msgid "Loading file list..." -msgstr "Loading file list..." +msgstr "Dateiliste laden..." msgid "No files" -msgstr "No files" +msgstr "Keine Dateien." + +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" #, c-format, boost-format msgid "File '%s' was lost! Please download it again." @@ -2824,6 +3080,12 @@ msgstr "Y/Z-Achsen vertauschen" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Druckprozess" @@ -2851,11 +3113,11 @@ msgstr "100%" msgid "Lamp" msgstr "Lampe" -msgid "Part Cooling" -msgstr "BAuteilkühlung" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Hilfskühlung" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Druckbett" @@ -2866,6 +3128,12 @@ msgstr "Entladen" msgid "Debug Info" msgstr "Debug-Informationen" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Druckliste" @@ -2875,8 +3143,37 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." -msgstr "Downloading..." +msgstr "Herunterladen..." + +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" msgid "This only takes effect during printing" msgstr "" @@ -2893,6 +3190,9 @@ msgstr "Sport" msgid "Ludicrous" msgstr "Verrückt" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Verbindung zum Server fehlgeschlagen" @@ -2911,11 +3211,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Verbindung zum Drucker fehlgeschlagen" -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nein" +msgid "Don't show again" +msgstr "Nicht mehr anzeigen" #, c-format, boost-format msgid "%s error" @@ -3019,8 +3316,8 @@ msgstr "Fehler:" msgid "Warning:" msgstr "Warnung:" -msgid "Export ok." -msgstr "Exportieren ok." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Reparatur)" @@ -3049,9 +3346,6 @@ msgstr "Schichten" msgid "Range" msgstr "Reichweite" -msgid "default" -msgstr "Standard" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3084,22 +3378,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Untere" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." +msgid "Auto-recovery from step loss" msgstr "" -"Wechseln Sie in den objektbezogenen Einstellungsmodus, um die " -"Modifikatoreinstellungen zu bearbeiten." - -msgid "Don't show again" -msgstr "Nicht mehr anzeigen" msgid "Global" msgstr "Allgemein" @@ -3168,7 +3465,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3189,6 +3486,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Unbenannt" @@ -3219,6 +3522,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Datei wird geladen: %s" @@ -3332,9 +3641,6 @@ msgstr "Das ausgewählte Objekt konnte nicht geteilt werden." msgid "Another export job is running." msgstr "Ein weiterer Exportauftrag läuft gerade." -msgid "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3359,6 +3665,9 @@ msgstr "Warnungen" msgid "Invalid data" msgstr "Ungültige Daten" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Slicen der Druckplatte %d" @@ -3386,6 +3695,28 @@ msgstr "Neues Projekt erstellen" msgid "Load project" msgstr "Projekt laden" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "Die gewählte Datei" @@ -3445,6 +3776,12 @@ msgstr "Speichere G-Code Datei als:" msgid "Save Sliced file as:" msgstr "Geslicte Datei speichern unter:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3467,6 +3804,9 @@ msgstr "" msgid "Invalid number" msgstr "Ungültige Nummer" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Name des Teils: %1%\n" @@ -3495,6 +3835,18 @@ msgstr "Volumen: %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Dreiecke: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "Der Wechsel der Sprache erfordert einen Neustart der Anwendung.\n" @@ -3613,6 +3965,12 @@ msgstr "Sicherungsintervall" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Startseite und tägliche Tipps" @@ -3724,6 +4082,15 @@ msgstr "Voreinstellung bearbeiten" msgid "Project-inside presets" msgstr "Projektinterne Voreinstellungen" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "" "Slicen Sie alle Druckplatten, um Zeit- und Filamentschätzungen zu erhalten" @@ -3883,9 +4250,6 @@ msgstr "Druckbettnivellierung" msgid "Flow Calibration" msgstr "Durchfluss-Kalibrierung" -msgid "Send" -msgstr "Senden" - msgid "send completed" msgstr "senden abgeschlossen" @@ -3901,10 +4265,8 @@ msgstr "Geräteinformationen synchronisieren" msgid "Synchronizing device information time out" msgstr "Zeitüberschreitung bei der Synchronisierung von Geräteinformationen" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "" -"Die Druckaufgabe kann nicht gesendet werden, während das Upgrade ausgeführt " -"wird" msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3959,10 +4321,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3971,18 +4346,51 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Druckauftrag vorbereiten" msgid "Modifying the device name" msgstr "Den Gerätenamen ändern" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "" +"Die Druckaufgabe kann nicht gesendet werden, während das Upgrade ausgeführt " +"wird" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "kalte Druckplatte" + +msgid "Engineering Plate" +msgstr "technische Druckplatte" + +msgid "High Temp Plate" +msgstr "Hochtemperaturdruckplatte" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Drucker anmelden" @@ -4025,13 +4433,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -4050,6 +4458,9 @@ msgstr "Nahtstelle" msgid "Precision" msgstr "Präzision" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Wände" @@ -4081,15 +4492,15 @@ msgstr "Fahrgeschwindigkeit" msgid "Acceleration" msgstr "Beschleunigung" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Supportfilament" msgid "Prime tower" msgstr "Prime-Turm" -msgid "Flush options" -msgstr "Optionen für die Druckdüsensäuberung" - msgid "Special mode" msgstr "Spezialmodus" @@ -4171,9 +4582,6 @@ msgstr "" "wird. Ein Wert von 0 bedeutet, dass das Filament das Drucken auf der " "technischen Druckplatte nicht unterstützt." -msgid "High Temp Plate" -msgstr "Hochtemperaturdruckplatte" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4182,9 +4590,6 @@ msgstr "" "ist. Ein Wert von 0 bedeutet, dass das Filament das Drucken auf der " "Hochtemperaturdruckplatte nicht unterstützt." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4409,13 +4814,18 @@ msgstr "" "Die Voreinstellung \"%1%\" ist nicht mit dem neuen Prozessprofil kompatibel " "und enthält die folgenden nicht gespeicherten Änderungen:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"Sie haben einige voreingestellte Einstellungen geändert. \n" -"Möchten Sie diese geänderten Einstellungen nach dem Wechsel der " -"Voreinstellung beibehalten?" msgid "Extruders count" msgstr "Anzahl der Extruder" @@ -4426,6 +4836,11 @@ msgstr "Allgemein" msgid "Capabilities" msgstr "Fähigkeiten" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4512,17 +4927,28 @@ msgstr "Keine Updates verfügbar." msgid "The configuration is up to date." msgstr "Die Konfiguration ist auf dem neuesten Stand." -msgid "Auto-Calc" -msgstr "Automatisch berechnen" - msgid "Flushing volumes for filament change" msgstr "Säuberungsvolumen für Filamentwechsel" +msgid "Auto-Calc" +msgstr "Automatisch berechnen" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Säuberungvolumen (mm³) für jedes Filamentpaar." -msgid "Flush multiplier" -msgstr "Multiplikator der Druckdüsensäuberung" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "entladen wird" @@ -4802,7 +5228,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4814,13 +5240,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4840,6 +5266,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "Das Speichern von Objekten in der 3mf ist fehlgeschlagen." @@ -5091,12 +5520,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "" @@ -5186,6 +5609,11 @@ msgstr "" "Der Prime Turm setzt voraus, dass alle Objekte mit den gleichen Schichthöhen " "gesliced werden." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "Zu geringe Linienbreite" @@ -5208,8 +5636,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "Schichthöhe kann Druckdüsendurchmesser nicht überschreiten" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "Druckplatte %d: %s unterstützt kein Filament %s.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Erzeugen von Schürze und Rand (skirt & brim)" @@ -5235,6 +5663,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Elefantenfußkompensation" @@ -5417,12 +5851,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Vom Drucker unterstützte Druckbettypen" -msgid "Cool Plate" -msgstr "kalte Druckplatte" - -msgid "Engineering Plate" -msgstr "technische Druckplatte" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "" "Dieser G-Code wird bei jedem Schichtwechsel vor dem Heben von Z eingefügt" @@ -5483,15 +5911,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Schwellenwert für die Kühlung des Überhangs" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"Erzwingt eine bestimmte Lüftergeschwindigkeit, wenn der Grad des Überhangs " -"des gedruckten Teils diesen Wert überschreitet. Ausgedrückt als Prozentsatz, " -"der angibt, wie groß die Breite der Linie ohne Unterstützung durch die " -"untere Schicht ist" msgid "Bridge flow" msgstr "Fluss der Brücke" @@ -5559,6 +5994,9 @@ msgstr "" msgid "Compatible machine" msgstr "Kompatible Maschine" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Kompatibler Maschinenzustand" @@ -5648,9 +6086,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5679,6 +6114,25 @@ msgid "End G-code when finish the printing of this filament" msgstr "" "Fügen Sie den End-G-Code hinzu, wenn Sie den Druck dieses Filaments beenden." +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Muster der oberen Oberfläche" @@ -5703,6 +6157,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Muster der unteren Oberfläche" @@ -5754,9 +6214,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Radius" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5826,21 +6283,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Farbe" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Maximale Volumengeschwindigkeit" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Diese Einstellung gibt an, wie viel Volumen an Material pro Sekunde " -"geschmolzen und extrudiert werden kann. Die Druckgeschwindigkeit wird durch " -"die maximale volumetrische Geschwindigkeit begrenzt, falls die Einstellung " -"zu hoch und unangemessen ist. Null bedeutet keine Begrenzung." msgid "mm³/s" msgstr "mm³/s" @@ -5973,6 +6440,12 @@ msgstr "Bienenwabe" msgid "Adaptive Cubic" msgstr "Adaptiv kubisch" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5984,6 +6457,9 @@ msgstr "" "Verwendung eines niedrigeren Werts kann die Qualität der oberen Oberfläche " "verbessern." +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -6004,22 +6480,6 @@ msgstr "" "Höhe der ersten Schicht. Eine etwas dickere erste Schicht kann die Haftung " "der Druckplatte verbessern" -msgid "Adaptive layer height" -msgstr "Adaptive Schichthöhe" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Die Aktivierung dieser Option bedeutet, dass die Höhe jeder Schicht außer " -"der ersten während des Slicing automatisch entsprechend der Neigung der " -"Oberfläche des Modells berechnet wird.\n" -"Beachten Sie, dass diese Option nur wirksam wird, wenn in der aktuellen " -"Druckplatte kein Prime Turm erzeugt wird." - msgid "Speed of initial layer except the solid infill part" msgstr "Geschwindigkeit der ersten Schicht mit Ausnahme des festen Füllteils" @@ -6130,6 +6590,17 @@ msgstr "Rostfreier Edelstahl" msgid "Brass" msgstr "Messing" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" "Aktivieren Sie diese Option, wenn die Maschine über ein zusätzliches " @@ -6492,9 +6963,6 @@ msgstr "" "Das Objekt wird um diese Anzahl von Supportschichten erhöht. Verwenden Sie " "diese Funktion, um ein abheben beim Drucken von ABS zu vermeiden" -msgid "Resolution" -msgstr "Auflösung" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6652,9 +7120,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6679,6 +7144,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Support aktivieren" @@ -6702,11 +7184,11 @@ msgstr "Baum(automatisch)" msgid "hybrid(auto)" msgstr "Hybrid(automatisch)" -msgid "normal" -msgstr "Normal" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "Baum" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "XY-Abstand der Supports zum Objekt" @@ -6744,12 +7226,16 @@ msgstr "Oberer Z-Abstand" msgid "The z gap between the top support interface and object" msgstr "Die Z-Lücke zwischen der oberen Supportschnittstelle und dem Objekt" -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filament für den Druck der Supports und der Umrandung. 0 bedeutet, dass kein " -"spezielles Filament für den Support und das aktuelle Filament wird verwendet" msgid "Line width of support" msgstr "Linienbreite des Support" @@ -6764,12 +7250,9 @@ msgstr "" "deaktiviert." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Filament zum Drucken der Support-Schnittstelle. 0 bedeutet, dass kein " -"spezielles Filament für die Support-Schnittstelle vorhanden ist und das " -"aktuelle Filament verwendet wird" msgid "Top interface layers" msgstr "Obere Schnittstellenschichten" @@ -6823,6 +7306,12 @@ msgstr "Abstand des Grundmusters" msgid "Spacing between support lines" msgstr "Abstände zwischen den Supportlinien" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Druckgeschwindigkeit für Supports" @@ -6883,16 +7372,6 @@ msgstr "Wandschlaufen für Baumsupport" msgid "This setting specify the count of walls around tree support" msgstr "Diese Einstellung gibt die Anzahl der Wände um den Baumsupport an" -msgid "Tree support with infill" -msgstr "Baumsupport mit Füllung" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"Diese Einstellung legt fest, ob in großen Hohlräumen von Baumsupports " -"Füllmaterial hinzugefügt werden soll" - msgid "Nozzle temperature for layers after the initial one" msgstr "Druckdüsentemperatur für Schichten nach der ersten Schicht" @@ -7001,6 +7480,14 @@ msgstr "" msgid "Purging volumes" msgstr "Reinigungsvolumen" +msgid "Flush multiplier" +msgstr "Multiplikator der Druckdüsensäuberung" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Volumen an neuem Material" @@ -7013,42 +7500,24 @@ msgstr "Breite" msgid "Width of prime tower" msgstr "Breite des Prime-Turms" -msgid "Flush into objects' infill" -msgstr "Druckdüse in der Füllung der Objekte säubern" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"Die Spülung der Druckdüse nach dem Filamentwechsel erfolgt innerhalb der " -"Füllungen der Objekte. Dies kann die Abfallmenge verringern und die " -"Druckzeit verkürzen. Wenn die Wände mit transparentem Filament gedruckt " -"werden, ist die gemischte Farbe der Füllung sichtbar." - -msgid "Flush into objects' support" -msgstr "Druckdüse in der Supportstruktur des Objekts säubern" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"Die Reinigung der Druckdüse nach dem Filamentwechsel erfolgt innerhalb des " -"Objektsupport. Dies kann die Abfallmenge verringern und die Druckzeit " -"verkürzen." - -msgid "Flush into this object" -msgstr "Druckdüse in diesem Objekt säubern" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"Dieses Objekt wird verwendet, um die Düse nach einem Filamentwechsel zu " -"säubern, um Filament zu sparen und die Druckzeit zu verkürzen. Die Farben " -"der Objekte werden als Ergebnis gemischt" msgid "X-Y hole compensation" msgstr "X-Y-Loch-Kompensation" @@ -7079,6 +7548,79 @@ msgstr "" "die Größe geringfügig anzupassen, wenn das Objekt ein Problem beim " "Zusammensetzen hat" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Erkennen einer schmalen internen festen Füllung" @@ -7098,6 +7640,18 @@ msgstr "Exportiere 3MF" msgid "Export project as 3MF." msgstr "Projekt als 3MF exportieren." +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 the plates: 0-all plates, i-plate i, others-invalid" msgstr "" "Slicen sie die Druckplatten: 0-alle Druckplatten; i-Druckplatte i; andere-" @@ -7106,6 +7660,12 @@ msgstr "" msgid "Show command help." msgstr "Befehlshilfe anzeigen." +msgid "UpToDate" +msgstr "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Ausgabe Modellinformationen" @@ -7118,6 +7678,12 @@ msgstr "Einstellungen exportieren" msgid "Export settings to a file." msgstr "Einstellungen in eine Datei exportieren." +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Anordnungsoptionen" @@ -7133,14 +7699,6 @@ msgstr "Einheiten des Modells umrechnen" msgid "Orient the model" msgstr "Das Modell ausrichten" -msgid "Repair" -msgstr "Reparieren" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "" -"Reparieren Sie die Maschen des Modells, wenn es sich um nicht-verzweigte " -"Maschen handelt" - msgid "Scale the model by a float factor" msgstr "Skalierung des Modells um einen Faktor" @@ -7215,9 +7773,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Slicen des Netzes" -msgid " Object:" -msgstr " Objekt:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Support: Werkzeugpfad auf Ebene %d erzeugen" @@ -7413,33 +7968,74 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Gemaltes löschen" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Pinselgröße festlegen" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Drehung:" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Höhe:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Wählen sie eine oder mer Dateien (3mf/step/stl/obj/amf):" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "Initialisierung fehlgeschlagen [%d]!" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Importiere 3MF/STL/STEP/OBJ/AMF" -#~ msgid "Management" -#~ msgstr "Management" +#~ msgid "Part Cooling" +#~ msgstr "BAuteilkühlung" -#~ msgid "Open" -#~ msgstr "Open" +#~ msgid "Aux Cooling" +#~ msgstr "Hilfskühlung" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" #~ msgstr "" -#~ "%1% liegt zu nahe am Ausschlussbereich, beim Drucken kommt es zu " -#~ "Kollisionen." +#~ "Filament für den Druck der Supports und der Umrandung. 0 bedeutet, dass " +#~ "kein spezielles Filament für den Support und das aktuelle Filament wird " +#~ "verwendet" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Filament zum Drucken der Support-Schnittstelle. 0 bedeutet, dass kein " +#~ "spezielles Filament für die Support-Schnittstelle vorhanden ist und das " +#~ "aktuelle Filament verwendet wird" + +#~ msgid "Repair" +#~ msgstr "Reparieren" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "" +#~ "Reparieren Sie die Maschen des Modells, wenn es sich um nicht-verzweigte " +#~ "Maschen handelt" + +#~ msgid "Monitoring Recording" +#~ msgstr "Überwachung der Aufzeichnung" + +#~ msgid "Tree support with infill" +#~ msgstr "Baumsupport mit Füllung" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Diese Einstellung legt fest, ob in großen Hohlräumen von Baumsupports " +#~ "Füllmaterial hinzugefügt werden soll" #~ msgid "" #~ "\n" @@ -7450,77 +8046,19 @@ msgstr "" #~ "%1% liegt zu nahe am Ausschlussbereich, beim Drucken kommt es zu " #~ "Kollisionen." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr " zu nahe an anderen, es kommt beim Drucken zu Kollisionen.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." #~ msgstr "" -#~ " ist zu nahe am Sperrbereich, es kommt beim Drucken zu Kollisionen.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Vermeiden Sie das Überqueren von Mauern während der Fahrt" - -#~ msgid "Max travel detour distance" -#~ msgstr "Maximale Umwegentfernung" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Maximale Umleitungsstrecke zur Vermeidung einer querenden Wand. Keine " -#~ "Umleitung, wenn die Umleitungsstrecke größer als dieser Wert ist" - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Höhe des Abstandszylinders um den Extruder. Wird als Eingabe für die " -#~ "automatische Anordnung verwendet, um Kollisionen zu vermeiden, wenn " -#~ "Objekt für Objekt gedruckt wird" - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Abstandsradius um den Extruder. Wird als Eingabe für die automatische " -#~ "Anordnung verwendet, um Kollisionen zu vermeiden, wenn Objekt für Objekt " -#~ "gedruckt wird" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Fehler auf Zeile %1%:\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Dreiecke reduzieren" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "Umschalten auf Zick-Zack-Muster?\n" -#~ "Ja - automatisch zum Zick-Zack-Muster wechseln\n" -#~ "Nein - setzt die Dichte automatisch auf den Standardwert von nicht 100% " -#~ "zurück\n" - -#~ msgid "Extruder position" -#~ msgstr "Extruderposition" - -#~ msgid "Zig zag" -#~ msgstr "Zick-Zack" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "Die Temperatur des Druckbett ist höher als die Verglasungstemperatur " -#~ "dieses Filaments.\n" -#~ "Dies kann zu einer Verstopfung der Düse und zu Druckfehlern führen" +#~ "%1% liegt zu nahe am Ausschlussbereich, beim Drucken kommt es zu " +#~ "Kollisionen." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Adaptive Schichthöhe" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." @@ -7540,9 +8078,35 @@ msgstr "" #~ "Wenn es ausgewählte Objekte gibt, werden nur die ausgewählten Objekte " #~ "ausgerichtet, ansonsten werden alle Objekte im Projekt ausgerichtet." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Vermeiden Sie das Überqueren von Mauern während der Fahrt" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "Die Temperatur des Druckbett ist höher als die Verglasungstemperatur " +#~ "dieses Filaments.\n" +#~ "Dies kann zu einer Verstopfung der Düse und zu Druckfehlern führen" + #~ msgid "Clear all" #~ msgstr "Alles löschen" +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Abstandsradius um den Extruder. Wird als Eingabe für die automatische " +#~ "Anordnung verwendet, um Kollisionen zu vermeiden, wenn Objekt für Objekt " +#~ "gedruckt wird" + +#~ msgid "Color Print" +#~ msgstr "Farbdruck" + +#~ msgid "Comsumption" +#~ msgstr "Verbrauch" + #~ msgid "Creating" #~ msgstr "Wird erstellt..." @@ -7591,11 +8155,51 @@ msgstr "" #~ "Ziehen Sie nicht zurück, wenn sich der Weg im Füllbereich befindet. Das " #~ "bedeutet, dass man die Quellung nicht sehen kann" +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Die Aktivierung dieser Option bedeutet, dass die Höhe jeder Schicht außer " +#~ "der ersten während des Slicing automatisch entsprechend der Neigung der " +#~ "Oberfläche des Modells berechnet wird.\n" +#~ "Beachten Sie, dass diese Option nur wirksam wird, wenn in der aktuellen " +#~ "Druckplatte kein Prime Turm erzeugt wird." + #~ msgid "Enter a search term" #~ msgstr "Suchbegriff eingeben" +#~ msgid "Erase painting" +#~ msgstr "Gemaltes löschen" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Fehler auf Zeile %1%:\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Geslicete Datei exportieren" + +#~ msgid "Export current Sliced file" +#~ msgstr "Aktuelle geslicete Datei exportieren" + +#~ msgid "Export ok." +#~ msgstr "Exportieren ok." + +#~ msgid "Export sliced file" +#~ msgstr "Geslicete Datei exportieren" + +#~ msgid "Extruder position" +#~ msgstr "Extruderposition" + #~ msgid "Failed" -#~ msgstr "Failed" +#~ msgstr "Fehlgeschlagen" + +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" #~ msgid "Filaments Selection" #~ msgstr "Auswahl der Filamente" @@ -7609,6 +8213,19 @@ msgstr "" #~ msgid "Fix model through cloud" #~ msgstr "Modell durch die Cloud reparieren" +#~ msgid "Flushed filament" +#~ msgstr "gereinigtes Filament" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Erzwingt eine bestimmte Lüftergeschwindigkeit, wenn der Grad des " +#~ "Überhangs des gedruckten Teils diesen Wert überschreitet. Ausgedrückt als " +#~ "Prozentsatz, der angibt, wie groß die Breite der Linie ohne Unterstützung " +#~ "durch die untere Schicht ist" + #~ msgid "Fragment Filter" #~ msgstr "Fragment-Filter" @@ -7623,12 +8240,26 @@ msgstr "" #~ "temperature" #~ msgstr "Die Druckdüse auf die Zieltemperatur heitzen" +#~ msgid "Height:" +#~ msgstr "Höhe:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Höhe des Abstandszylinders um den Extruder. Wird als Eingabe für die " +#~ "automatische Anordnung verwendet, um Kollisionen zu vermeiden, wenn " +#~ "Objekt für Objekt gedruckt wird" + #~ msgid "In the calibration of extrusion flow" #~ msgstr "Kalibrierung des Materialflusses" #~ msgid "In the calibration of laser scanner" #~ msgstr "Kalibrierung des Laser-Scanner" +#~ msgid "Initialize failed [%d]!" +#~ msgstr "Initialisierung fehlgeschlagen [%d]!" + #~ msgid "Inner wall speed" #~ msgstr "Geschwindigkeit der inneren Wände" @@ -7642,12 +8273,34 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Linientyp" +#~ msgid "Management" +#~ msgstr "Verwaltung" + +#~ msgid "Max travel detour distance" +#~ msgstr "Maximale Umwegentfernung" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Maximale Umleitungsstrecke zur Vermeidung einer querenden Wand. Keine " +#~ "Umleitung, wenn die Umleitungsstrecke größer als dieser Wert ist" + #~ msgid "Module" #~ msgstr "Modul" #~ msgid "Monitoring" #~ msgstr "Überwachung" +#~ msgid "Open" +#~ msgstr "Öffnen" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "Öffne &PrusaSlicer" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "PrusaSlicer öffnen" + #~ msgid "Output file" #~ msgstr "Ausgabedatei" @@ -7663,6 +8316,9 @@ msgstr "" #~ msgid "Per object edit" #~ msgstr "Je Objekt bearbeiten" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "Druckplatte %d: %s unterstützt kein Filament %s.\n" + #~ msgid "Please fill report first." #~ msgstr "Bitte füllen Sie zuerst den Bericht aus." @@ -7685,6 +8341,25 @@ msgstr "" #~ msgid "Printer Selection" #~ msgstr "Auswahl der Drucker" +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "Die Spülung der Druckdüse nach dem Filamentwechsel erfolgt innerhalb der " +#~ "Füllungen der Objekte. Dies kann die Abfallmenge verringern und die " +#~ "Druckzeit verkürzen. Wenn die Wände mit transparentem Filament gedruckt " +#~ "werden, ist die gemischte Farbe der Füllung sichtbar." + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "Die Reinigung der Druckdüse nach dem Filamentwechsel erfolgt innerhalb " +#~ "des Objektsupport. Dies kann die Abfallmenge verringern und die Druckzeit " +#~ "verkürzen." + #~ msgid "" #~ "Push new filament \n" #~ "into extruder" @@ -7701,15 +8376,30 @@ msgstr "" #~ "then a snapshot is taken with the chamber camera. When printing finishes, " #~ "a timelapse video is created from all the snapshots." +#~ msgid "Reduce Triangles" +#~ msgstr "Dreiecke reduzieren" + +#~ msgid "Reload item" +#~ msgstr "Element neu laden" + +#~ msgid "Reload items" +#~ msgstr "Elemente neu laden" + #~ msgid "Report" #~ msgstr "Bericht" +#~ msgid "Rotation:" +#~ msgstr "Drehung:" + #~ msgid "Save configuration as:" #~ msgstr "Konfiguration speichern unter:" #~ msgid "Sending" #~ msgstr "Senden" +#~ msgid "Set pen size" +#~ msgstr "Pinselgröße festlegen" + #~ msgid "Shift + Any arrow" #~ msgstr "Umschalttaste + beliebiger Pfeil" @@ -7741,6 +8431,16 @@ msgstr "" #~ "Supportlücken, kann aber zusätzliche Filamentwechsel verursachen, wenn " #~ "die Supportschicht von einem anderen Filament gedruckt wird" +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "Umschalten auf Zick-Zack-Muster?\n" +#~ "Ja - automatisch zum Zick-Zack-Muster wechseln\n" +#~ "Nein - setzt die Dichte automatisch auf den Standardwert von nicht 100% " +#~ "zurück\n" + #~ msgid "Swith cloud environment, Please login again!" #~ msgstr "Cloud-Umgebung wechseln, bitte erneut anmelden!" @@ -7766,6 +8466,25 @@ msgstr "" #~ "Ergebnisse überprüfen oder die Eingabedatei reparieren und es erneut " #~ "versuchen." +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Dieses Objekt wird verwendet, um die Düse nach einem Filamentwechsel zu " +#~ "säubern, um Filament zu sparen und die Druckzeit zu verkürzen. Die Farben " +#~ "der Objekte werden als Ergebnis gemischt" + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Diese Einstellung gibt an, wie viel Volumen an Material pro Sekunde " +#~ "geschmolzen und extrudiert werden kann. Die Druckgeschwindigkeit wird " +#~ "durch die maximale volumetrische Geschwindigkeit begrenzt, falls die " +#~ "Einstellung zu hoch und unangemessen ist. Null bedeutet keine Begrenzung." + #~ msgid "Timelapse Wipe Tower" #~ msgstr "Zeitraffer-Wischturm" @@ -7784,5 +8503,33 @@ msgstr "" #~ msgid "Waiting" #~ msgstr "Warten" +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "Sie haben einige voreingestellte Einstellungen geändert. \n" +#~ "Möchten Sie diese geänderten Einstellungen nach dem Wechsel der " +#~ "Voreinstellung beibehalten?" + +#~ msgid "Zig zag" +#~ msgstr "Zick-Zack" + +#~ msgid " Object:" +#~ msgstr " Objekt:" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr "" +#~ " ist zu nahe am Sperrbereich, es kommt beim Drucken zu Kollisionen.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr " zu nahe an anderen, es kommt beim Drucken zu Kollisionen.\n" + +#~ msgid "normal" +#~ msgstr "Normal" + #~ msgid "the 3mf is not compatible, load geometry data only!" #~ msgstr "die 3mf ist nicht kompatibel, laden Sie nur Geometriedaten!" + +#~ msgid "tree" +#~ msgstr "Baum" diff --git a/bbl/i18n/en/BambuStudio_en.po b/bbl/i18n/en/BambuStudio_en.po index 92851f2ea0..9ea01cb7c1 100644 --- a/bbl/i18n/en/BambuStudio_en.po +++ b/bbl/i18n/en/BambuStudio_en.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -19,6 +19,9 @@ msgstr "Alt + Mouse wheel" msgid "Section view" msgstr "Section view" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + Mouse wheel" @@ -64,6 +67,9 @@ msgstr "Tool type" msgid "Smart fill angle" msgstr "Smart fill angle" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Auto support threshold angle: " @@ -79,6 +85,10 @@ msgstr "Fill" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Highlight faces according to overhang angle." @@ -135,6 +145,12 @@ msgstr "Bucket fill" msgid "Height range" msgstr "Height range" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Shortcut Key " @@ -330,9 +346,6 @@ msgstr "Face recognition" msgid "Perform Recognition" msgstr "Perform Recognition" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -351,15 +364,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -504,8 +508,8 @@ msgstr "Loading a mode view" msgid "Choose one file (3mf):" msgstr "Choose one file (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Choose one or more files (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Choose one file (.gcode/.gco/.g/.ngc/ngc):" @@ -588,6 +592,9 @@ msgstr "Infill" msgid "Support" msgstr "Support" +msgid "Flush options" +msgstr "Flush options" + msgid "Speed" msgstr "Speed" @@ -721,6 +728,18 @@ msgstr "Scale to build volume" msgid "Scale an object to fit the build volume" msgstr "Scale an object to fit the build volume" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Flush into objects' infill" + +msgid "Flush into this object" +msgstr "Flush into this object" + +msgid "Flush into objects' support" +msgstr "Flush into objects' support" + msgid "Convert from inch" msgstr "Convert from Inch" @@ -772,6 +791,9 @@ msgstr "Mirror object" msgid "Add Primitive" msgstr "Add Primitive" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "To Objects" @@ -838,6 +860,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -925,6 +950,14 @@ msgstr "Generic" msgid "Add Modifier" msgstr "Add Modifier" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "Switch to per-object setting mode to edit modifier settings." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "Deleting the last solid part is not allowed." @@ -1069,6 +1102,9 @@ msgstr "More" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1081,6 +1117,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1102,7 +1147,7 @@ msgstr "" msgid "No printer" msgstr "No printer" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1310,12 +1355,34 @@ msgid "Sending print configuration" msgstr "Sending print configuration" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "" @@ -1325,7 +1392,7 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" +msgid "Install successfully." msgstr "" msgid "Installing" @@ -1418,6 +1485,9 @@ msgstr "The input value should be greater than %1% and less than %2%" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Confirm" @@ -1443,6 +1513,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "AMS Settings" @@ -1491,6 +1574,23 @@ msgstr "" "during startup and will continue to use the information recorded before the " "last shutdown." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "File" @@ -1696,6 +1796,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1769,6 +1874,17 @@ msgstr "" "Yes - Change these settings and enable spiral mode automatically\n" "No - Cancel enabling spiral mode" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1919,6 +2035,9 @@ msgstr "Update failed." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "default" + msgid "parameter name" msgstr "" @@ -1986,6 +2105,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "Loading G-codes" @@ -1995,6 +2120,9 @@ msgstr "Generating geometry vertex data" msgid "Generating geometry index data" msgstr "Generating geometry index data" +msgid "Display" +msgstr "Display" + msgid "up to" msgstr "up to" @@ -2010,14 +2138,11 @@ msgstr "to" msgid "Color Scheme" msgstr "Color scheme" -msgid "Percent" -msgstr "Percent" - msgid "Time" msgstr "Time" -msgid "Display" -msgstr "Display" +msgid "Percent" +msgstr "Percent" msgid "Layer Height (mm)" msgstr "Layer height (mm)" @@ -2040,14 +2165,11 @@ msgstr "Volumetric flow rate (mm³/s)" msgid "Used filament" msgstr "Used filament" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Color print" - -msgid "Comsumption" -msgstr "Consumption" +msgid "Total" +msgstr "Total" msgid "Travel" msgstr "Travel" @@ -2076,18 +2198,12 @@ msgstr "Travel" msgid "Extruder" msgstr "Extruder" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "Flushed filament" - -msgid "Total" -msgstr "Total" - msgid "Filament change times" msgstr "Filament change times" +msgid "Cost" +msgstr "Cost" + msgid "Color change" msgstr "Color change" @@ -2106,24 +2222,75 @@ msgstr "Print settings" msgid "Total Estimation" msgstr "Total estimation" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Normal mode" -msgid "Cost" -msgstr "Cost" - msgid "Prepare time" msgstr "Prepare time" msgid "Model printing time" msgstr "Model printing time" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Switch to silent mode" msgid "Switch to normal mode" msgstr "Switch to normal mode" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Radius" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Sequence" @@ -2235,6 +2402,18 @@ msgstr "" msgid "Calibration" msgstr "Calibration" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Calibration program" @@ -2259,11 +2438,23 @@ msgstr "" msgid "Calibrating" msgstr "Calibrating" -msgid "Timelapse" -msgstr "Timelapse" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Monitoring Recording" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Resolution" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Connect Printer (LAN)" @@ -2308,6 +2499,15 @@ msgstr "Device" msgid "Project" msgstr "Project" +msgid "Yes" +msgstr "Yes" + +msgid "No" +msgstr "No" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Slice" @@ -2317,17 +2517,26 @@ msgstr "Slice all" msgid "Slice plate" msgstr "Slice plate" -msgid "Print all" -msgstr "Print all" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Export Sliced File" +msgid "Send" +msgstr "Send" -msgid "Export Sliced File" -msgstr "Export Sliced File" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Print all" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Keyboard Shortcuts" @@ -2341,17 +2550,23 @@ msgstr "Setup Wizard" msgid "Show Configuration Folder" msgstr "Show Configuration Folder" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Check for Updates" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&About %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2422,8 +2637,8 @@ msgstr "Save Project as" msgid "Save current project as" msgstr "Save current project as" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Import 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Load a model" @@ -2446,8 +2661,11 @@ msgstr "" msgid "Export 3mf file without using some 3mf-extensions" msgstr "" -msgid "Export current Sliced file" -msgstr "Export Sliced File" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Export G-code" @@ -2539,6 +2757,9 @@ msgstr "View" msgid "Help" msgstr "Help" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "&Open G-code" @@ -2557,11 +2778,11 @@ msgstr "Export &Toolpaths as OBJ" msgid "Export toolpaths as OBJ" msgstr "Export toolpaths as OBJ" -msgid "Open &PrusaSlicer" -msgstr "Open &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Open PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Quit" @@ -2655,7 +2876,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2672,6 +2896,27 @@ msgstr "" msgid "Stopped." msgstr "Stopped." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Playing..." @@ -2697,6 +2942,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Timelapse" + msgid "Switch to timelapse files." msgstr "" @@ -2724,7 +2972,7 @@ msgstr "" msgid "No printers." msgstr "" -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2740,6 +2988,12 @@ msgstr "" msgid "No files" msgstr "" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2784,6 +3038,12 @@ msgstr "Swap Y/Z axes" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Printing progress" @@ -2811,11 +3071,11 @@ msgstr "100%" msgid "Lamp" msgstr "Lamp" -msgid "Part Cooling" -msgstr "Part Cooling" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Aux Cooling" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Bed" @@ -2826,6 +3086,12 @@ msgstr "Unload" msgid "Debug Info" msgstr "Debug Info" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Printing list" @@ -2835,9 +3101,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "" +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2853,6 +3148,9 @@ msgstr "Sport" msgid "Ludicrous" msgstr "Ludicrous" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Failed to connect to the server" @@ -2871,11 +3169,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Failed to connect to the printer" -msgid "Yes" -msgstr "Yes" - -msgid "No" -msgstr "No" +msgid "Don't show again" +msgstr "Don't show again" #, c-format, boost-format msgid "%s error" @@ -2979,8 +3274,8 @@ msgstr "Error:" msgid "Warning:" msgstr "Warning:" -msgid "Export ok." -msgstr "Export ok." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Repair)" @@ -3009,9 +3304,6 @@ msgstr "Layers" msgid "Range" msgstr "Range" -msgid "default" -msgstr "default" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3044,20 +3336,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Bottom" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." -msgstr "Switch to per-object setting mode to edit modifier settings." - -msgid "Don't show again" -msgstr "Don't show again" +msgid "Auto-recovery from step loss" +msgstr "" msgid "Global" msgstr "Global" @@ -3126,7 +3423,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3147,6 +3444,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Untitled" @@ -3176,6 +3479,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Loading file: %s" @@ -3286,9 +3595,6 @@ msgstr "The selected object couldn't be split." msgid "Another export job is running." msgstr "Another export job is running." -msgid "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3313,6 +3619,9 @@ msgstr "warnings" msgid "Invalid data" msgstr "Invalid data" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Slicing Plate %d" @@ -3338,6 +3647,28 @@ msgstr "Creating a new project" msgid "Load project" msgstr "Load project" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "The selected file" @@ -3397,6 +3728,12 @@ msgstr "Save G-code file as:" msgid "Save Sliced file as:" msgstr "Save Sliced file as:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3416,6 +3753,9 @@ msgstr "Custom supports and color painting were removed before repairing." msgid "Invalid number" msgstr "Invalid number" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Part name: %1%\n" @@ -3444,6 +3784,18 @@ msgstr "Volume: %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Triangles: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "Switching languages requires the application to restart.\n" @@ -3558,6 +3910,12 @@ msgstr "Backup interval" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Home page and daily tips" @@ -3669,6 +4027,15 @@ msgstr "Edit preset" msgid "Project-inside presets" msgstr "Project-inside presets" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "Slice all plate to obtain time and filament estimation" @@ -3820,9 +4187,6 @@ msgstr "Bed leveling" msgid "Flow Calibration" msgstr "Flow calibration" -msgid "Send" -msgstr "Send" - msgid "send completed" msgstr "Send complete" @@ -3838,8 +4202,8 @@ msgstr "Synchronizing device information" msgid "Synchronizing device information time out" msgstr "Synchronizing device information time out" -msgid "Cannot send the print task when the upgrade is in progress" -msgstr "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" +msgstr "" msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3893,10 +4257,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3905,18 +4282,49 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Preparing print job" msgid "Modifying the device name" msgstr "Modifying the device name" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "Cannot send the print task when the upgrade is in progress" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Cool Plate" + +msgid "Engineering Plate" +msgstr "Engineering Plate" + +msgid "High Temp Plate" +msgstr "High Temp Plate" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Log in printer" @@ -3956,13 +4364,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -3981,6 +4389,9 @@ msgstr "Seam" msgid "Precision" msgstr "Precision" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Walls" @@ -4011,15 +4422,15 @@ msgstr "Travel speed" msgid "Acceleration" msgstr "Acceleration" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Support filament" msgid "Prime tower" msgstr "Prime tower" -msgid "Flush options" -msgstr "Flush options" - msgid "Special mode" msgstr "Special mode" @@ -4097,9 +4508,6 @@ msgstr "" "This is the bed temperature when the engineering plate is installed. A value " "of 0 means the filament does not support printing on the Engineering Plate." -msgid "High Temp Plate" -msgstr "High Temp Plate" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4108,9 +4516,6 @@ msgstr "" "value of 0 means the filament does not support printing on the High Temp " "Plate." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4325,12 +4730,18 @@ msgstr "" "Preset \"%1%\" is not compatible with the new process profile and it " "contains the following unsaved changes:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching presets?" msgid "Extruders count" msgstr "Extruder count" @@ -4341,6 +4752,11 @@ msgstr "General" msgid "Capabilities" msgstr "Capabilities" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4427,17 +4843,28 @@ msgstr "No updates available." msgid "The configuration is up to date." msgstr "The configuration is up to date." -msgid "Auto-Calc" -msgstr "Auto-Calc" - msgid "Flushing volumes for filament change" msgstr "Flushing volumes for filament change" +msgid "Auto-Calc" +msgstr "Auto-Calc" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Flushing volume (mm³) for each filament pair." -msgid "Flush multiplier" -msgstr "Flush multiplier" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "unloaded" @@ -4713,7 +5140,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4725,13 +5152,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4751,6 +5178,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "Saving objects into the 3mf failed." @@ -4993,12 +5423,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "%1% is too close to others, and collisions may be caused." @@ -5085,6 +5509,11 @@ msgstr "" "A prime tower requires that all objects are sliced with the same layer " "height." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "Line width too small" @@ -5105,8 +5534,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "Layer height cannot exceed nozzle diameter." #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "Plate %d: %s does not support filament %s.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Generating skirt & brim" @@ -5132,6 +5561,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Elephant foot compensation" @@ -5309,12 +5744,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Bed types supported by the printer" -msgid "Cool Plate" -msgstr "Cool Plate" - -msgid "Engineering Plate" -msgstr "Engineering Plate" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "This G-code is inserted at every layer change before lifting z." @@ -5371,14 +5800,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Cooling overhang threshold" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"This forces the cooling fan to use a specific speed when overhang degrees of " -"parts exceed the set value. It is expressed as percentage which indicates " -"how much line is acceptable without support from lower layers." msgid "Bridge flow" msgstr "Bridge flow" @@ -5445,6 +5882,9 @@ msgstr "" msgid "Compatible machine" msgstr "Compatible machine" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Compatible machine condition" @@ -5534,9 +5974,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5564,6 +6001,25 @@ msgstr "Add end G-Code when finishing the entire print." msgid "End G-code when finish the printing of this filament" msgstr "Add end G-code when finishing the printing of this filament." +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Top surface pattern" @@ -5588,6 +6044,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Bottom surface pattern" @@ -5640,9 +6102,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Radius" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5710,20 +6169,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Color" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Max volumetric speed" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Use this to set the maximum volume of filament that can be melted and " -"extruded per second. Printing speed is limited by maximum volumetric speed " -"if settings are unreasonably high. 0 means there is no limit." msgid "mm³/s" msgstr "mm³/s" @@ -5856,6 +6326,12 @@ msgstr "Honeycomb" msgid "Adaptive Cubic" msgstr "Adaptive Cubic" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5866,6 +6342,9 @@ msgstr "" "Acceleration of top surface infill. Using a lower value may improve top " "surface quality" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5886,22 +6365,6 @@ msgstr "" "This is the height of the first layer. Making the first layer height thicker " "can improve build plate adhesion." -msgid "Adaptive layer height" -msgstr "Adaptive layer height" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Enabling this option means that the height of each layer after the first " -"will be automatically calculated according to the slope of the model’s " -"surface.\n" -"Please note that this option only takes effect if there is no prime tower " -"generated on the current plate." - msgid "Speed of initial layer except the solid infill part" msgstr "" "This is the speed for the first layer except for solid infill sections." @@ -6011,6 +6474,17 @@ msgstr "Stainless steel" msgid "Brass" msgstr "Brass" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "Enable this option if the machine has an auxiliary part cooling fan" @@ -6363,9 +6837,6 @@ msgstr "" "Object will be raised by this number of support layers. Use this function to " "avoid warping when printing ABS." -msgid "Resolution" -msgstr "Resolution" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6525,9 +6996,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6552,6 +7020,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Enable support" @@ -6575,11 +7060,11 @@ msgstr "tree(auto)" msgid "hybrid(auto)" msgstr "hybrid(auto)" -msgid "normal" -msgstr "normal" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "tree" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Support/object xy distance" @@ -6614,12 +7099,16 @@ msgstr "Top Z distance" msgid "The z gap between the top support interface and object" msgstr "This determines the Z gap between top support interfaces and objects." -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"This is the filament used to print supports and skirts. 0 means no specific " -"filament for support and the current filament is used." msgid "Line width of support" msgstr "Line width of support" @@ -6634,11 +7123,9 @@ msgstr "" "by default." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"This is the filament to print support interfaces. 0 means no specific " -"filament for support interfaces and the current filament is used" msgid "Top interface layers" msgstr "Top interface layers" @@ -6692,6 +7179,12 @@ msgstr "Base pattern spacing" msgid "Spacing between support lines" msgstr "This determines the spacing between support lines." +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "This is the speed for support." @@ -6751,16 +7244,6 @@ msgstr "Tree support wall loops" msgid "This setting specify the count of walls around tree support" msgstr "This setting specifies the wall count around tree support." -msgid "Tree support with infill" -msgstr "Tree support with infill" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"This setting specifies whether to add infill inside large hollows of tree " -"support." - msgid "Nozzle temperature for layers after the initial one" msgstr "Nozzle temperature after the first layer" @@ -6865,6 +7348,14 @@ msgstr "" msgid "Purging volumes" msgstr "Purging volumes" +msgid "Flush multiplier" +msgstr "Flush multiplier" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Prime volume" @@ -6878,40 +7369,24 @@ msgstr "Width" msgid "Width of prime tower" msgstr "This is the width of prime towers." -msgid "Flush into objects' infill" -msgstr "Flush into objects' infill" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"Purging after filament change will be done inside objects' infills. This may " -"lower the amount of waste and decrease the print time. If the walls are " -"printed with transparent filament, the mixed color infill will be visible." - -msgid "Flush into objects' support" -msgstr "Flush into objects' support" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time." - -msgid "Flush into this object" -msgstr "Flush into this object" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"This object will be used to purge the nozzle after a filament change to save " -"filament and decrease the print time. Colors of the objects will be mixed as " -"a result." msgid "X-Y hole compensation" msgstr "X-Y hole compensation" @@ -6940,6 +7415,79 @@ msgstr "" "contours smaller. This function is used to adjust sizes slightly when " "objects have assembly issues." +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Detect narrow internal solid infill" @@ -6958,12 +7506,30 @@ msgstr "Export 3mf" msgid "Export project as 3MF." msgstr "This exports the project as a 3mf file." +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 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 "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Output Model Info" @@ -6976,6 +7542,12 @@ msgstr "Export Settings" msgid "Export settings to a file." msgstr "This exports settings to a file." +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Arrange Options" @@ -6991,12 +7563,6 @@ msgstr "Convert the units of model" msgid "Orient the model" msgstr "Orient the model" -msgid "Repair" -msgstr "Repair" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Repair the model’s meshes if they are non-manifold." - msgid "Scale the model by a float factor" msgstr "Scale the model by a float factor" @@ -7069,9 +7635,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Slicing mesh" -msgid " Object:" -msgstr " Object:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Support: generate toolpath at layer %d" @@ -7267,6 +7830,142 @@ msgid "" "one time?" msgstr "" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" + +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" + +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" + +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Choose one or more files (3mf/step/stl/obj/amf):" + +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Import 3MF/STL/STEP/OBJ/AMF" + +#~ msgid "Part Cooling" +#~ msgstr "Part Cooling" + +#~ msgid "Aux Cooling" +#~ msgstr "Aux Cooling" + +#~ msgid "" +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" +#~ msgstr "" +#~ "This is the filament used to print supports and skirts. 0 means no " +#~ "specific filament for support and the current filament is used." + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "This is the filament to print support interfaces. 0 means no specific " +#~ "filament for support interfaces and the current filament is used" + +#~ msgid "Repair" +#~ msgstr "Repair" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "Repair the model’s meshes if they are non-manifold." + +#~ msgid "Monitoring Recording" +#~ msgstr "Monitoring Recording" + +#~ msgid "Tree support with infill" +#~ msgstr "Tree support with infill" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support." + +#~ msgid "Export ok." +#~ msgstr "Export ok." + +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "Plate %d: %s does not support filament %s.\n" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" + +#~ msgid "Color Print" +#~ msgstr "Color print" + +#~ msgid "Comsumption" +#~ msgstr "Consumption" + +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Flushed filament" +#~ msgstr "Flushed filament" + +#~ msgid "Adaptive layer height" +#~ msgstr "Adaptive layer height" + +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Enabling this option means that the height of each layer after the first " +#~ "will be automatically calculated according to the slope of the model’s " +#~ "surface.\n" +#~ "Please note that this option only takes effect if there is no prime tower " +#~ "generated on the current plate." + +#~ msgid "normal" +#~ msgstr "normal" + +#~ msgid "tree" +#~ msgstr "tree" + +#~ msgid " Object:" +#~ msgstr " Object:" + +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching presets?" + +#~ msgid "Export sliced file" +#~ msgstr "Export Sliced File" + +#~ msgid "Export Sliced File" +#~ msgstr "Export Sliced File" + +#~ msgid "Export current Sliced file" +#~ msgstr "Export Sliced File" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "This forces the cooling fan to use a specific speed when overhang degrees " +#~ "of parts exceed the set value. It is expressed as percentage which " +#~ "indicates how much line is acceptable without support from lower layers." + #~ msgid "Erase painting" #~ msgstr "Erase painting" diff --git a/bbl/i18n/es/BambuStudio_es.po b/bbl/i18n/es/BambuStudio_es.po index 4c3c66ca0f..4d6b5a1252 100644 --- a/bbl/i18n/es/BambuStudio_es.po +++ b/bbl/i18n/es/BambuStudio_es.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -22,6 +22,9 @@ msgstr "Alt + Rueda del ratón" msgid "Section view" msgstr "Vista de la sección" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + Rueda del ratón" @@ -67,6 +70,9 @@ msgstr "Tipo de herramienta" msgid "Smart fill angle" msgstr "Ángulo de relleno inteligente" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Ángulo del umbral de soporte automático: " @@ -82,6 +88,10 @@ msgstr "Llenar" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Resalte las caras según el ángulo del voladizo." @@ -139,6 +149,12 @@ msgstr "Relleno de cubos" msgid "Height range" msgstr "Rango de altura" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Tecla de acceso directo " @@ -336,9 +352,6 @@ msgstr "Reconocimiento facial" msgid "Perform Recognition" msgstr "Realizar el reconocimiento" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -357,15 +370,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -517,8 +521,8 @@ msgstr "Cargar un modo de vista" msgid "Choose one file (3mf):" msgstr "Elija un archivo (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Elija uno o varios archivos (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Elija un archivo (gcode/.gco/.g/.ngc/ngc):" @@ -601,6 +605,9 @@ msgstr "Relleno" msgid "Support" msgstr "Soporte" +msgid "Flush options" +msgstr "Opciones de purga" + msgid "Speed" msgstr "Velocidad" @@ -734,6 +741,18 @@ msgstr "Escala para la impresión del volumen" msgid "Scale an object to fit the build volume" msgstr "Escalar un objeto para que se ajuste al volumen de impresión" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Purgar en el relleno de los objetos" + +msgid "Flush into this object" +msgstr "Descarga en este objeto" + +msgid "Flush into objects' support" +msgstr "Depositar en el soporte de los objetos" + msgid "Convert from inch" msgstr "Convertir desde pulgadas" @@ -785,6 +804,9 @@ msgstr "Objeto reflejado" msgid "Add Primitive" msgstr "Añadir Primitivo" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "A los objetos" @@ -852,6 +874,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -946,6 +971,16 @@ msgstr "Genérico" msgid "Add Modifier" msgstr "Añadir modificador" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" +"Cambia al modo de ajuste por objeto para editar los ajustes de los " +"modificadores." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "No se permite borrar la última parte sólida." @@ -1090,6 +1125,9 @@ msgstr "Más" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1102,6 +1140,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1123,7 +1170,7 @@ msgstr "" msgid "No printer" msgstr "Sin impresión" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1339,12 +1386,34 @@ msgid "Sending print configuration" msgstr "Enviando la configuración de impresión" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "" @@ -1354,8 +1423,8 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" -msgstr "Finalizar" +msgid "Install successfully." +msgstr "" msgid "Installing" msgstr "" @@ -1447,6 +1516,9 @@ msgstr "El valor de entrada debe ser mayor que %1% y menor que %2%" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Confirmar" @@ -1472,6 +1544,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "Ajustes del AMS" @@ -1520,6 +1605,23 @@ msgstr "" "durante el arranque y seguirá utilizando la información registrada antes del " "último apagado." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Archivo" @@ -1727,6 +1829,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1805,6 +1912,17 @@ msgstr "" "Sí - Cambiar estos ajustes y activar el modo espiral automáticamente\n" "No - Dejar de usar el modo espiral esta vez" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1961,6 +2079,9 @@ msgstr "Actualización fallida." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "por defecto" + msgid "parameter name" msgstr "" @@ -2028,6 +2149,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "Carga de códigos G" @@ -2037,6 +2164,9 @@ msgstr "Generación de datos de vértices de la geometría" msgid "Generating geometry index data" msgstr "Generación de datos de índices geométricos" +msgid "Display" +msgstr "Pantalla" + msgid "up to" msgstr "hasta" @@ -2052,14 +2182,11 @@ msgstr "a" msgid "Color Scheme" msgstr "Esquema de colores" -msgid "Percent" -msgstr "Porcentaje" - msgid "Time" msgstr "Tiempo" -msgid "Display" -msgstr "Pantalla" +msgid "Percent" +msgstr "Porcentaje" msgid "Layer Height (mm)" msgstr "Altura de la capa (mm)" @@ -2082,14 +2209,11 @@ msgstr "Tasa de flujo volumétrico (mm³/seg)" msgid "Used filament" msgstr "Filamento usado" -msgid "Filament N XX" -msgstr "Filamento N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Impresión en color" - -msgid "Comsumption" -msgstr "Consumo" +msgid "Total" +msgstr "Total" msgid "Travel" msgstr "Recorrido" @@ -2118,18 +2242,12 @@ msgstr "Recorrido" msgid "Extruder" msgstr "Extrusor" -msgid "Filament 1" -msgstr "Filamento 1" - -msgid "Flushed filament" -msgstr "Filamento limpiado" - -msgid "Total" -msgstr "Total" - msgid "Filament change times" msgstr "Tiempos de cambio de filamento" +msgid "Cost" +msgstr "Coste" + msgid "Color change" msgstr "Cambio de color" @@ -2148,24 +2266,75 @@ msgstr "Configuración de impresión" msgid "Total Estimation" msgstr "Estimación total" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Modo normal" -msgid "Cost" -msgstr "Coste" - msgid "Prepare time" msgstr "Planificar tiempo" msgid "Model printing time" msgstr "Tiempo de impresión del modelo" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Cambiar al modo silencioso" msgid "Switch to normal mode" msgstr "Cambiar al modo normal" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Radio" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Secuencia" @@ -2277,6 +2446,18 @@ msgstr "" msgid "Calibration" msgstr "Calibración" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Programa de calibración" @@ -2301,11 +2482,23 @@ msgstr "" msgid "Calibrating" msgstr "Calibrando" -msgid "Timelapse" -msgstr "Timelapse" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Monitoreo de grabación" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Resolución" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Conectar Impresora (LAN)" @@ -2350,6 +2543,15 @@ msgstr "Dispositivo" msgid "Project" msgstr "Proyecto" +msgid "Yes" +msgstr "Sí" + +msgid "No" +msgstr "No" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Laminar" @@ -2359,17 +2561,26 @@ msgstr "Laminar todo" msgid "Slice plate" msgstr "Laminar placa" -msgid "Print all" -msgstr "Imprimir todo" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Exportar archivo rebanado" +msgid "Send" +msgstr "Enviar" -msgid "Export Sliced File" -msgstr "Exportar Archivo Rebanado" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Imprimir todo" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Atajos de teclado" @@ -2383,17 +2594,23 @@ msgstr "Asistente de configuración" msgid "Show Configuration Folder" msgstr "Mostrar Carpeta de Configuración" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Comprobar Actualicaciones" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&Acerca de %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2464,32 +2681,35 @@ msgstr "Guardar proyecto como" msgid "Save current project as" msgstr "Guardar el proyecto actual como" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Importar 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Cargar un modelo" msgid "Import Configs" -msgstr "Import Configs" +msgstr "Importar configuraciones" msgid "Load configs" -msgstr "Load configs" +msgstr "Cargar configuraciones" msgid "Import" -msgstr "Import" +msgstr "Importar" msgid "Export all objects as STL" msgstr "Exportar todos los objetos como STL" msgid "Export Generic 3MF" -msgstr "Export Generic 3MF" +msgstr "Exportar 3MF genérico" msgid "Export 3mf file without using some 3mf-extensions" -msgstr "Export 3mf file without using some 3mf-extensions" +msgstr "Exporte el archivo 3mf sin usar algunas de las extensiones" -msgid "Export current Sliced file" -msgstr "Exportar el archivo rebanado actual" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Exportar código G" @@ -2498,7 +2718,7 @@ msgid "Export current plate as G-code" msgstr "" msgid "Export &Configs" -msgstr "Export &Configs" +msgstr "Exportar & Configuración" msgid "Export current configuration to files" msgstr "" @@ -2581,6 +2801,9 @@ msgstr "Vista" msgid "Help" msgstr "Ayuda" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "Abrir código G (&O)" @@ -2599,11 +2822,11 @@ msgstr "Exportar &Movimientos como OBJ" msgid "Export toolpaths as OBJ" msgstr "Exportar trayectorias de herramientas como OBJ" -msgid "Open &PrusaSlicer" -msgstr "Abrir &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Abrir PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "Sa&lir" @@ -2622,13 +2845,13 @@ msgid "&Help" msgstr "Ayu&da" msgid "Overwrite file" -msgstr "Overwrite file" +msgstr "Sobrescribir archivo" msgid "Yes to All" -msgstr "Yes to All" +msgstr "Sí a todo" msgid "No to All" -msgstr "No to All" +msgstr "No a todo" msgid "Choose a directory" msgstr "" @@ -2640,7 +2863,7 @@ msgstr[0] "" msgstr[1] "" msgid "Export result" -msgstr "Export Result" +msgstr "Exportar resultado" msgid "Select profile to load:" msgstr "" @@ -2653,7 +2876,7 @@ msgstr[0] "" msgstr[1] "" msgid "Import result" -msgstr "Import result" +msgstr "Importar resultado" msgid "File is missing" msgstr "Falta el archivo" @@ -2693,7 +2916,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2710,6 +2936,27 @@ msgstr "" msgid "Stopped." msgstr "Detenido." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Reproduciendo..." @@ -2718,10 +2965,10 @@ msgid "Load failed [%d]!" msgstr "¡La carga ha fallado [%d]!" msgid "Year" -msgstr "Year" +msgstr "Año" msgid "Month" -msgstr "Month" +msgstr "Mes" msgid "All Files" msgstr "" @@ -2735,6 +2982,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Timelapse" + msgid "Switch to timelapse files." msgstr "" @@ -2760,23 +3010,29 @@ msgid "Batch manage files." msgstr "" msgid "No printers." -msgstr "No printers." +msgstr "No hay impresoras." -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." -msgstr "Connecting..." +msgstr "Conectando…" #, c-format, boost-format msgid "Connect failed [%d]!" -msgstr "Connection failed [%d]!" +msgstr "Error de conexión [%d]!" msgid "Loading file list..." -msgstr "Loading file list..." +msgstr "Cargando lista de archivos..." msgid "No files" -msgstr "No files" +msgstr "No hay archivos" + +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" #, c-format, boost-format msgid "File '%s' was lost! Please download it again." @@ -2822,6 +3078,12 @@ msgstr "Intercambiar los ejes Y/Z" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Progreso de impresión" @@ -2849,11 +3111,11 @@ msgstr "100%" msgid "Lamp" msgstr "Luz" -msgid "Part Cooling" -msgstr "Refrigeración de Piezas" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Enfriamiento Auxiliar" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Cama" @@ -2864,6 +3126,12 @@ msgstr "Descarga" msgid "Debug Info" msgstr "Información de Depuración" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Imprimiendo Lista" @@ -2873,8 +3141,37 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." -msgstr "Downloading..." +msgstr "Descargando…" + +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" msgid "This only takes effect during printing" msgstr "" @@ -2891,6 +3188,9 @@ msgstr "Deportivo" msgid "Ludicrous" msgstr "Lúdico" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "No se ha podido conectar con el servidor" @@ -2909,11 +3209,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "No se ha podido conectar a la impresora" -msgid "Yes" -msgstr "Sí" - -msgid "No" -msgstr "No" +msgid "Don't show again" +msgstr "No mostrar de nuevo" #, c-format, boost-format msgid "%s error" @@ -3017,8 +3314,8 @@ msgstr "Error:" msgid "Warning:" msgstr "Advertencia:" -msgid "Export ok." -msgstr "Exportación correcta." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Reparación)" @@ -3049,9 +3346,6 @@ msgstr "Capas" msgid "Range" msgstr "Rango" -msgid "default" -msgstr "por defecto" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3084,22 +3378,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Inferior" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." +msgid "Auto-recovery from step loss" msgstr "" -"Cambia al modo de ajuste por objeto para editar los ajustes de los " -"modificadores." - -msgid "Don't show again" -msgstr "No mostrar de nuevo" msgid "Global" msgstr "Global" @@ -3168,7 +3465,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3189,6 +3486,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Sin título" @@ -3218,6 +3521,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Cargando archivo: %s" @@ -3333,9 +3642,6 @@ 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 "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3360,6 +3666,9 @@ msgstr "advertencias" msgid "Invalid data" msgstr "Datos inválidos" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Placa de corte %d" @@ -3387,6 +3696,28 @@ msgstr "Creando un nuevo proyecto" msgid "Load project" msgstr "Carga de Proyecto" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "El archivo seleccionado" @@ -3445,6 +3776,12 @@ msgstr "Guardar archivo Código G como:" msgid "Save Sliced file as:" msgstr "Guardar el archivo rebanado como:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3466,6 +3803,9 @@ msgstr "" msgid "Invalid number" msgstr "Número inválido" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Nombre de la pieza: %1%\n" @@ -3496,6 +3836,18 @@ msgstr "Volumen: %1% mm³\n" msgid "Triangles: %1%\n" msgstr " Triángulos: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "El cambio de idioma requiere el reinicio de la aplicación.\n" @@ -3614,6 +3966,12 @@ msgstr "Intervalo de copia de seguridad" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Página de inicio y consejos diarios" @@ -3725,6 +4083,15 @@ msgstr "Editar ajuste preestablecido" msgid "Project-inside presets" msgstr "Preajustes internos del proyecto" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "" "Rebana todas las piezas para obtener una estimación del tiempo y del " @@ -3880,9 +4247,6 @@ msgstr "Nivelación de la cama" msgid "Flow Calibration" msgstr "Calibración del flujo" -msgid "Send" -msgstr "Enviar" - msgid "send completed" msgstr "envío completo" @@ -3899,10 +4263,8 @@ msgid "Synchronizing device information time out" msgstr "" "Finalización del tiempo de sincronización de la información del dispositivo" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "" -"No se puede enviar la tarea de impresión cuando la actualización está en " -"curso" msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3957,10 +4319,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3969,18 +4344,51 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Preparando el trabajo de impresión" msgid "Modifying the device name" msgstr "Modificar el nombre del dispositivo" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "" +"No se puede enviar la tarea de impresión cuando la actualización está en " +"curso" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Placa fría" + +msgid "Engineering Plate" +msgstr "Placa de ingeniería" + +msgid "High Temp Plate" +msgstr "Placa de alta temperatura" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Iniciar sesión en la impresora" @@ -4022,13 +4430,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -4047,6 +4455,9 @@ msgstr "Costura" msgid "Precision" msgstr "Precisión" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Paredes" @@ -4078,15 +4489,15 @@ msgstr "Velocidad de desplazamiento" msgid "Acceleration" msgstr "Aceleración" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Filamento de soporte" msgid "Prime tower" msgstr "Torre Principal" -msgid "Flush options" -msgstr "Opciones de purga" - msgid "Special mode" msgstr "Modo especial" @@ -4168,9 +4579,6 @@ msgstr "" "instalada. Un valor de 0 significa que el filamento no admite la impresión " "en la placa de ingeniería." -msgid "High Temp Plate" -msgstr "Placa de alta temperatura" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4179,9 +4587,6 @@ msgstr "" "instalada. Un valor de 0 significa que el filamento no admite la impresión " "en la placa de alta temperatura." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4401,12 +4806,18 @@ msgstr "" "El preajuste \"%1%\" no es compatible con el nuevo perfil de proceso y " "contiene los siguientes cambios no guardados:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"Has cambiado algunos ajustes de preajuste. \n" -"¿Desea mantener estos ajustes cambiados después de cambiar de preajuste?" msgid "Extruders count" msgstr "Contador de extrusores" @@ -4417,6 +4828,11 @@ msgstr "General" msgid "Capabilities" msgstr "Capacidades" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4500,17 +4916,28 @@ msgstr "No hay actualizaciones disponibles." msgid "The configuration is up to date." msgstr "La configuración está actualizada." -msgid "Auto-Calc" -msgstr "Auto-Calc" - msgid "Flushing volumes for filament change" msgstr "Volúmenes de limpieza para el cambio de filamentos" +msgid "Auto-Calc" +msgstr "Auto-Calc" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Volumen de limpieza (mm³) para cada par de filamentos." -msgid "Flush multiplier" -msgstr "Multiplicador de flujo" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "descargado" @@ -4792,7 +5219,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4804,13 +5231,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4830,6 +5257,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "El guardado de objetos en el 3mf no ha funcionado." @@ -5079,12 +5509,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "%1% está demasiado cerca de otros, y pueden producirse colisiones." @@ -5175,6 +5599,11 @@ msgstr "" "La torre principal requiere que todos los objetos se corten con las mismas " "alturas de capa." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "Ancho de línea demasiado pequeño" @@ -5197,8 +5626,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "La altura de la capa no puede superar el diámetro de la boquilla" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "La placa %d: %s no admite el filamento %s.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Generando falda y ala" @@ -5224,6 +5653,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Compensación del pie de elefante" @@ -5403,12 +5838,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Tipos de cama que admite la impresora" -msgid "Cool Plate" -msgstr "Placa fría" - -msgid "Engineering Plate" -msgstr "Placa de ingeniería" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "Este código G se inserta en cada cambio de capa antes de levantar z" @@ -5467,14 +5896,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Umbral del voladizo de refrigeración" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"Fuerza al ventilador de refrigeración a una velocidad específica cuando el " -"grado de voladizo de la pieza impresa supera este valor. Expresado en " -"porcentaje, indica la anchura de la línea sin apoyo de la capa inferior." msgid "Bridge flow" msgstr "Flujo del puente" @@ -5541,6 +5978,9 @@ msgstr "" msgid "Compatible machine" msgstr "Máquina compatible" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Condición de máquina compatible" @@ -5632,9 +6072,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5662,6 +6099,25 @@ msgstr "Finalizar el código G cuando termine la impresión completa" msgid "End G-code when finish the printing of this filament" msgstr "Terminar el código G cuando se termine de imprimir este filamento" +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Patrón de la superficie superior" @@ -5686,6 +6142,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Patrón de la superficie inferior" @@ -5740,9 +6202,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Radio" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5811,21 +6270,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Color" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Velocidad volumétrica máxima" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Este ajuste representa la cantidad de volumen de filamento que se puede " -"fundir y extruir por segundo. La velocidad de impresión está limitada por la " -"velocidad volumétrica máxima, en caso de ajustar una velocidad demasiado " -"alta y poco razonable. Cero significa que no hay límite" msgid "mm³/s" msgstr "mm³/s" @@ -5960,6 +6429,12 @@ msgstr "Panal de abeja" msgid "Adaptive Cubic" msgstr "Cúbico Adaptativo" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5970,6 +6445,9 @@ msgstr "" "Aceleración del relleno de la superficie superior. El uso de un valor más " "bajo puede mejorar la calidad de la superficie superior" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5990,22 +6468,6 @@ msgstr "" "Altura de la capa inicial. Hacer que la altura de la capa inicial sea " "ligeramente gruesa puede mejorar la adherencia de la placa de impresión" -msgid "Adaptive layer height" -msgstr "Altura de capa adaptable" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Si se activa esta opción, la altura de cada capa, excepto la primera, se " -"calculará automáticamente durante el corte en función de la pendiente de la " -"superficie del modelo.\n" -"Tenga en cuenta que esta opción sólo surte efecto si no se genera ninguna " -"torre principal en la placa actual." - msgid "Speed of initial layer except the solid infill part" msgstr "Velocidad de la capa inicial excepto la parte sólida de relleno" @@ -6116,6 +6578,17 @@ msgstr "Acero inoxidable" msgid "Brass" msgstr "Latón" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" "Habilite esta opción si la máquina tiene un ventilador auxiliar de " @@ -6479,9 +6952,6 @@ msgstr "" "El objeto será elevado por este número de capas de soporte. Utilice esta " "función para evitar la envoltura al imprimir ABS" -msgid "Resolution" -msgstr "Resolución" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6641,9 +7111,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6668,6 +7135,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Habilitar el soporte" @@ -6690,11 +7174,11 @@ msgstr "árbol(auto)" msgid "hybrid(auto)" msgstr "híbrido(auto)" -msgid "normal" -msgstr "normal" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "árbol" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Distancia soporte/objeto xy" @@ -6730,12 +7214,16 @@ msgstr "Distancia Z superior" msgid "The z gap between the top support interface and object" msgstr "La distancia z entre la interfaz de soporte superior y el objeto" -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filamento para imprimir el soporte y el faldón. 0 significa que no hay " -"filamento específico para el soporte y se utiliza el filamento actual" msgid "Line width of support" msgstr "Ancho de línea del soporte" @@ -6750,12 +7238,9 @@ msgstr "" "por defecto." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Filamento para imprimir la interfaz de soporte. 0 significa que no hay " -"filamento específico para la interfaz de soporte y se utiliza el filamento " -"actual" msgid "Top interface layers" msgstr "Capas de la interfaz superior" @@ -6811,6 +7296,12 @@ msgstr "Espaciamiento del patrón base" msgid "Spacing between support lines" msgstr "Espacio entre las líneas de apoyo" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Velocidad de la asistencia" @@ -6872,16 +7363,6 @@ msgid "This setting specify the count of walls around tree support" msgstr "" "Este ajuste especifica el número de muros alrededor del soporte del árbol" -msgid "Tree support with infill" -msgstr "Soporte para árboles con relleno" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"Este ajuste especifica si se añade relleno dentro de los grandes huecos del " -"soporte del árbol" - msgid "Nozzle temperature for layers after the initial one" msgstr "Temperatura de la boquilla después de la primera capa" @@ -6990,6 +7471,14 @@ msgstr "" msgid "Purging volumes" msgstr "Volúmenes de purga" +msgid "Flush multiplier" +msgstr "Multiplicador de flujo" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Volumen principal" @@ -7002,42 +7491,24 @@ msgstr "Ancho" msgid "Width of prime tower" msgstr "Anchura de la torre principal" -msgid "Flush into objects' infill" -msgstr "Purgar en el relleno de los objetos" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"La purga tras el cambio de filamento se realizará dentro del relleno de los " -"objetos. Esto puede reducir la cantidad de residuos y disminuir el tiempo de " -"impresión. Si las paredes se imprimen con filamento transparente, el " -"mezclado se podrá ver en el exterior." - -msgid "Flush into objects' support" -msgstr "Depositar en el soporte de los objetos" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"La purga después del cambio de filamento se hará dentro del soporte de los " -"objetos. Esto puede reducir la cantidad de residuos y disminuir el tiempo de " -"impresión." - -msgid "Flush into this object" -msgstr "Descarga en este objeto" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"Este objeto se utilizará para purgar la boquilla después de un cambio de " -"filamento para ahorrar filamento y disminuir el tiempo de impresión. Los " -"colores de los objetos se mezclarán como resultado" msgid "X-Y hole compensation" msgstr "Compensación de huecos X-Y" @@ -7067,6 +7538,79 @@ msgstr "" "negativo hace que el contorno sea más pequeño. Esta función se utiliza para " "ajustar el tamaño ligeramente cuando el objeto tiene problemas de ensamblaje" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Detectar el relleno sólido interno estrecho" @@ -7086,12 +7630,30 @@ msgstr "Exportar 3MF" msgid "Export project as 3MF." msgstr "Exportar el proyecto como 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 the plates: 0-all plates, i-plate i, others-invalid" msgstr "Cortar las placas: 0-todas las placas, i-placa i, otras-inválidas" msgid "Show command help." msgstr "Mostrar la ayuda del comando." +msgid "UpToDate" +msgstr "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Información del modelo de salida" @@ -7104,6 +7666,12 @@ msgstr "Ajustes de exportación" msgid "Export settings to a file." msgstr "Exporta los ajustes a un archivo." +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Opciones de posicionamiento" @@ -7119,12 +7687,6 @@ msgstr "Convertir las unidades del modelo" msgid "Orient the model" msgstr "Orientar el modelo" -msgid "Repair" -msgstr "Reparar" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Reparar las mallas del modelo si se trata de una malla no plegable" - msgid "Scale the model by a float factor" msgstr "Escala el modelo por un factor de flotación" @@ -7199,9 +7761,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Malla de corte" -msgid " Object:" -msgstr "Objeto" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Soporte: generar trayectoria en la capa %d" @@ -7397,33 +7956,74 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Borrar lo pintado" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Ajustar el tamaño del lápiz" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Rotación:" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Altura:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Elija uno o varios archivos (3mf/step/stl/obj/amf):" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "¡Ha fallado la inicialización [%d]!" +#~ msgid "Finish" +#~ msgstr "Finalizar" -#~ msgid "Management" -#~ msgstr "Management" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Importar 3MF/STL/STEP/OBJ/AMF" -#~ msgid "Open" -#~ msgstr "Open" +#~ msgid "Part Cooling" +#~ msgstr "Refrigeración de Piezas" + +#~ msgid "Aux Cooling" +#~ msgstr "Enfriamiento Auxiliar" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" #~ msgstr "" -#~ "%1% está demasiado cerca del área de exclusión, habrá colisiones al " -#~ "imprimir." +#~ "Filamento para imprimir el soporte y el faldón. 0 significa que no hay " +#~ "filamento específico para el soporte y se utiliza el filamento actual" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Filamento para imprimir la interfaz de soporte. 0 significa que no hay " +#~ "filamento específico para la interfaz de soporte y se utiliza el " +#~ "filamento actual" + +#~ msgid "Repair" +#~ msgstr "Reparar" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "Reparar las mallas del modelo si se trata de una malla no plegable" + +#~ msgid "Monitoring Recording" +#~ msgstr "Monitoreo de grabación" + +#~ msgid "Tree support with infill" +#~ msgstr "Soporte para árboles con relleno" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Este ajuste especifica si se añade relleno dentro de los grandes huecos " +#~ "del soporte del árbol" #~ msgid "" #~ "\n" @@ -7434,78 +8034,19 @@ msgstr "" #~ "%1% está demasiado cerca del área de exclusión, habrá colisiones al " #~ "imprimir." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr " está demasiado cerca de otros, habrá colisiones al imprimir.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." #~ msgstr "" -#~ " está demasiado cerca del área de exclusión, habrá colisiones al " -#~ "imprimir.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Evitar cruzar el muro en los desplazamientos" - -#~ msgid "Max travel detour distance" -#~ msgstr "Distancia máxima de desvío de viaje" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Distancia máxima de desvío para evitar cruzar el muro. No se desvía si la " -#~ "distancia de desvío es mayor que este valor" - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Altura del cilindro de separación alrededor del extrusor. Se utiliza como " -#~ "entrada de auto-organización para evitar la colisión cuando se imprime " -#~ "objeto por objeto." - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Radio de separación alrededor del extrusor. Se utiliza como entrada de " -#~ "auto-organización para evitar la colisión cuando se imprime objeto por " -#~ "objeto" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Error en la línea %1%:\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Reducir los triángulos" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "¿Cambiar al patrón en zig-zag?\n" -#~ "Sí - cambia automáticamente al patrón en zig-zag\n" -#~ "No - restablecer automáticamente la densidad al valor por defecto que no " -#~ "es del 100%.\n" - -#~ msgid "Extruder position" -#~ msgstr "Posición del extrusor" - -#~ msgid "Zig zag" -#~ msgstr "Zig zag" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "La temperatura del lecho es superior a la temperatura de vitrificación de " -#~ "este filamento.\n" -#~ "Esto puede causar el bloqueo de la boquilla y el fracaso de la impresión" +#~ "%1% está demasiado cerca del área de exclusión, habrá colisiones al " +#~ "imprimir." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Altura de capa adaptable" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." @@ -7526,9 +8067,35 @@ msgstr "" #~ "hay objetos seleccionados, sólo orienta los seleccionados.En caso " #~ "contrario, orienta todos los objetos del proyecto." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Evitar cruzar el muro en los desplazamientos" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "La temperatura del lecho es superior a la temperatura de vitrificación de " +#~ "este filamento.\n" +#~ "Esto puede causar el bloqueo de la boquilla y el fracaso de la impresión" + #~ msgid "Clear all" #~ msgstr "Borrar todo" +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Radio de separación alrededor del extrusor. Se utiliza como entrada de " +#~ "auto-organización para evitar la colisión cuando se imprime objeto por " +#~ "objeto" + +#~ msgid "Color Print" +#~ msgstr "Impresión en color" + +#~ msgid "Comsumption" +#~ msgstr "Consumo" + #~ msgid "Creating" #~ msgstr "Creando" @@ -7576,11 +8143,51 @@ msgstr "" #~ "No se repliegue cuando el recorrido esté en zona de relleno " #~ "absolutamente. Eso significa que el rezago no puede ser visto" +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Si se activa esta opción, la altura de cada capa, excepto la primera, se " +#~ "calculará automáticamente durante el corte en función de la pendiente de " +#~ "la superficie del modelo.\n" +#~ "Tenga en cuenta que esta opción sólo surte efecto si no se genera ninguna " +#~ "torre principal en la placa actual." + #~ msgid "Enter a search term" #~ msgstr "Teclea un término de búsqueda" +#~ msgid "Erase painting" +#~ msgstr "Borrar lo pintado" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Error en la línea %1%:\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Exportar Archivo Rebanado" + +#~ msgid "Export current Sliced file" +#~ msgstr "Exportar el archivo rebanado actual" + +#~ msgid "Export ok." +#~ msgstr "Exportación correcta." + +#~ msgid "Export sliced file" +#~ msgstr "Exportar archivo rebanado" + +#~ msgid "Extruder position" +#~ msgstr "Posición del extrusor" + #~ msgid "Failed" -#~ msgstr "Failed" +#~ msgstr "Error" + +#~ msgid "Filament 1" +#~ msgstr "Filamento 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filamento N XX" #~ msgid "Filaments Selection" #~ msgstr "Selección de filamentos" @@ -7594,6 +8201,18 @@ msgstr "" #~ msgid "Fix model through cloud" #~ msgstr "Fijar el modelo a través de la nube" +#~ msgid "Flushed filament" +#~ msgstr "Filamento limpiado" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Fuerza al ventilador de refrigeración a una velocidad específica cuando " +#~ "el grado de voladizo de la pieza impresa supera este valor. Expresado en " +#~ "porcentaje, indica la anchura de la línea sin apoyo de la capa inferior." + #~ msgid "Fragment Filter" #~ msgstr "Filtro de fragmentos" @@ -7610,12 +8229,26 @@ msgstr "" #~ "Calentar la boquilla a la temperatura deseada \n" #~ "temperatura" +#~ msgid "Height:" +#~ msgstr "Altura:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Altura del cilindro de separación alrededor del extrusor. Se utiliza como " +#~ "entrada de auto-organización para evitar la colisión cuando se imprime " +#~ "objeto por objeto." + #~ msgid "In the calibration of extrusion flow" #~ msgstr "En la calibración del flujo de extrusión" #~ msgid "In the calibration of laser scanner" #~ msgstr "En la calibración del escáner láser" +#~ msgid "Initialize failed [%d]!" +#~ msgstr "¡Ha fallado la inicialización [%d]!" + #~ msgid "Inner wall speed" #~ msgstr "Velocidad de la pared interior" @@ -7629,12 +8262,34 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Tipo de línea" +#~ msgid "Management" +#~ msgstr "Gestión" + +#~ msgid "Max travel detour distance" +#~ msgstr "Distancia máxima de desvío de viaje" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Distancia máxima de desvío para evitar cruzar el muro. No se desvía si la " +#~ "distancia de desvío es mayor que este valor" + #~ msgid "Module" #~ msgstr "Módulo" #~ msgid "Monitoring" #~ msgstr "Monitorizando" +#~ msgid "Open" +#~ msgstr "Abrir" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "Abrir &PrusaSlicer" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "Abrir PrusaSlicer" + #~ msgid "Output file" #~ msgstr "Archivo de salida" @@ -7650,6 +8305,9 @@ msgstr "" #~ msgid "Per object edit" #~ msgstr "Por objeto editar" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "La placa %d: %s no admite el filamento %s.\n" + #~ msgid "Please fill report first." #~ msgstr "Por favor, rellene primero el informe." @@ -7672,6 +8330,25 @@ msgstr "" #~ msgid "Printer Selection" #~ msgstr "Selección de la impresora" +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "La purga tras el cambio de filamento se realizará dentro del relleno de " +#~ "los objetos. Esto puede reducir la cantidad de residuos y disminuir el " +#~ "tiempo de impresión. Si las paredes se imprimen con filamento " +#~ "transparente, el mezclado se podrá ver en el exterior." + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "La purga después del cambio de filamento se hará dentro del soporte de " +#~ "los objetos. Esto puede reducir la cantidad de residuos y disminuir el " +#~ "tiempo de impresión." + #~ msgid "" #~ "Push new filament \n" #~ "into extruder" @@ -7690,15 +8367,30 @@ msgstr "" #~ "then a snapshot is taken with the chamber camera. When printing finishes, " #~ "a timelapse video is created from all the snapshots." +#~ msgid "Reduce Triangles" +#~ msgstr "Reducir los triángulos" + +#~ msgid "Reload item" +#~ msgstr "Volver a cargar el objeto" + +#~ msgid "Reload items" +#~ msgstr "Recarga de objetos" + #~ msgid "Report" #~ msgstr "Informe" +#~ msgid "Rotation:" +#~ msgstr "Rotación:" + #~ msgid "Save configuration as:" #~ msgstr "Guardar la configuración como:" #~ msgid "Sending" #~ msgstr "Enviando" +#~ msgid "Set pen size" +#~ msgstr "Ajustar el tamaño del lápiz" + #~ msgid "Shift + Any arrow" #~ msgstr "Mayúsculas + Cualquier flecha" @@ -7732,6 +8424,16 @@ msgstr "" #~ "personalizada, pero puede causar cambios de filamento adicionales si el " #~ "soporte se especifica como un extrusor diferente con el objeto" +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "¿Cambiar al patrón en zig-zag?\n" +#~ "Sí - cambia automáticamente al patrón en zig-zag\n" +#~ "No - restablecer automáticamente la densidad al valor por defecto que no " +#~ "es del 100%.\n" + #~ msgid "Swith cloud environment, Please login again!" #~ msgstr "Cambiar el entorno de la nube, ¡Por favor, inicie sesión de nuevo!" @@ -7755,6 +8457,25 @@ msgstr "" #~ "repararlo, sin embargo, es posible que desee comprobar los resultados o " #~ "reparar el archivo de entrada y volver a intentarlo." +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Este objeto se utilizará para purgar la boquilla después de un cambio de " +#~ "filamento para ahorrar filamento y disminuir el tiempo de impresión. Los " +#~ "colores de los objetos se mezclarán como resultado" + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Este ajuste representa la cantidad de volumen de filamento que se puede " +#~ "fundir y extruir por segundo. La velocidad de impresión está limitada por " +#~ "la velocidad volumétrica máxima, en caso de ajustar una velocidad " +#~ "demasiado alta y poco razonable. Cero significa que no hay límite" + #~ msgid "Timelapse Wipe Tower" #~ msgstr "Timelapse Torre de limpieza" @@ -7773,5 +8494,33 @@ msgstr "" #~ msgid "Waiting" #~ msgstr "Esperando" +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "Has cambiado algunos ajustes de preajuste. \n" +#~ "¿Desea mantener estos ajustes cambiados después de cambiar de preajuste?" + +#~ msgid "Zig zag" +#~ msgstr "Zig zag" + +#~ msgid " Object:" +#~ msgstr "Objeto" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr "" +#~ " está demasiado cerca del área de exclusión, habrá colisiones al " +#~ "imprimir.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr " está demasiado cerca de otros, habrá colisiones al imprimir.\n" + +#~ msgid "normal" +#~ msgstr "normal" + #~ msgid "the 3mf is not compatible, load geometry data only!" #~ msgstr "el 3mf no es compatible, ¡cargue sólo los datos geométricos!" + +#~ msgid "tree" +#~ msgstr "árbol" diff --git a/bbl/i18n/fr/BambuStudio_fr.po b/bbl/i18n/fr/BambuStudio_fr.po index 4987c8704c..71240fe325 100644 --- a/bbl/i18n/fr/BambuStudio_fr.po +++ b/bbl/i18n/fr/BambuStudio_fr.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -22,6 +22,9 @@ msgstr "Alt + molette de la souris" msgid "Section view" msgstr "Vue en coupe" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + molette de la souris" @@ -67,6 +70,9 @@ msgstr "Type d'outil" msgid "Smart fill angle" msgstr "Angle de remplissage intelligent" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Angle de seuil de support automatique :" @@ -82,6 +88,10 @@ msgstr "Remplir" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Mettez en surbrillance les faces en fonction de l'angle de surplomb." @@ -139,6 +149,12 @@ msgstr "Remplissage du seau" msgid "Height range" msgstr "Plage de hauteur" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Touche de raccourci" @@ -335,9 +351,6 @@ msgstr "Reconnaissance faciale" msgid "Perform Recognition" msgstr "Effectuer la reconnaissance" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -356,15 +369,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -516,8 +520,8 @@ msgstr "Chargement d'une vue de mode" msgid "Choose one file (3mf):" msgstr "Choisissez un fichier (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Choisissez un ou plusieurs fichiers (3mf/step/stl/obj/amf) :" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Choisissez un fichier (gcode/.gco/.g/.ngc/ngc) :" @@ -600,6 +604,9 @@ msgstr "Remplissage" msgid "Support" msgstr "Supports" +msgid "Flush options" +msgstr "Options de purge" + msgid "Speed" msgstr "La rapidité" @@ -733,6 +740,18 @@ msgstr "Échelle pour créer du volume" msgid "Scale an object to fit the build volume" msgstr "Mettre à l'échelle un objet pour l'adapter au volume de construction" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Purger dans le remplissage d'objet" + +msgid "Flush into this object" +msgstr "Purger dans cet objet" + +msgid "Flush into objects' support" +msgstr "Purger dans les supports de l'objet" + msgid "Convert from inch" msgstr "Convertir en pouce" @@ -784,6 +803,9 @@ msgstr "Symétriser l'Objet" msgid "Add Primitive" msgstr "Ajouter une primitive" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "Aux objets" @@ -851,6 +873,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -942,6 +967,16 @@ msgstr "Générique" msgid "Add Modifier" msgstr "Ajouter un modificateur" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" +"Basculez vers le mode de réglage par objet pour modifier les paramètres du " +"modificateur." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "La suppression de la dernière partie solide n'est pas autorisée." @@ -1011,7 +1046,7 @@ msgstr "Réparer l'objet modèle" msgid "Following model object has been repaired" msgid_plural "Following model objects have been repaired" msgstr[0] "L'objet modèle suivant a été réparé" -msgstr[1] "L'objet modèle suivant a été réparé" +msgstr[1] "" msgid "Failed to repair folowing model object" msgid_plural "Failed to repair folowing model objects" @@ -1089,6 +1124,9 @@ msgstr "Suite" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1101,6 +1139,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1122,7 +1169,7 @@ msgstr "" msgid "No printer" msgstr "Pas d'imprimante" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1333,12 +1380,34 @@ msgid "Sending print configuration" msgstr "Envoi de la configuration d'impression" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "Downloading" @@ -1348,8 +1417,8 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" -msgstr "Finish" +msgid "Install successfully." +msgstr "" msgid "Installing" msgstr "" @@ -1440,6 +1509,9 @@ msgstr "La valeur saisie doit être supérieure à %1% et inférieure à %2%" msgid "SN" msgstr "Numéro de série" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Confirmer" @@ -1465,6 +1537,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "Paramètres AMS" @@ -1515,6 +1600,23 @@ msgstr "" "pendant le démarrage et continuera à utiliser les informations enregistrées " "avant le dernier arrêt." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Dossier" @@ -1720,6 +1822,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1786,6 +1893,17 @@ msgstr "" "support est désactivé, les couches de coque supérieures sont à 0 et la " "densité de remplissage clairsemée est à 0" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1937,6 +2055,9 @@ msgstr "Mise à jour a échoué." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "défaut" + msgid "parameter name" msgstr "" @@ -2001,6 +2122,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "Chargement des codes G" @@ -2010,6 +2137,9 @@ msgstr "Génération de données de sommet de géométrie" msgid "Generating geometry index data" msgstr "Génération de données d'index de géométrie" +msgid "Display" +msgstr "Affichage" + msgid "up to" msgstr "jusqu'à" @@ -2025,14 +2155,11 @@ msgstr "à" msgid "Color Scheme" msgstr "Schéma de couleur" -msgid "Percent" -msgstr "Pour cent" - msgid "Time" msgstr "Temps" -msgid "Display" -msgstr "Affichage" +msgid "Percent" +msgstr "Pour cent" msgid "Layer Height (mm)" msgstr "Hauteur de couche (mm)" @@ -2055,14 +2182,11 @@ msgstr "Débit volumétrique (mm³/s)" msgid "Used filament" msgstr "Filament usagé" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Impression couleur" - -msgid "Comsumption" -msgstr "Consommation" +msgid "Total" +msgstr "Total" msgid "Travel" msgstr "Voyager" @@ -2091,18 +2215,12 @@ msgstr "Déplacement" msgid "Extruder" msgstr "Extrudeuse" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "Filament purgé" - -msgid "Total" -msgstr "Total" - msgid "Filament change times" msgstr "Temps de changement de filament" +msgid "Cost" +msgstr "Coût" + msgid "Color change" msgstr "Changement de couleur" @@ -2121,24 +2239,75 @@ msgstr "Paramètres d'impression" msgid "Total Estimation" msgstr "Estimation totale" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Mode normal" -msgid "Cost" -msgstr "Coût" - msgid "Prepare time" msgstr "Temps de préparation" msgid "Model printing time" msgstr "Temps d'impression du modèle" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Passer en mode silencieux" msgid "Switch to normal mode" msgstr "Passer en mode normal" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Rayon" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Séquence" @@ -2250,6 +2419,18 @@ msgstr "" msgid "Calibration" msgstr "Étalonnage" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Programme d'étalonnage" @@ -2274,11 +2455,23 @@ msgstr "" msgid "Calibrating" msgstr "Étalonnage" -msgid "Timelapse" -msgstr "Laps de temps" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Enregistrement de surveillance" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Résolution" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Connecter l'imprimante (LAN)" @@ -2324,6 +2517,15 @@ msgstr "Appareil" msgid "Project" msgstr "Projet" +msgid "Yes" +msgstr "Oui" + +msgid "No" +msgstr "Non" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Tranche" @@ -2333,17 +2535,26 @@ msgstr "Tout trancher" msgid "Slice plate" msgstr "Assiette à trancher" -msgid "Print all" -msgstr "Tout imprimer" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Exporter le fichier découpé" +msgid "Send" +msgstr "Envoyer" -msgid "Export Sliced File" -msgstr "Exporter le fichier découpé" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Tout imprimer" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Raccourcis clavier" @@ -2357,17 +2568,23 @@ msgstr "Assistant de configuration" msgid "Show Configuration Folder" msgstr "Afficher le dossier de configuration" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Vérifier la mise à jour" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&À propos de %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2438,8 +2655,8 @@ msgstr "Enregistrer le projet sous" msgid "Save current project as" msgstr "Enregistrer le projet actuel sous" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Importer 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Charger un modèle" @@ -2462,8 +2679,11 @@ msgstr "Export Generic 3MF" msgid "Export 3mf file without using some 3mf-extensions" msgstr "Export 3mf file without using some 3mf-extensions" -msgid "Export current Sliced file" -msgstr "Exporter le fichier en tranches actuel" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Exporter le code G" @@ -2555,6 +2775,9 @@ msgstr "Voir" msgid "Help" msgstr "Aider" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "&Ouvrir G-code" @@ -2573,11 +2796,11 @@ msgstr "Exporter &Toolpaths en OBJ" msgid "Export toolpaths as OBJ" msgstr "Exporter les parcours d'outils en OBJ" -msgid "Open &PrusaSlicer" -msgstr "Ouvrir &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Ouvrir PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Quitter" @@ -2667,7 +2890,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2684,6 +2910,27 @@ msgstr "" msgid "Stopped." msgstr "Arrêté." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "En jouant..." @@ -2709,6 +2956,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Laps de temps" + msgid "Switch to timelapse files." msgstr "" @@ -2736,7 +2986,7 @@ msgstr "" msgid "No printers." msgstr "No printers." -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2752,6 +3002,12 @@ msgstr "Loading file list..." msgid "No files" msgstr "No files" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2796,6 +3052,12 @@ msgstr "Permuter les axes Y/Z" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Progression de l'impression" @@ -2823,11 +3085,11 @@ msgstr "100%" msgid "Lamp" msgstr "Lampe" -msgid "Part Cooling" -msgstr "Refroidissement des pièces" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Refroidissement auxiliaire" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Lit" @@ -2838,6 +3100,12 @@ msgstr "retirer" msgid "Debug Info" msgstr "Les informations de débogage" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Liste d'impression" @@ -2847,9 +3115,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "Downloading..." +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2865,6 +3162,9 @@ msgstr "sport" msgid "Ludicrous" msgstr "Ridicule" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Impossible de se connecter au serveur" @@ -2883,11 +3183,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Échec de la connexion à l'imprimante" -msgid "Yes" -msgstr "Oui" - -msgid "No" -msgstr "Non" +msgid "Don't show again" +msgstr "Ne plus afficher" #, c-format, boost-format msgid "%s error" @@ -2953,13 +3250,13 @@ msgstr "Dossier ouvert." msgid "%1$d Object has custom supports." msgid_plural "%1$d Objects have custom supports." msgstr[0] "L'objet %1$d a des supports personnalisés." -msgstr[1] "L'objet %1$d a des supports personnalisés." +msgstr[1] " %1$d objets ont des supports personnalisés." #, c-format, boost-format msgid "%1$d Object has color painting." msgid_plural "%1$d Objects have color painting." msgstr[0] "%1$d L'objet est peint en couleur." -msgstr[1] "%1$d L'objet est peint en couleur." +msgstr[1] "%1$d L'objets sont peints en couleur." msgid "ERROR" msgstr "" @@ -2991,8 +3288,8 @@ msgstr "Erreur:" msgid "Warning:" msgstr "Avertissement:" -msgid "Export ok." -msgstr "Exporter ok." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr "(Réparation)" @@ -3022,9 +3319,6 @@ msgstr "Couches" msgid "Range" msgstr "Intervalle" -msgid "default" -msgstr "défaut" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3055,22 +3349,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Fond" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." +msgid "Auto-recovery from step loss" msgstr "" -"Basculez vers le mode de réglage par objet pour modifier les paramètres du " -"modificateur." - -msgid "Don't show again" -msgstr "Ne plus afficher" msgid "Global" msgstr "Mondial" @@ -3139,7 +3436,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3160,6 +3457,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Sans titre" @@ -3188,6 +3491,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Chargement du fichier : %s" @@ -3303,9 +3612,6 @@ 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 "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3330,6 +3636,9 @@ msgstr "avertissements" msgid "Invalid data" msgstr "Données invalides" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Assiette à découper %d" @@ -3357,6 +3666,28 @@ msgstr "Créer un nouveau projet" msgid "Load project" msgstr "Charger le projet" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "Le fichier sélectionné" @@ -3417,6 +3748,12 @@ msgstr "Enregistrer le fichier G-code sous :" msgid "Save Sliced file as:" msgstr "Enregistrer le fichier découpé sous :" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3438,6 +3775,9 @@ msgstr "" msgid "Invalid number" msgstr "Numéro invalide" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Nom de la pièce : %1%\n" @@ -3456,7 +3796,7 @@ msgstr "Taille : %1% x %2% x %3% mm\n" #, boost-format msgid "Volume: %1% in³\n" -msgstr "Volume : %1% en³\n" +msgstr "Volume : %1% en³\n" #, boost-format msgid "Volume: %1% mm³\n" @@ -3466,6 +3806,18 @@ msgstr "Volume : %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Triangles : %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "Le changement de langue nécessite le redémarrage de l'application.\n" @@ -3584,6 +3936,12 @@ msgstr "Intervalle de sauvegarde" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Page d'accueil et conseils quotidiens" @@ -3695,6 +4053,15 @@ msgstr "Modifier le préréglage" msgid "Project-inside presets" msgstr "Préréglages intégrés au projet" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "" "Tranchez toutes les couches pour obtenir une estimation du temps et du " @@ -3852,9 +4219,6 @@ msgstr "Mise à niveau du lit" msgid "Flow Calibration" msgstr "Étalonnage du débit" -msgid "Send" -msgstr "Envoyer" - msgid "send completed" msgstr "envoi terminé" @@ -3871,10 +4235,8 @@ msgstr "Synchronisation des informations sur l'appareil" msgid "Synchronizing device information time out" msgstr "Expiration du délai de synchronisation des informations sur l'appareil" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "" -"Impossible d'envoyer la tâche d'impression lorsque la mise à niveau est en " -"cours." msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3930,30 +4292,78 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." msgstr "" +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" +msgstr "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" + msgid "" "The printer type used to generate G-code is not the same type as the " "currently selected physical printer. It is recommend to re-slice by " "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Préparation du travail d'impression" msgid "Modifying the device name" msgstr "Modification du nom de l'appareil" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "" +"Impossible d'envoyer la tâche d'impression lorsque la mise à niveau est en " +"cours." + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Assiette froide" + +msgid "Engineering Plate" +msgstr "Plaque d'ingénierie" + +msgid "High Temp Plate" +msgstr "Plaque haute température" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Connectez-vous à l'imprimante" @@ -3996,13 +4406,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -4021,6 +4431,9 @@ msgstr "Couture" msgid "Precision" msgstr "Précision" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Des murs" @@ -4052,15 +4465,15 @@ msgstr "Vitesse de voyage" msgid "Acceleration" msgstr "Accélération" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Filament de support" msgid "Prime tower" msgstr "Tour principale" -msgid "Flush options" -msgstr "Options de purge" - msgid "Special mode" msgstr "Mode spécial" @@ -4142,9 +4555,6 @@ msgstr "" "(\"Engineering plate\") est installé. Une valeur à 0 signifie que ce " "filament ne peut pas être imprimé sur le plateau technique." -msgid "High Temp Plate" -msgstr "Plaque haute température" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4153,9 +4563,6 @@ msgstr "" "(\"Cool plate\") est installé. Une valeur à 0 signifie que ce filament ne " "peut pas être imprimé sur le plateau haute température." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4378,12 +4785,18 @@ msgstr "" "Le préréglage \"%1%\" n'est pas compatible avec le nouveau profil de " "processus et contient les modifications non enregistrées suivantes :" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"Vous avez modifié certains paramètres prédéfinis. Souhaitez-vous conserver " -"ces paramètres modifiés après avoir changé de préréglage ?" msgid "Extruders count" msgstr "Les extrudeuses comptent" @@ -4394,6 +4807,11 @@ msgstr "Général" msgid "Capabilities" msgstr "Capacités" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4480,17 +4898,28 @@ msgstr "Aucune mise à jour disponible." msgid "The configuration is up to date." msgstr "La configuration est à jour." -msgid "Auto-Calc" -msgstr "Auto-Calc" - msgid "Flushing volumes for filament change" msgstr "Volumes de rinçage pour le changement de filament" +msgid "Auto-Calc" +msgstr "Auto-Calc" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Volume de rinçage (mm³) pour chaque paire de filaments." -msgid "Flush multiplier" -msgstr "Multiplicateur de purge" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "déchargé" @@ -4771,7 +5200,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4783,13 +5212,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4809,6 +5238,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "L'enregistrement d'objets dans le 3mf a échoué." @@ -5056,12 +5488,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "" @@ -5072,7 +5498,7 @@ msgid "%1% is too tall, and collisions will be caused." msgstr "%1% est trop grand, cela pourrait provoquer des collisions." msgid " is too close to others, there may be collisions when printing.\n" -msgstr "" +msgstr " is too close to others, there may be collisions when printing.\n" msgid "" " is too close to exclusion area, there may be collisions when printing.\n" @@ -5156,6 +5582,11 @@ msgstr "" "La tour principale nécessite que tous les objets soient découpés avec les " "mêmes hauteurs de couche." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "Largeur de ligne trop petite" @@ -5178,8 +5609,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "La hauteur de la couche ne peut pas dépasser le diamètre de la buse" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "Plaque %d : %s ne prend pas en charge le filament %s.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Génération jupe et bord" @@ -5205,6 +5636,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Compensation de pied d'éléphant" @@ -5386,12 +5823,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Types de lit pris en charge par l'imprimante" -msgid "Cool Plate" -msgstr "Assiette froide" - -msgid "Engineering Plate" -msgstr "Plaque d'ingénierie" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "Ce G-code est inséré à chaque changement de couche avant de soulever z" @@ -5452,15 +5883,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Seuil de dépassement de refroidissement" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"Forcer le ventilateur de refroidissement à une vitesse spécifique lorsque le " -"degré de surplomb de la pièce imprimée dépasse cette valeur. Exprimé en " -"pourcentage qui indique la largeur de la ligne sans support de la couche " -"inférieure" msgid "Bridge flow" msgstr "Débit des ponts" @@ -5527,6 +5965,9 @@ msgstr "" msgid "Compatible machine" msgstr "Appareils compatibles" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "État de la machine compatible" @@ -5616,9 +6057,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5647,6 +6085,25 @@ msgstr "Terminer le code G lorsque vous avez terminé toute l'impression" msgid "End G-code when finish the printing of this filament" msgstr "Fin du code G lorsque l'impression de ce filament est terminée" +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Modèle de surface supérieure" @@ -5671,6 +6128,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Modèle de surface inférieure" @@ -5725,9 +6188,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Rayon" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5798,21 +6258,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Couleur" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Vitesse volumétrique max" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Ce paramètre représente le volume de filament pouvant être fondu et extrudé " -"par seconde. La vitesse d'impression est limitée par la vitesse volumétrique " -"maximale, en cas de réglage de vitesse trop élevé et déraisonnable. Zéro " -"signifie pas de limite" msgid "mm³/s" msgstr "mm³/s" @@ -5946,6 +6416,12 @@ msgstr "Rayon de miel" msgid "Adaptive Cubic" msgstr "Cubique adaptatif" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5957,6 +6433,9 @@ msgstr "" "Utiliser une valeur plus petite pourrait améliorer la qualité de la surface " "supérieure." +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5978,22 +6457,6 @@ msgstr "" "initiale soit légèrement épaisse peut améliorer l'adhérence de la plaque de " "construction" -msgid "Adaptive layer height" -msgstr "Hauteur de couche adaptative" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"En activant cette option, la hauteur de chaque couche, à l'exception de la " -"première, sera automatiquement calculée en fonction de la pente de la " -"surface du modèle.\n" -"Veuillez noter que cette option ne prend effet que si aucune tour primaire " -"n'est générée sur le plateau en cours d'utilisation." - msgid "Speed of initial layer except the solid infill part" msgstr "" "Vitesse de la couche initiale à l'exception de la partie de remplissage " @@ -6106,6 +6569,17 @@ msgstr "Acier inoxydable" msgid "Brass" msgstr "Laiton" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" "Activez cette option si la machine est équipée d'un ventilateur de " @@ -6473,9 +6947,6 @@ msgstr "" "L'objet sera élevé par ce nombre de couches de support. Utilisez cette " "fonction pour éviter l'emballage lors de l'impression ABS" -msgid "Resolution" -msgstr "Résolution" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6636,9 +7107,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6663,6 +7131,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Activer l'assistance" @@ -6686,11 +7171,11 @@ msgstr "arbre (auto)" msgid "hybrid(auto)" msgstr "hybride (auto)" -msgid "normal" -msgstr "Ordinaire" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "arbre" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Distance support/objet xy" @@ -6728,12 +7213,16 @@ msgstr "Distance Z supérieure" msgid "The z gap between the top support interface and object" msgstr "L'écart z entre l'interface de support supérieure et l'objet" -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filament pour imprimer le support et la jupe. 0 signifie qu'aucun filament " -"spécifique pour le support et le filament actuel est utilisé" msgid "Line width of support" msgstr "Largeur de ligne du support" @@ -6748,11 +7237,9 @@ msgstr "" "Désactivé par défaut." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Filament pour imprimer l'interface de support. 0 signifie qu'aucun filament " -"spécifique pour l'interface de support et le filament actuel est utilisé" msgid "Top interface layers" msgstr "Couches d'interface supérieures" @@ -6807,6 +7294,12 @@ msgstr "Espacement du motif de base" msgid "Spacing between support lines" msgstr "Espacement entre les lignes de support" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Vitesse pour les supports" @@ -6868,16 +7361,6 @@ msgstr "Boucles de mur de support d'arbre" msgid "This setting specify the count of walls around tree support" msgstr "Ce paramètre spécifie le nombre de murs autour du support d'arbre" -msgid "Tree support with infill" -msgstr "Support d'arbre avec remplissage" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"Ce paramètre spécifie s'il faut ajouter un remplissage à l'intérieur des " -"grands creux du support d'arbre" - msgid "Nozzle temperature for layers after the initial one" msgstr "Température de la buse pour les couches après la première" @@ -6986,6 +7469,14 @@ msgstr "" msgid "Purging volumes" msgstr "Volumes de purge" +msgid "Flush multiplier" +msgstr "Multiplicateur de purge" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Premier volume" @@ -6998,42 +7489,24 @@ msgstr "Largeur" msgid "Width of prime tower" msgstr "Largeur de la tour principale" -msgid "Flush into objects' infill" -msgstr "Purger dans le remplissage d'objet" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"La purge après le changement de filament se fera dans le remplissage des " -"objets. Cela peut réduire la quantité de déchets et diminuer le temps " -"d'impression. Si les murs sont imprimés avec un filament translucide, le " -"remplissage de couleur mixte sera visible." - -msgid "Flush into objects' support" -msgstr "Purger dans les supports de l'objet" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"La purge après le changement de filament se fera dans les supports des " -"objets. Cela peut réduire la quantité de déchets et diminuer le temps " -"d'impression." - -msgid "Flush into this object" -msgstr "Purger dans cet objet" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"Cet objet sera utilisé pour purger la buse après un changement de filament " -"afin d'économiser du filament et de diminuer le temps d'impression. Les " -"couleurs des objets seront mélangées en conséquence." msgid "X-Y hole compensation" msgstr "Compensation de trou X-Y" @@ -7062,6 +7535,79 @@ msgstr "" "rend le contour plus petit. Cette fonction est utilisée pour ajuster " "légèrement la taille lorsque l'objet a un problème d'assemblage" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Détecter un remplissage solide interne étroit" @@ -7081,6 +7627,18 @@ msgstr "Exporter 3MF" msgid "Export project as 3MF." msgstr "Exporter le projet au format 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 the plates: 0-all plates, i-plate i, others-invalid" msgstr "" "Trancher les assiettes : 0-toutes les assiettes, i-assiette i, autres-" @@ -7089,6 +7647,12 @@ msgstr "" msgid "Show command help." msgstr "Afficher l'aide de la commande." +msgid "UpToDate" +msgstr "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Informations sur le modèle de sortie" @@ -7101,6 +7665,12 @@ 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 "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Options d'organisation" @@ -7116,12 +7686,6 @@ msgstr "Convertir les unités du modèle" msgid "Orient the model" msgstr "Orienter le modèle" -msgid "Repair" -msgstr "Réparation" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Réparer les maillages du modèle s'il s'agit d'un maillage non multiple" - msgid "Scale the model by a float factor" msgstr "Mettre à l'échelle le modèle par un facteur flottant" @@ -7198,9 +7762,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Maillage de tranchage" -msgid " Object:" -msgstr "Objet:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Support : génération du parcours d'impression à la couche %d" @@ -7396,33 +7957,75 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Effacer la peinture" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Définir la taille du stylo" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Rotation :" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Hauteur:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Choisissez un ou plusieurs fichiers (3mf/step/stl/obj/amf) :" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "Échec de l'initialisation [%d] !" +#~ msgid "Finish" +#~ msgstr "Finish" -#~ msgid "Management" -#~ msgstr "Management" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Importer 3MF/STL/STEP/OBJ/AMF" -#~ msgid "Open" -#~ msgstr "Open" +#~ msgid "Part Cooling" +#~ msgstr "Refroidissement des pièces" + +#~ msgid "Aux Cooling" +#~ msgstr "Refroidissement auxiliaire" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" #~ msgstr "" -#~ "%1% est trop proche de la zone d'exclusion, il y aura des collisions lors " -#~ "de l'impression." +#~ "Filament pour imprimer le support et la jupe. 0 signifie qu'aucun " +#~ "filament spécifique pour le support et le filament actuel est utilisé" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Filament pour imprimer l'interface de support. 0 signifie qu'aucun " +#~ "filament spécifique pour l'interface de support et le filament actuel est " +#~ "utilisé" + +#~ msgid "Repair" +#~ msgstr "Réparation" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "" +#~ "Réparer les maillages du modèle s'il s'agit d'un maillage non multiple" + +#~ msgid "Monitoring Recording" +#~ msgstr "Enregistrement de surveillance" + +#~ msgid "Tree support with infill" +#~ msgstr "Support d'arbre avec remplissage" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Ce paramètre spécifie s'il faut ajouter un remplissage à l'intérieur des " +#~ "grands creux du support d'arbre" #~ msgid "" #~ "\n" @@ -7433,80 +8036,19 @@ msgstr "" #~ "%1% est trop proche de la zone d'exclusion, il y aura des collisions lors " #~ "de l'impression." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr "" -#~ "est trop proche des autres, il y aura des collisions lors de " -#~ "l'impression.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." #~ msgstr "" -#~ "est trop proche de la zone d'exclusion, il y aura des collisions lors de " -#~ "l'impression.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Évitez de traverser le mur lorsque vous voyagez" - -#~ msgid "Max travel detour distance" -#~ msgstr "Distance de détour maximale" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Distance de détour maximale pour éviter de traverser le mur. Ne faites " -#~ "pas de détour si la distance de détour est supérieure à cette valeur" - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Hauteur du cylindre de dégagement autour de l'extrudeuse. Utilisé comme " -#~ "entrée de l'auto-arrangement pour éviter les collisions lors de " -#~ "l'impression objet par objet" - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Rayon de dégagement autour de l'extrudeuse. Utilisé comme entrée de " -#~ "l'auto-arrangement pour éviter les collisions lors de l'impression objet " -#~ "par objet" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Erreur à la ligne %1% :\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Réduire les triangles" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "Passer au motif en zigzag?\n" -#~ "Oui - passer automatiquement au motif en zigzag\n" -#~ "Non - réinitialiser automatiquement la densité à la valeur par défaut " -#~ "autre que 100%\n" - -#~ msgid "Extruder position" -#~ msgstr "Position de l'extrudeuse" - -#~ msgid "Zig zag" -#~ msgstr "Zig zag" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "La température du lit est supérieure à la température de vitrification de " -#~ "ce filament. Cela peut entraîner le blocage de la buse et l'échec de " -#~ "l'impression" +#~ "%1% est trop proche de la zone d'exclusion, il y aura des collisions lors " +#~ "de l'impression." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Hauteur de couche adaptative" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." @@ -7527,9 +8069,35 @@ msgstr "" #~ "y a des objets sélectionnés, il oriente uniquement ceux qui sont " #~ "sélectionnés. Sinon, il oriente tous les objets du projet." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Évitez de traverser le mur lorsque vous voyagez" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "La température du lit est supérieure à la température de vitrification de " +#~ "ce filament. Cela peut entraîner le blocage de la buse et l'échec de " +#~ "l'impression" + #~ msgid "Clear all" #~ msgstr "Tout effacer" +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Rayon de dégagement autour de l'extrudeuse. Utilisé comme entrée de " +#~ "l'auto-arrangement pour éviter les collisions lors de l'impression objet " +#~ "par objet" + +#~ msgid "Color Print" +#~ msgstr "Impression couleur" + +#~ msgid "Comsumption" +#~ msgstr "Consommation" + #~ msgid "Creating" #~ msgstr "Création" @@ -7578,12 +8146,52 @@ msgstr "" #~ "Ne vous rétractez absolument pas lorsque le déplacement est dans la zone " #~ "de remplissage. Cela signifie que le suintement ne peut pas être vu" +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "En activant cette option, la hauteur de chaque couche, à l'exception de " +#~ "la première, sera automatiquement calculée en fonction de la pente de la " +#~ "surface du modèle.\n" +#~ "Veuillez noter que cette option ne prend effet que si aucune tour " +#~ "primaire n'est générée sur le plateau en cours d'utilisation." + #~ msgid "Enter a search term" #~ msgstr "Entrer un terme de recherche" +#~ msgid "Erase painting" +#~ msgstr "Effacer la peinture" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Erreur à la ligne %1% :\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Exporter le fichier découpé" + +#~ msgid "Export current Sliced file" +#~ msgstr "Exporter le fichier en tranches actuel" + +#~ msgid "Export ok." +#~ msgstr "Exporter ok." + +#~ msgid "Export sliced file" +#~ msgstr "Exporter le fichier découpé" + +#~ msgid "Extruder position" +#~ msgstr "Position de l'extrudeuse" + #~ msgid "Failed" #~ msgstr "Failed" +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" + #~ msgid "Filaments Selection" #~ msgstr "Sélection de filaments" @@ -7596,6 +8204,19 @@ msgstr "" #~ msgid "Fix model through cloud" #~ msgstr "Correction du modèle via le cloud" +#~ msgid "Flushed filament" +#~ msgstr "Filament purgé" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Forcer le ventilateur de refroidissement à une vitesse spécifique lorsque " +#~ "le degré de surplomb de la pièce imprimée dépasse cette valeur. Exprimé " +#~ "en pourcentage qui indique la largeur de la ligne sans support de la " +#~ "couche inférieure" + #~ msgid "Fragment Filter" #~ msgstr "Filtre à particules" @@ -7610,12 +8231,26 @@ msgstr "" #~ "temperature" #~ msgstr "Chauffer la buse à la température choisie" +#~ msgid "Height:" +#~ msgstr "Hauteur:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Hauteur du cylindre de dégagement autour de l'extrudeuse. Utilisé comme " +#~ "entrée de l'auto-arrangement pour éviter les collisions lors de " +#~ "l'impression objet par objet" + #~ msgid "In the calibration of extrusion flow" #~ msgstr "Calibrage du flux d'extrusion en cours" #~ msgid "In the calibration of laser scanner" #~ msgstr "Calibrage du scanner laser en cours" +#~ msgid "Initialize failed [%d]!" +#~ msgstr "Échec de l'initialisation [%d] !" + #~ msgid "Inner wall speed" #~ msgstr "Vitesse de la paroi intérieure" @@ -7629,12 +8264,34 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Type de ligne" +#~ msgid "Management" +#~ msgstr "Management" + +#~ msgid "Max travel detour distance" +#~ msgstr "Distance de détour maximale" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Distance de détour maximale pour éviter de traverser le mur. Ne faites " +#~ "pas de détour si la distance de détour est supérieure à cette valeur" + #~ msgid "Module" #~ msgstr "Module" #~ msgid "Monitoring" #~ msgstr "Surveillance" +#~ msgid "Open" +#~ msgstr "Open" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "Ouvrir &PrusaSlicer" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "Ouvrir PrusaSlicer" + #~ msgid "Output file" #~ msgstr "Fichier de sortie" @@ -7650,6 +8307,9 @@ msgstr "" #~ msgid "Per object edit" #~ msgstr "Modification par objet" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "Plaque %d : %s ne prend pas en charge le filament %s.\n" + #~ msgid "Please fill report first." #~ msgstr "Veuillez d'abord remplir le rapport." @@ -7672,6 +8332,25 @@ msgstr "" #~ msgid "Printer Selection" #~ msgstr "Sélection de l'imprimante" +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "La purge après le changement de filament se fera dans le remplissage des " +#~ "objets. Cela peut réduire la quantité de déchets et diminuer le temps " +#~ "d'impression. Si les murs sont imprimés avec un filament translucide, le " +#~ "remplissage de couleur mixte sera visible." + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "La purge après le changement de filament se fera dans les supports des " +#~ "objets. Cela peut réduire la quantité de déchets et diminuer le temps " +#~ "d'impression." + #~ msgid "" #~ "Push new filament \n" #~ "into extruder" @@ -7688,15 +8367,30 @@ msgstr "" #~ "then a snapshot is taken with the chamber camera. When printing finishes, " #~ "a timelapse video is created from all the snapshots." +#~ msgid "Reduce Triangles" +#~ msgstr "Réduire les triangles" + +#~ msgid "Reload item" +#~ msgstr "Recharger l'élément" + +#~ msgid "Reload items" +#~ msgstr "Recharger les éléments" + #~ msgid "Report" #~ msgstr "Signaler" +#~ msgid "Rotation:" +#~ msgstr "Rotation :" + #~ msgid "Save configuration as:" #~ msgstr "Enregistrer la configuration sous :" #~ msgid "Sending" #~ msgstr "Envoi en cours" +#~ msgid "Set pen size" +#~ msgstr "Définir la taille du stylo" + #~ msgid "Shift + Any arrow" #~ msgstr "Maj + n'importe quelle flèche" @@ -7731,6 +8425,16 @@ msgstr "" #~ "supplémentaires si le support est spécifié comme extrudeuse différente " #~ "avec l'objet" +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "Passer au motif en zigzag?\n" +#~ "Oui - passer automatiquement au motif en zigzag\n" +#~ "Non - réinitialiser automatiquement la densité à la valeur par défaut " +#~ "autre que 100%\n" + #~ msgid "Swith cloud environment, Please login again!" #~ msgstr "Changez d'environnement cloud, veuillez vous reconnecter !" @@ -7753,6 +8457,25 @@ msgstr "" #~ "La vitesse d'impression minimale lors du ralentissement pour le " #~ "refroidissement" +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Cet objet sera utilisé pour purger la buse après un changement de " +#~ "filament afin d'économiser du filament et de diminuer le temps " +#~ "d'impression. Les couleurs des objets seront mélangées en conséquence." + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Ce paramètre représente le volume de filament pouvant être fondu et " +#~ "extrudé par seconde. La vitesse d'impression est limitée par la vitesse " +#~ "volumétrique maximale, en cas de réglage de vitesse trop élevé et " +#~ "déraisonnable. Zéro signifie pas de limite" + #~ msgid "Timelapse Wipe Tower" #~ msgstr "Timelapse tour de purge" @@ -7771,6 +8494,36 @@ msgstr "" #~ msgid "Waiting" #~ msgstr "Attente" +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "Vous avez modifié certains paramètres prédéfinis. Souhaitez-vous " +#~ "conserver ces paramètres modifiés après avoir changé de préréglage ?" + +#~ msgid "Zig zag" +#~ msgstr "Zig zag" + +#~ msgid " Object:" +#~ msgstr "Objet:" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr "" +#~ "est trop proche de la zone d'exclusion, il y aura des collisions lors de " +#~ "l'impression.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr "" +#~ "est trop proche des autres, il y aura des collisions lors de " +#~ "l'impression.\n" + +#~ msgid "normal" +#~ msgstr "Ordinaire" + #~ 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 "tree" +#~ msgstr "arbre" diff --git a/bbl/i18n/hu/BambuStudio_hu.po b/bbl/i18n/hu/BambuStudio_hu.po index d74cee127b..33b73cf4fb 100644 --- a/bbl/i18n/hu/BambuStudio_hu.po +++ b/bbl/i18n/hu/BambuStudio_hu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -17,11 +17,14 @@ msgid "Supports Painting" msgstr "Támaszok festése" msgid "Alt + Mouse wheel" -msgstr "Alt + Mouse wheel" +msgstr "Alt + Egérgörgő" msgid "Section view" msgstr "Keresztmetszet nézet" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + Egérgörgő" @@ -67,6 +70,9 @@ msgstr "Eszköz típusa" msgid "Smart fill angle" msgstr "Okos kitöltési szög" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Automatikus támasz szögének határértéke: " @@ -82,6 +88,10 @@ msgstr "Kitöltés" msgid "Gap Fill" msgstr "Hézagok kitöltése" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Felületek kiemelése a túlnyúlási szögnek megfelelően." @@ -138,6 +148,12 @@ msgstr "Vödör kitöltés" msgid "Height range" msgstr "Magasságtartomány" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Gyorsgomb " @@ -173,7 +189,7 @@ 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 "Tool-Lay on Face" +msgstr "Eszköz-Felületre fektetés" msgid "in" msgstr "in" @@ -197,7 +213,7 @@ msgid "Volume Operations" msgstr "Térfogat műveletek" msgid "Translate" -msgstr "Translate" +msgstr "Fordítás" msgid "Group Operations" msgstr "Csoportos műveletek" @@ -254,7 +270,7 @@ msgid "Cut to parts" msgstr "Részekre darabolás" msgid "Auto Segment" -msgstr "Auto Segment" +msgstr "Automatikus szegmentálás" msgid "Perform cut" msgstr "Vágás" @@ -330,14 +346,11 @@ msgstr "" "A művelet törlése már folyamatban van. Kérjük, várj néhány másodpercet." msgid "Face recognition" -msgstr "Face recognition" +msgstr "Arcfelismerés" msgid "Perform Recognition" msgstr "Felismerés" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -356,15 +369,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -514,8 +518,8 @@ msgstr "Mód nézet betöltése" msgid "Choose one file (3mf):" msgstr "Válassz ki egy fájlt (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Válassz ki egy vagy több fájlt (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Válassz ki egy fájlt (gcode/.gco/.g/.ngc/ngc):" @@ -527,8 +531,8 @@ msgid "" "You can keep the modifield presets to the new project, discard or save " "changes as new presets." msgstr "" -"You can keep the modified presets for the new project, discard, or save " -"changes as new presets." +"Megtarthatod az új projekt módosított beállításait, elvetheted őket, vagy " +"elmentheted új beállításokként." msgid "User logged out" msgstr "" @@ -598,6 +602,9 @@ msgstr "Kitöltés" msgid "Support" msgstr "Támasz" +msgid "Flush options" +msgstr "Öblítési lehetőségek" + msgid "Speed" msgstr "Sebesség" @@ -620,7 +627,7 @@ msgid "Ironing" msgstr "Vasalás" msgid "Fuzzy Skin" -msgstr "Fuzzy skin" +msgstr "Barázdált felület" msgid "Extruders" msgstr "Extruderek" @@ -731,6 +738,18 @@ msgstr "Átméretezés a nyomtatótérhez" msgid "Scale an object to fit the build volume" msgstr "Átméretez egy objektumot, hogy beférjen a nyomtatótérbe" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Öblítés a tárgyak kitöltésébe" + +msgid "Flush into this object" +msgstr "Öblítés ebbe a tárgyba" + +msgid "Flush into objects' support" +msgstr "Öblítés a tárgyak támaszába" + msgid "Convert from inch" msgstr "Átváltás hüvelykről" @@ -783,6 +802,9 @@ msgstr "Objektum tükrözése" msgid "Add Primitive" msgstr "Primitív hozzáadása" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "Objektumokra" @@ -850,6 +872,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -940,6 +965,16 @@ msgstr "Általános" msgid "Add Modifier" msgstr "Módosító hozzáadása" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" +"Válts át objektumonkénti beállítási módba a módosító beállításainak " +"szerkesztéséhez." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "Az utolsó szilárd rész törlése nem megengedett." @@ -977,7 +1012,7 @@ msgstr "" "lennie." msgid "The type of the last solid object part is not to be changed." -msgstr "The type of the last solid object part cannot be changed." +msgstr "Az utolsó tömör objektumrész típusa nem módosítható." msgid "Negative Part" msgstr "Negatív tárgy" @@ -1087,6 +1122,9 @@ msgstr "Több" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1099,6 +1137,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1120,8 +1167,8 @@ msgstr "" msgid "No printer" msgstr "Nincs nyomtató" -msgid "Heat the nozzle to target temperature" -msgstr "Fúvóka felmelegítése a kívánt hőmérsékletre" +msgid "Heat the nozzle" +msgstr "" msgid "Cut filament" msgstr "Filament vágása" @@ -1145,10 +1192,10 @@ msgid "Click the pencil icon to edit the filament." msgstr "Kattints a ceruza ikonra a filament szerkesztéséhez." msgid "Load Filament" -msgstr "Load" +msgstr "Filament betöltés" msgid "Unload Filament" -msgstr "Unload" +msgstr "Filament kitöltése" msgid "Tips" msgstr "Tippek" @@ -1255,7 +1302,7 @@ msgid "Orienting" msgstr "Orientáció" msgid "Error! Unable to create thread!" -msgstr "Error. Unable to create thread." +msgstr "Hiba. Nem sikerült létrehozni a szálat." msgid "Exception" msgstr "Kivétel" @@ -1273,7 +1320,7 @@ msgid "Failure of printer login" msgstr "Sikertelen bejelentkezés a nyomtatóra" msgid "Failed to get ticket" -msgstr "Failed to get ticket" +msgstr "Nem sikerült jegyet szerezni" msgid "User authorization timeout" msgstr "Felhasználó hitelesítési időtúllépés" @@ -1334,13 +1381,34 @@ msgid "Sending print configuration" msgstr "Nyomtatási konfiguráció küldése" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" -"Sikeresen elküldve. Az eszköz oldala automatikusan megjelenik %s mp belül" msgid "An SD card needs to be inserted before printing via LAN." msgstr "A LAN-on keresztüli nyomtatáshoz helyezz be egy SD kártyát." +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "Letöltés" @@ -1350,8 +1418,8 @@ msgstr "Letöltés sikertelen" msgid "Cancelled" msgstr "Megszakítva" -msgid "Finish" -msgstr "Kész" +msgid "Install successfully." +msgstr "" msgid "Installing" msgstr "Telepítés" @@ -1453,6 +1521,9 @@ msgstr "" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Megerősítés" @@ -1478,11 +1549,24 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "AMS beállítások" msgid "Insertion update" -msgstr "Insertion update" +msgstr "Frissítés" msgid "" "The AMS will automatically read the filament information when inserting a " @@ -1526,6 +1610,23 @@ msgstr "" "behelyezett filamentről, és továbbra is a legutóbbi leállítás előtt " "rögzített információkat használja." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Fájl" @@ -1727,6 +1828,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1765,11 +1871,12 @@ msgid "" "\n" "The value will be reset to 0." msgstr "" -"This setting is only used for tuning model size by small amounts.\n" -"For example, when the model size has small errors or when tolerances are " -"incorrect. For large adjustments, please use the model scale function.\n" +"Ez a beállítás csak a modell méretének kismértékű finomítására szolgál.\n" +"Például, ha a modellméret kis mértékben eltér, vagy ha a tűrések " +"helytelenek. Nagyobb mértékű változtatásokhoz használd a modell átméretezése " +"funkciót.\n" "\n" -"The value will be reset to 0." +"Az érték 0-ra áll vissza." msgid "" "Too large elefant foot compensation is unreasonable.\n" @@ -1778,11 +1885,11 @@ msgid "" "\n" "The value will be reset to 0." msgstr "" -"The elephant foot compensation value is too large.\n" -"If there are significant elephant foot issues, please check other settings.\n" -"The bed temperature may be too high, for example.\n" +"Az elefántláb kompenzáció értéke túl nagy.\n" +"Ha jelentős elefántláb-problémával küzdesz, ellenőrizd a többi beállítást.\n" +"Például lehetséges, hogy az asztal hőmérséklete túl magas.\n" "\n" -"The value will be reset to 0." +"Az érték 0-ra áll vissza." msgid "" "Spiral mode only works when wall loops is 1, \n" @@ -1802,6 +1909,17 @@ msgstr "" "spirál mód használatát\n" "Nem - Ne használja a spirál módot ez alkalommal" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1847,6 +1965,9 @@ msgid "" "Yes - switch to rectilinear pattern automaticlly\n" "No - reset density to default non 100% value automaticlly\n" msgstr "" +"Switch to rectilinear pattern?\n" +"Yes - switch to rectilinear pattern automaticlly\n" +"No - reset density to default non 100% value automaticlly\n" msgid "Auto bed leveling" msgstr "Automatikus asztalszintezés" @@ -1855,13 +1976,13 @@ msgid "Heatbed preheating" msgstr "Asztal előfűtése" msgid "Sweeping XY mech mode" -msgstr "Sweeping XY mech mode" +msgstr "XY mechanika ellenőrzése" msgid "Changing filament" msgstr "Filament váltása" msgid "M400 pause" -msgstr "M400 pause" +msgstr "M400 szünet" msgid "Paused due to filament runout" msgstr "Megállítva, mert kifogyott a filament" @@ -1897,7 +2018,7 @@ msgid "Printing was paused by the user" msgstr "Nyomtatás szüneteltetve a felhasználó által" msgid "Pause of front cover falling" -msgstr "Pause of front cover falling" +msgstr "Szünet az előlap leesése miatt" msgid "Calibrating the micro lida" msgstr "Micro Lidar kalibrálása" @@ -1953,6 +2074,9 @@ msgstr "A frissítés sikertelen." msgid "Failed to start printing job" msgstr "Nem sikerült elindítani a nyomtatási feladatot" +msgid "default" +msgstr "alapértelmezett" + msgid "parameter name" msgstr "" @@ -1968,13 +2092,13 @@ msgstr "%s nem lehet százalék" #, c-format, boost-format msgid "Value %s is out of range, continue?" -msgstr "Value %s is out of range, continue?" +msgstr "%s érték tartományon kívül esik, folytatod?" msgid "Parameter validation" msgstr "Paraméter validáció" msgid "Value is out of range." -msgstr "Value is out of range." +msgstr "Az érték tartományon kívül esik." #, c-format, boost-format msgid "" @@ -1982,13 +2106,13 @@ msgid "" "YES for %s%%, \n" "NO for %s %s." msgstr "" -"Is it %s%% or %s %s?\n" -"YES for %s%%, \n" -"NO for %s %s." +"%s%% vagy %s %s?\n" +"IGEN %s%%, \n" +"NEM %s %s." #, boost-format msgid "Invalid format. Expected vector format: \"%1%\"" -msgstr "Invalid format. Expected vector format: \"%1%\"" +msgstr "Érvénytelen formátum. Elvárt vektor formátum: \"%1%\"" msgid "Layer Height" msgstr "Rétegmagasság" @@ -2000,13 +2124,13 @@ msgid "Fan Speed" msgstr "Ventilátor fordulatszám" msgid "Temperature" -msgstr "Temperature" +msgstr "Hőmérséklet" msgid "Flow" msgstr "Anyagáramlás" msgid "Tool" -msgstr "Tool" +msgstr "Szerszám" msgid "Height: " msgstr "" @@ -2020,8 +2144,14 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" -msgstr "Loading G-codes" +msgstr "G-kódok betöltése" msgid "Generating geometry vertex data" msgstr "Geometriai vertex adatok generálása" @@ -2029,29 +2159,29 @@ msgstr "Geometriai vertex adatok generálása" msgid "Generating geometry index data" msgstr "Geometriai index adatok generálása" +msgid "Display" +msgstr "Megjelenítés" + msgid "up to" -msgstr "up to" +msgstr "legfeljebb" msgid "above" -msgstr "above" +msgstr "felett" msgid "from" -msgstr "from" +msgstr "ettől" msgid "to" -msgstr "to" +msgstr "eddig" msgid "Color Scheme" msgstr "Színséma" -msgid "Percent" -msgstr "Százalék" - msgid "Time" msgstr "Idő" -msgid "Display" -msgstr "Megjelenítés" +msgid "Percent" +msgstr "Százalék" msgid "Layer Height (mm)" msgstr "Rétegmagasság (mm)" @@ -2066,22 +2196,19 @@ msgid "Fan Speed (%)" msgstr "Ventilátor fordulatszám (%)" msgid "Temperature (°C)" -msgstr "Temperature (°C)" +msgstr "Hőmérséklet (°C)" msgid "Volumetric flow rate (mm³/s)" msgstr "Térfogatáramlás (mm³/s)" msgid "Used filament" -msgstr "Used filament" +msgstr "Használt filament" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Színes nyomtatás" - -msgid "Comsumption" -msgstr "Felhasználás" +msgid "Total" +msgstr "Összesen" msgid "Travel" msgstr "Mozgás" @@ -2093,13 +2220,13 @@ msgid "Retract" msgstr "Visszahúzás" msgid "Unretract" -msgstr "Unretract" +msgstr "Visszahúzás" msgid "Filament Changes" msgstr "Filamentcserék" msgid "Wipe" -msgstr "Wipe" +msgstr "Törlés" msgid "Options" msgstr "Opciók" @@ -2110,18 +2237,12 @@ msgstr "mozgás" msgid "Extruder" msgstr "Extruder" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "Öblített filament" - -msgid "Total" -msgstr "Összesen" - msgid "Filament change times" msgstr "Filamentcserék száma" +msgid "Cost" +msgstr "Költség" + msgid "Color change" msgstr "Színváltás" @@ -2140,11 +2261,11 @@ msgstr "Nyomtatási beállítások" msgid "Total Estimation" msgstr "Összesített becslés" -msgid "Normal mode" -msgstr "Normal mode" +msgid "Time Estimation" +msgstr "" -msgid "Cost" -msgstr "Költség" +msgid "Normal mode" +msgstr "Normál mód" msgid "Prepare time" msgstr "Előkészítési idő" @@ -2152,23 +2273,74 @@ msgstr "Előkészítési idő" msgid "Model printing time" msgstr "Modell nyomtatási ideje" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" -msgstr "Switch to silent mode" +msgstr "Váltás csendes módra" msgid "Switch to normal mode" -msgstr "Switch to normal mode" +msgstr "Váltás normál módra" + +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Sugár" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" msgid "Sequence" msgstr "Sorrend" msgid "Mirror Object" -msgstr "Mirror object" +msgstr "Objektum tükrözése" msgid "Tool Move" -msgstr "Tool move" +msgstr "Fej mozgatása" msgid "Move Object" -msgstr "Move object" +msgstr "Objektum mozgatása" msgid "Auto Orientation options" msgstr "Automatikus orientáció beállításai" @@ -2177,7 +2349,7 @@ msgid "Enable rotation" msgstr "Forgatás engedélyezése" msgid "Optimize support interface area" -msgstr "Optimize support interface area" +msgstr "Támasz érintkező felületének optimalizálása" msgid "Orient" msgstr "Orientáció" @@ -2222,7 +2394,7 @@ msgid "Select Plate" msgstr "Tálca kiválasztása" msgid "Assembly Return" -msgstr "Assembly Return" +msgstr "Vissza az összeszereléshez" msgid "return" msgstr "vissza" @@ -2240,7 +2412,7 @@ msgid "Assemble Control" msgstr "" msgid "Total Volume:" -msgstr "Total Volume:" +msgstr "Teljes térfogat:" msgid "Assembly Info" msgstr "Összeállítási információ" @@ -2273,6 +2445,18 @@ msgstr "" msgid "Calibration" msgstr "Kalibrálás" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Kalibrációs program" @@ -2281,9 +2465,9 @@ msgid "" "minimize deviation.\n" "It keeps the device performing optimally." msgstr "" -"The calibration program detects the status of your device automatically to " -"minimize deviation.\n" -"It keeps the device performing optimally." +"A kalibrációs program automatikusan felismeri a nyomtató állapotát, hogy " +"minimálisra csökkentse az eltéréseket.\n" +"A nyomtatót az optimális teljesítményen tartja." msgid "Calibration Flow" msgstr "Kalibrációs anyagáramlás" @@ -2297,11 +2481,23 @@ msgstr "Befejezve" msgid "Calibrating" msgstr "Kalibrálás" -msgid "Timelapse" -msgstr "Timelapse" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Monitoring Recording" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Felbontás" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Nyomtató csatlakoztatása (LAN)" @@ -2313,8 +2509,8 @@ msgid "" "You can find it in \"Settings > Network > Connection code\"\n" "on the printer, as shown in the figure:" msgstr "" -"You can find it in \"Settings > Network > Access code\"\n" -"on the printer, as shown in the figure:" +"Ezt a \"Beállítások > Hálózat > Csatlakozási kód\" menüpontban\n" +"találod a nyomtatón, ahogy az ábrán látható:" msgid "Invalid input." msgstr "" @@ -2332,7 +2528,7 @@ msgid "Closing Application while some presets are modified." msgstr "Alkalmazás bezárása egyes beállítások módosítása közben." msgid "Logging" -msgstr "Logging" +msgstr "Naplózás" msgid "Prepare" msgstr "Előkészítés" @@ -2346,6 +2542,15 @@ msgstr "Nyomtató" msgid "Project" msgstr "Projekt" +msgid "Yes" +msgstr "Igen" + +msgid "No" +msgstr "Nem" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Szeletelés" @@ -2355,17 +2560,26 @@ msgstr "Összes szeletelése" msgid "Slice plate" msgstr "Tálca szeletelése" -msgid "Print all" -msgstr "Összes nyomtatása" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Szeletelt fájl exportálása" +msgid "Send" +msgstr "Küldés" -msgid "Export Sliced File" -msgstr "Szeletelt fájl exportálása" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Összes nyomtatása" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Gyorsbillentyűk" @@ -2379,17 +2593,23 @@ msgstr "Beállítás varázsló" msgid "Show Configuration Folder" msgstr "Konfigurációs mappa megjelenítése" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Frissítés keresése" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&%s névjegye" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2460,11 +2680,11 @@ msgstr "Projekt mentése másként" msgid "Save current project as" msgstr "Jelenlegi projekt mentése másként" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "3MF/STL/STEP/OBJ/AMF importálása" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" -msgstr "Load a model" +msgstr "Modell betöltése" msgid "Import Configs" msgstr "Import Configs" @@ -2484,8 +2704,11 @@ msgstr "Export Generic 3MF" msgid "Export 3mf file without using some 3mf-extensions" msgstr "Export 3mf file without using some 3mf-extensions" -msgid "Export current Sliced file" -msgstr "Jelenlegi szeletelt fájl exportálása" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "G-kód exportálása" @@ -2577,29 +2800,32 @@ msgstr "Nézet" msgid "Help" msgstr "Segítség" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" -msgstr "&Open G-code" +msgstr "&G-kód megnyitása" msgid "Open a G-code file" msgstr "G-kód fájl megnyitása" msgid "Re&load from Disk" -msgstr "Re&load from Disk" +msgstr "Újratöltés lemezről" msgid "Reload the plater from disk" -msgstr "Reload the plater from disk" +msgstr "Plater újratöltése a lemezről" msgid "Export &Toolpaths as OBJ" -msgstr "Export &Toolpaths as OBJ" +msgstr "Szerszámút exportálása OBJ-ként" msgid "Export toolpaths as OBJ" msgstr "Szerszámút exportálása OBJ-ként" -msgid "Open &PrusaSlicer" -msgstr "Open &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Open PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Kilépés" @@ -2609,13 +2835,13 @@ msgid "Quit %s" msgstr "Kilépés %s" msgid "&File" -msgstr "&File" +msgstr "&Fájl" msgid "&View" -msgstr "&View" +msgstr "&Nézet" msgid "&Help" -msgstr "&Help" +msgstr "&Segítség" msgid "Overwrite file" msgstr "Overwrite file" @@ -2655,7 +2881,7 @@ msgid "File is missing" msgstr "Hiányzik a fájl" msgid "The project is no longer available." -msgstr "The project is no longer available." +msgstr "A projekt már nem elérhető." msgid "Filament Settings" msgstr "Filament beállítások" @@ -2674,7 +2900,7 @@ msgstr "" "3. Nyomtató beállítások\n" msgid "Synchronization" -msgstr "Synchronization" +msgstr "Szinkronizálás" msgid "Initialize failed (No Device)!" msgstr "Sikertelen inicializálás (Nincs eszköz)!" @@ -2683,10 +2909,10 @@ msgid "Initialize failed (No Camera Device)!" msgstr "" msgid "Initializing..." -msgstr "Initializing..." +msgstr "Inicializálás…" msgid "Loading..." -msgstr "Loading..." +msgstr "Betöltés…" msgid "Initialize failed (Not supported with LAN-only mode)!" msgstr "" @@ -2694,7 +2920,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2711,12 +2940,33 @@ msgstr "" msgid "Stopped." msgstr "Megállítva." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Lejátszás..." #, c-format, boost-format msgid "Load failed [%d]!" -msgstr "Loading failed [%d]!" +msgstr "A betöltés sikertelen [%d]!" msgid "Year" msgstr "Year" @@ -2736,6 +2986,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Timelapse" + msgid "Switch to timelapse files." msgstr "" @@ -2763,7 +3016,7 @@ msgstr "" msgid "No printers." msgstr "No printers." -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2779,6 +3032,12 @@ msgstr "Loading file list..." msgid "No files" msgstr "No files" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2809,7 +3068,7 @@ msgid "Options:" msgstr "Opciók:" msgid "Zoom" -msgstr "Zoom" +msgstr "Nagyítás" msgid "Translation/Zoom" msgstr "" @@ -2818,11 +3077,17 @@ msgid "3Dconnexion settings" msgstr "3Dconnexion beállítások" msgid "Swap Y/Z axes" -msgstr "Swap Y/Z axes" +msgstr "Y/Z tengelyek felcserélése" msgid "Camera" msgstr "Kamera" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Nyomtatás folyamata" @@ -2850,11 +3115,11 @@ msgstr "100%" msgid "Lamp" msgstr "Világítás" -msgid "Part Cooling" -msgstr "Tárgyhűtés" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Segédhűtés" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Asztal" @@ -2865,6 +3130,12 @@ msgstr "Kitöltés" msgid "Debug Info" msgstr "Hibakeresési infó" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Nyomtatási lista" @@ -2874,9 +3145,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "Letöltés..." +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2892,6 +3192,9 @@ msgstr "Sport" msgid "Ludicrous" msgstr "Őrült" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Nem sikerült csatlakozni a szerverhez" @@ -2899,10 +3202,10 @@ msgid "Status" msgstr "Állapot" msgid "Media" -msgstr "Media" +msgstr "Média" msgid "Update" -msgstr "Update" +msgstr "Frissítés" msgid "HMS" msgstr "HMS" @@ -2910,11 +3213,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Nem sikerült csatlakozni a nyomtatóhoz" -msgid "Yes" -msgstr "Igen" - -msgid "No" -msgstr "Nem" +msgid "Don't show again" +msgstr "Ne mutasd újra" #, c-format, boost-format msgid "%s error" @@ -2950,19 +3250,19 @@ msgid "Configuration can update now." msgstr "A konfiguráció már frissíthető." msgid "Detail." -msgstr "More" +msgstr "Több" msgid "Integration was successful." -msgstr "Integration was successful." +msgstr "Az integráció sikeres volt." msgid "Integration failed." -msgstr "Integration failed." +msgstr "Az integráció nem sikerült." msgid "Undo integration was successful." -msgstr "Undo integration was successful." +msgstr "Az integráció visszavonása sikeres volt." msgid "Undo integration failed." -msgstr "Undo integration failed." +msgstr "Az integráció visszavonása nem sikerült." msgid "Exporting." msgstr "Exportálás." @@ -3010,7 +3310,7 @@ msgid "Export." msgstr "Exportálás." msgid "Jump to" -msgstr "Jump to" +msgstr "Ugrás ide:" msgid "Error:" msgstr "Hiba:" @@ -3018,8 +3318,8 @@ msgstr "Hiba:" msgid "Warning:" msgstr "Figyelem:" -msgid "Export ok." -msgstr "Exportálás kész." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Javítás)" @@ -3028,10 +3328,11 @@ msgid " Click here to install it." msgstr " Kattints ide a telepítéshez." msgid "WARNING:" -msgstr "WARNING:" +msgstr "FIGYELEM:" msgid "Your model needs support ! Please make support material enable." -msgstr "Your model needs support! Please enable support material." +msgstr "" +"A modellnek támaszra van szüksége! Kérjük, engedélyezd a támasz generálását." msgid "Gcode path overlap" msgstr "G-kód útvonal átfedés" @@ -3043,33 +3344,30 @@ msgid "Color painting" msgstr "Színfestés" msgid "Layers" -msgstr "Layers" +msgstr "Rétegek" msgid "Range" msgstr "Tartomány" -msgid "default" -msgstr "alapértelmezett" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" msgstr "" -"The application cannot run normally because your OpenGL version is lower " -"than 2.0.\n" +"Az alkalmazás nem futtatható megfelelően, mert az OpenGL verziója 2.0-nál " +"alacsonyabb.\n" msgid "Please upgrade your graphics card driver." msgstr "Kérjük, frissítsd a grafikus kártya illesztőprogramját." msgid "Unsupported OpenGL version" -msgstr "Unsupported OpenGL version" +msgstr "Nem támogatott OpenGL verzió" #, c-format, boost-format msgid "" "Unable to load shaders:\n" "%s" msgstr "" -"Unable to load shaders:\n" +"Nem sikerült betölteni a shadereket:\n" "%s" msgid "Error loading shaders" @@ -3083,20 +3381,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Alsó" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." -msgstr "Switch to per-object setting mode to edit modifier settings." - -msgid "Don't show again" -msgstr "Ne mutasd újra" +msgid "Auto-recovery from step loss" +msgstr "" msgid "Global" msgstr "Globális" @@ -3111,7 +3414,7 @@ msgid "Compare presets" msgstr "Beállítások összehasonlítása" msgid "View all object's settings" -msgstr "View all object's settings" +msgstr "Összes objektum beállításainak megtekintése" msgid "Filament settings" msgstr "Filament beállítások" @@ -3124,22 +3427,22 @@ msgid " plate %1%:" msgstr " %1% tálca:" msgid "Invalid name, the following characters are not allowed:" -msgstr "Invalid name, the following characters are not allowed:" +msgstr "Érvénytelen név, a következő karakterek nem megengedettek:" msgid "Sliced Info" msgstr "Szeletelési infó" msgid "Used Filament (m)" -msgstr "Used Filament (m)" +msgstr "Felhasznált filament (m)" msgid "Used Filament (mm³)" -msgstr "Used Filament (mm³)" +msgstr "Felhasznált filament (mm³)" msgid "Used Filament (g)" -msgstr "Used Filament (g)" +msgstr "Felhasznált filament (g)" msgid "Used Materials" -msgstr "Used Materials" +msgstr "Felhasznált anyagok" msgid "Estimated time" msgstr "Becsült idő" @@ -3157,7 +3460,7 @@ msgid "Bed type" msgstr "Asztaltípus" msgid "Flushing volumes" -msgstr "Öblítési mennyiségek" +msgstr "Tisztítási mennyiségek" msgid "Add one filament" msgstr "" @@ -3165,7 +3468,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3186,8 +3489,14 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" -msgstr "Untitled" +msgstr "Névtelen" #, boost-format msgid "Do you want to save changes to \"%1%\"?" @@ -3214,9 +3523,15 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" -msgstr "Loading file: %s" +msgstr "Fájl betöltése: %s" msgid "The 3mf is not from Bambu Lab, load geometry data only." msgstr "" @@ -3235,14 +3550,14 @@ msgid "" "The 3mf's version %s is newer than %s's version %s, Found following keys " "unrecognized:\n" msgstr "" -"The 3mf file's version %s is newer than %s's version %s, Found the following " -"unrecognized keys:\n" +"A 3mf fájl %s verziója újabb, mint a(z) %s verziója %s, a következő " +"ismeretlen kulcsokat találtuk:\n" msgid "You'd better upgrade your software.\n" -msgstr "You'd better upgrade your software.\n" +msgstr "Jobb lenne, ha frissítenéd a szoftvert.\n" msgid "Newer 3mf version" -msgstr "Newer 3mf version" +msgstr "Újabb 3mf verzió" #, c-format, boost-format msgid "" @@ -3257,10 +3572,11 @@ msgid "Incompatible 3mf" msgstr "Nem kompatibilis 3mf" msgid "Name of components inside step file is not UTF8 format!" -msgstr "Component name(s) inside step file not in UTF8 format!" +msgstr "A STEP fájlon belüli komponens neve nem UTF-8 formátumban van!" msgid "The name may show garbage characters!" -msgstr "Because of unsupported text encoding, garbage characters may appear!" +msgstr "" +"A nem támogatott szövegkódolás miatt helytelen karakterek jelenhetnek meg!" msgid "Attention!" msgstr "Figyelem!" @@ -3270,21 +3586,21 @@ msgid "Failed loading file \"%1%\". An invalid configuration was found." msgstr "Nem sikerült betölteni \"%1%\" fájlt. Érvénytelen konfiguráció." msgid "Objects with zero volume removed" -msgstr "Objects with zero volume removed" +msgstr "Nulla térfogatú objektumok eltávolítva" msgid "The volume of the object is zero" -msgstr "The volume of the object is zero" +msgstr "Az objektum térfogata nulla" #, c-format, boost-format msgid "" "The object from file %s is too small, and maybe in meters or inches.\n" " Do you want to scale to millimeters?" msgstr "" -"The object from file %s is too small, and may be in meters or inches.\n" -" Do you want to scale to millimeters?" +"A(z) %s fájlból származó objektum túl kicsi, lehet, hogy méterben vagy " +"hüvelykben lett létrehozva. Szeretnéd milliméterre méretezni?" msgid "Object too small" -msgstr "Object too small" +msgstr "Objektum túl kicsi" msgid "" "This file contains several objects positioned at multiple heights.\n" @@ -3296,13 +3612,13 @@ msgid "Multi-part object detected" msgstr "" msgid "Load these files as a single object with multiple parts?\n" -msgstr "Load these files as a single object with multiple parts?\n" +msgstr "Betöltöd ezeket a fájlokat több részből álló egyetlen objektumként?\n" msgid "Object with multiple parts was detected" -msgstr "An object with multiple parts was detected" +msgstr "Több részből álló objektumot észleltünk" msgid "The file does not contain any geometry data." -msgstr "The file does not contain any geometry data." +msgstr "A fájl nem tartalmaz geometriai adatokat." msgid "" "Your object appears to be too large, Do you want to scale it down to fit the " @@ -3319,14 +3635,11 @@ msgid "Save file as:" msgstr "Fájl mentése mint:" msgid "The selected object couldn't be split." -msgstr "The selected object couldn't be split." +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 "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3343,13 +3656,16 @@ msgid "Slicing" msgstr "Szeletelés" msgid "There are warnings after slicing models:" -msgstr "There are warnings after slicing models:" +msgstr "A modellek szeletelése a következő figyelmeztetéseket generálta:" msgid "warnings" -msgstr "warnings" +msgstr "figyelmeztetések" msgid "Invalid data" -msgstr "Invalid data" +msgstr "Érvénytelen adat" + +msgid "Slicing Canceled" +msgstr "" #, c-format, boost-format msgid "Slicing Plate %d" @@ -3371,16 +3687,39 @@ msgstr "" "Előkészítés fülre" msgid "You can keep the modified presets to the new project or discard them" -msgstr "You can keep the modified presets for the new project or discard them" +msgstr "" +"Megtarthatod az új projekt módosított beállításait, vagy elvetheted őket" msgid "Creating a new project" msgstr "Új projekt létrehozása" msgid "Load project" -msgstr "Load project" +msgstr "Projekt betöltése" + +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" msgid "The selected file" -msgstr "The selected file" +msgstr "A kiválasztott fájl" msgid "does not contain valid gcode." msgstr "nem tartalmaz érvényes G-kódot." @@ -3401,7 +3740,7 @@ msgid "Import geometry only" msgstr "Csak a geometria importálása" msgid "Only one G-code file can be opened at the same time." -msgstr "Only one G-code file can be opened at a time." +msgstr "Egyszerre csak egy G-kód fájl nyitható meg." msgid "G-code loading" msgstr "G-code betöltése" @@ -3438,6 +3777,12 @@ msgstr "G-kód fájl mentése mint:" msgid "Save Sliced file as:" msgstr "Szeletelt fájl mentése mint:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3457,7 +3802,10 @@ msgstr "" "Az egyedi támaszok és a színfestés eltávolításra került a javítást előtt." msgid "Invalid number" -msgstr "Invalid number" +msgstr "Érvénytelen szám" + +msgid "Select Bed Type" +msgstr "" #, boost-format msgid "Part name: %1%\n" @@ -3487,17 +3835,29 @@ msgstr "Térfogat: %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Háromszögek: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" -msgstr "Switching languages requires the application to restart.\n" +msgstr "A nyelvváltáshoz az alkalmazás újraindítása szükséges.\n" msgid "Do you want to continue?" msgstr "Szeretnéd folytatni?" msgid "Language selection" -msgstr "Language selection" +msgstr "Nyelv kiválasztása" msgid "Switching application language while some presets are modified." -msgstr "Switching application language while some presets are modified." +msgstr "Alkalmazás nyelvének átváltása, miközben egyes beállítások módosultak." msgid "Changing application language" msgstr "Alkalmazás nyelvének megváltoztatása" @@ -3562,7 +3922,7 @@ msgstr "" "Folyamat)" msgid "User Sync" -msgstr "User Sync" +msgstr "Felhasználó szinkronizálás" msgid "Associate files to BambuStudio" msgstr "Fájlok társítása a BambuStudiohoz" @@ -3603,6 +3963,12 @@ msgstr "Intervallum" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Kezdőoldal és napi tippek" @@ -3610,7 +3976,7 @@ msgid "Show home page on startup" msgstr "Kezdőlap megjelenítése indításkor" msgid "Sync settings" -msgstr "Sync settings" +msgstr "Szinkronizálási beállítások" msgid "Preset sync" msgstr "Beállítások szinkronizálása" @@ -3619,22 +3985,22 @@ msgid "Preferences sync" msgstr "Beállítások szinkronizálása" msgid "View control settings" -msgstr "View control settings" +msgstr "Vezérlési beállítások megtekintése" msgid "Rotate of view" msgstr "Nézet elforgatása" msgid "Move of view" -msgstr "Pan View" +msgstr "Pásztázó nézet" msgid "Zoom of view" -msgstr "Zoom View" +msgstr "Nagyítás nézet" msgid "Other" msgstr "Egyéb" msgid "Mouse wheel reverses when zooming" -msgstr "Reverse scroll direction while zooming" +msgstr "Görgetési irány megfordítása nagyítás közben" msgid "Develop mode" msgstr "Fejlesztői mód" @@ -3643,7 +4009,7 @@ msgid "Dump video" msgstr "Dump video" msgid "Log Level" -msgstr "Log Level" +msgstr "Naplózási szint" msgid "fatal" msgstr "súlyos" @@ -3652,16 +4018,16 @@ msgid "error" msgstr "hiba" msgid "warning" -msgstr "warning" +msgstr "figyelmeztetés" msgid "info" -msgstr "info" +msgstr "infó" msgid "debug" msgstr "debug" msgid "trace" -msgstr "trace" +msgstr "követés" msgid "Host Setting" msgstr "Host beállítás" @@ -3682,7 +4048,7 @@ msgid "debug save button" msgstr "debug mentés gomb" msgid "save debug settings" -msgstr "save debug settings" +msgstr "hibakeresési beállítások mentése" msgid "DEBUG settings have saved successfully!" msgstr "DEBUG beállítások sikeresen elmentve!" @@ -3691,10 +4057,10 @@ msgid "Switch cloud environment, Please login again!" msgstr "" msgid "System presets" -msgstr "System presets" +msgstr "Rendszer beállítások" msgid "User presets" -msgstr "User presets" +msgstr "Felhasználói beállítások" msgid "Incompatible presets" msgstr "Nem kompatibilis beállítások" @@ -3714,6 +4080,15 @@ msgstr "Beállítás módosítása" msgid "Project-inside presets" msgstr "Projekten belüli beállítások" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "Szeleteld fel az összes tálcát az idő és a filament becsléséhez" @@ -3721,13 +4096,13 @@ msgid "Packing project data into 3mf file" msgstr "Projektadatok csomagolása 3mf fájlba" msgid "Uploading 3mf" -msgstr "Uploading 3mf" +msgstr "3mf feltöltése" msgid "Jump to model publish web page" -msgstr "Jump to model publish web page" +msgstr "Ugrás a modell közzététele weboldalra" msgid "Note: The preparation may takes several minutes. Please be patiant." -msgstr "Note: The preparation may take several minutes. Please be patient." +msgstr "Megjegyzés: Az előkészítés több percig is eltarthat. Kérjük várj." msgid "Publish" msgstr "Közzététel" @@ -3742,7 +4117,7 @@ msgid "Packing data to 3mf" msgstr "Adatok csomagolása 3mf-be" msgid "Jump to webpage" -msgstr "Jump to webpage" +msgstr "Ugrás a weboldalra" #, c-format, boost-format msgid "Save %s as" @@ -3755,7 +4130,7 @@ msgid "Project Inside Preset" msgstr "Projekt a beállításon belül" msgid "Name is invalid;" -msgstr "Name is invalid;" +msgstr "A név érvénytelen;" msgid "illegal characters:" msgstr "tiltott karakterek:" @@ -3764,7 +4139,7 @@ msgid "illegal suffix:" msgstr "tiltott utótag:" msgid "Name is unavailable." -msgstr "Name is unavailable." +msgstr "A név nem elérhető." msgid "Overwrite a system profile is not allowed" msgstr "A rendszerprofil felülírása nem engedélyezett" @@ -3781,23 +4156,23 @@ msgid "Please note that saving action will replace this preset" msgstr "Figyelem, a mentési művelet lecseréli ezt a beállítást" msgid "The name is not allowed to be empty." -msgstr "The name field is not allowed to be empty." +msgstr "A név mező nem lehet üres." msgid "The name is not allowed to start with space character." -msgstr "The name is not allowed to start with a space." +msgstr "A név nem kezdődhet szóközzel." msgid "The name is not allowed to end with space character." -msgstr "The name is not allowed to end with a space." +msgstr "A név nem végződhet szóközzel." msgid "The name cannot be the same as a preset alias name." -msgstr "The name cannot be the same as a preset alias name." +msgstr "A név nem lehet azonos egy beállítás alias névvel." msgid "Save preset" msgstr "Beállítás mentése" msgctxt "PresetName" msgid "Copy" -msgstr "Másolás" +msgstr "Másolat" #, boost-format msgid "Printer \"%1%\" is selected with preset \"%2%\"" @@ -3809,11 +4184,11 @@ msgstr "Kérjük, válassz egy műveletet a(z) \"%1%\" beállítással a mentés #, boost-format msgid "For \"%1%\", change \"%2%\" to \"%3%\" " -msgstr "For \"%1%\", change \"%2%\" to \"%3%\" " +msgstr "Ehhez: \"%1%\", változtasd meg \"%2%\"-t erre: \"%3%\" " #, boost-format msgid "For \"%1%\", add \"%2%\" as a new preset" -msgstr "For \"%1%\", add \"%2%\" as a new preset" +msgstr "Ehhez: \"%1%\", add hozzá \"%2%\"-t új beállításként" #, boost-format msgid "Simply switch to \"%1%\"" @@ -3832,13 +4207,13 @@ msgid "Other Device" msgstr "Egyéb eszköz" msgid "Input access code" -msgstr "Input access code" +msgstr "Add meg a hozzáférési kódot" msgid "Can't find my devices?" msgstr "" msgid "Log out successful." -msgstr "Log out successful." +msgstr "Sikeres kijelentkezés." msgid "Busy" msgstr "Elfoglalt" @@ -3864,36 +4239,33 @@ msgstr "Asztalszintezés" msgid "Flow Calibration" msgstr "Anyagáramlás kalibráció" -msgid "Send" -msgstr "Küldés" - msgid "send completed" msgstr "küldés befejezve" msgid "No login account, only printers in LAN mode are displayed" -msgstr "No login account, only printers in LAN mode are displayed" +msgstr "" +"Nincs bejelentkezési fiók, csak a LAN módban lévő nyomtatók jelennek meg" msgid "Connecting to server" msgstr "Csatlakozás a szerverhez" msgid "Synchronizing device information" -msgstr "Synchronizing device information" +msgstr "Eszközinformációk szinkronizálása" msgid "Synchronizing device information time out" -msgstr "Synchronizing device information time out" +msgstr "Eszközinformációk szinkronizálása túllépte az időkorlátot" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "" -"Nem küldhetsz nyomtatási feladatot a nyomtatóra, amikor frissítés van " -"folyamatban" msgid "" "The printer is executing instructions. Please restart printing after it ends" msgstr "" -"The printer is executing instructions. Please restart printing after it ends" +"A nyomtató elfoglalt. Kérjük, indítsd újra a nyomtatást a nyomtatás " +"befejezése után" msgid "The printer is busy on other print job" -msgstr "The printer is busy with another print job." +msgstr "A nyomtató egy másik nyomtatási feladattal van elfoglalva." #, c-format, boost-format msgid "" @@ -3910,15 +4282,15 @@ msgid "" "Filaments to AMS slots mappings have been established. You can click a " "filament above to change its mapping AMS slot" msgstr "" -"Filaments to AMS slots mappings have been established. You can click a " -"filament above to change its mapping AMS slot" +"Megtörtént a filamentek AMS férőhelyekhez való kiosztása. Kattints egy fenti " +"filamentre az AMS kiosztás megváltoztatásához" msgid "" "Please click each filament above to specify its mapping AMS slot before " "sending the print job" msgstr "" -"Please click each filament above to specify its mapping AMS slot before " -"sending the print job" +"Kérjük, a nyomtatás megkezdése előtt kattints a fenti filamentekre, hogy " +"megadd a hozzájuk tartozó AMS férőhelyet" #, c-format, boost-format msgid "" @@ -3939,10 +4311,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3950,39 +4335,76 @@ msgid "" "currently selected physical printer. It is recommend to re-slice by " "selecting the same printer type.\n" msgstr "" +"The printer type used to generate G-code is not the same type as the " +"currently selected physical printer. It is recommend to re-slice by " +"selecting the same printer type.\n" +"\n" + +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" msgid "Preparing print job" msgstr "Nyomtatási feladat előkészítése" msgid "Modifying the device name" -msgstr "Modifying the device name" +msgstr "Eszköz nevének módosítása" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "" +"Nem küldhetsz nyomtatási feladatot a nyomtatóra, amikor frissítés van " +"folyamatban" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Cool Plate" + +msgid "Engineering Plate" +msgstr "Engineering Plate" + +msgid "High Temp Plate" +msgstr "High Temp Plate" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" -msgstr "Log in printer" +msgstr "Bejelentkezés a nyomtatóra" msgid "Would you like to log in this printer with current account?" -msgstr "Would you like to log in this printer with the current account?" +msgstr "Szeretnél bejelentkezni a nyomtatóra a jelenlegi fiókkal?" msgid "Log in successful." -msgstr "Log in successful." +msgstr "Sikeres bejelentkezés." msgid "Log out printer" -msgstr "Log out printer" +msgstr "Kijelentkezés a nyomtatóról" msgid "Would you like to log out the printer?" -msgstr "Would you like to log out the printer?" +msgstr "Szeretnél kijelentkezni a nyomtatóról?" msgid "Please log in first." msgstr "Kérjük, előbb jelentkezz be." msgid "There was a problem connecting to the printer. Please try again." -msgstr "There was a problem connecting to the printer. Please try again." +msgstr "Hiba történt a nyomtatóhoz való csatlakozáskor. Kérjük, próbáld újra." msgid "Failed to log out." msgstr "Sikertelen kijelentkezés." @@ -4002,13 +4424,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -4027,6 +4449,9 @@ msgstr "Varrat" msgid "Precision" msgstr "Pontosság" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Falak" @@ -4047,9 +4472,9 @@ msgid "" "expressed as a percentage of line width. 0 speed means no slowing down for " "the overhang degree range and wall speed is used" msgstr "" -"This is the speed for various overhang degrees. Overhang degrees are " -"expressed as a percentage of line width. 0 speed means no slowing down for " -"the overhang degree range and wall speed is used" +"Nyomtatási sebesség a különböző mértékű túlnyúlásoknál. A túlnyúlás mértéke " +"a vonalszélesség százalékában van kifejezve. A 0 sebesség azt jelenti, hogy " +"nem történik lassítás, és a fal nyomtatási sebessége kerül alkalmazásra." msgid "Travel speed" msgstr "Mozgás sebessége" @@ -4057,15 +4482,15 @@ msgstr "Mozgás sebessége" msgid "Acceleration" msgstr "Gyorsulás" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Filament a támaszhoz" msgid "Prime tower" msgstr "Törlő torony" -msgid "Flush options" -msgstr "Öblítési lehetőségek" - msgid "Special mode" msgstr "Speciális mód" @@ -4123,7 +4548,7 @@ msgid "Nozzle" msgstr "Fúvóka" msgid "Nozzle temperature when printing" -msgstr "Nozzle temperature when printing" +msgstr "Fúvóka hőmérséklete nyomtatáskor" msgid "Cool plate" msgstr "Cool plate" @@ -4145,9 +4570,6 @@ msgstr "" "Asztalhőmérséklet a mérnöki tálca használatával. A 0 érték azt jelenti, hogy " "a filament nem támogatja az Engineering Plate-re történő nyomtatást" -msgid "High Temp Plate" -msgstr "High Temp Plate" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4156,9 +4578,6 @@ msgstr "" "jelenti, hogy a filament nem támogatja a High Temp Plate-re történő " "nyomtatást" -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4247,7 +4666,7 @@ msgid "Motion ability" msgstr "Géplimitek" msgid "Normal" -msgstr "Normal" +msgstr "Normál" msgid "Speed limitation" msgstr "Sebesség limitek" @@ -4259,13 +4678,13 @@ msgid "Jerk limitation" msgstr "Jerk limitek" msgid "Layer height limits" -msgstr "Layer height limits" +msgstr "Rétegmagasság limitek" msgid "Retraction when switching material" msgstr "Visszahúzás anyagváltáskor" msgid "Detached" -msgstr "Detached" +msgstr "Különálló" msgid "Following preset will be deleted too." msgid_plural "Following presets will be deleted too." @@ -4274,7 +4693,7 @@ msgstr[1] "A következő beállítások szintén törlődni fognak." #, boost-format msgid "Are you sure to %1% the selected preset?" -msgstr "Are you sure you want to %1% the selected preset?" +msgstr "Biztos, hogy %1% a kiválasztott beállítást?" #. TRN Remove/Delete #, boost-format @@ -4288,7 +4707,8 @@ msgid "Set" msgstr "Beállít" msgid "Click to reset current value and attach to the global value." -msgstr "Click to reset current value and attach to the global value." +msgstr "" +"Kattints ide az érték visszaállításához és a globális érték használatához." msgid "Click to drop current modify and reset to saved value." msgstr "" @@ -4299,10 +4719,10 @@ msgid "Process Settings" msgstr "Folyamatbeállítások" msgid "Undef" -msgstr "Undefined" +msgstr "Nincs meghatározva" msgid "Unsaved Changes" -msgstr "unsaved changes" +msgstr "mentetlen változások" msgid "Discard or Keep changes" msgstr "Változások elvetése vagy megtartása" @@ -4314,7 +4734,7 @@ msgid "New Value" msgstr "Új érték" msgid "Transfer" -msgstr "Transfer" +msgstr "Átvitel" msgid "Don't save" msgstr "Ne mentsd" @@ -4335,10 +4755,10 @@ msgid "Save the selected options." msgstr "A kiválasztott beállítások mentése." msgid "Keep the selected options." -msgstr "Keep the selected options." +msgstr "Kiválasztott opciók megtartása." msgid "Transfer the selected options to the newly selected preset." -msgstr "Transfer the selected options to the newly selected preset." +msgstr "Kiválasztott opciók átmásolása az újonnan kiválasztott beállításba." #, boost-format msgid "" @@ -4353,7 +4773,7 @@ msgid "" "Transfer the selected options to the newly selected preset \n" "\"%1%\"." msgstr "" -"Transfer the selected options to the newly selected preset \n" +"Kiválasztott opciók átmásolása az újonnan kiválasztott beállításba\n" "\"%1%\"." #, boost-format @@ -4377,13 +4797,18 @@ msgstr "" "A(z) \"%1%\" beállítás nem kompatibilis az új folyamat profillal és a " "következő elmentetlen változásokat tartalmazza:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"Megváltoztattál néhány beállítást.\n" -"Szeretnéd megtartani ezeket a megváltozott beállításokat az előbeállítás " -"váltás után?" msgid "Extruders count" msgstr "Extruderek száma" @@ -4394,6 +4819,11 @@ msgstr "Általános" msgid "Capabilities" msgstr "Képességek" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4408,7 +4838,7 @@ msgstr "Lefedés" #, boost-format msgid "The name \"%1%\" already exists." -msgstr "The name \"%1%\" already exists." +msgstr "A(z) \"%1%\" név már létezik." msgid "Basic Info" msgstr "Alapinformáció" @@ -4429,7 +4859,7 @@ msgid "Author" msgstr "" msgid "Model Name" -msgstr "Model Name" +msgstr "Modellnév" #, c-format, boost-format msgid "%s Update" @@ -4451,16 +4881,15 @@ msgid "Configuration incompatible" msgstr "Nem kompatibilis konfiguráció" msgid "the configuration package is incompatible with current application." -msgstr "" -"the configuration package is incompatible with the current application." +msgstr "a konfigurációs csomag nem kompatibilis a jelenlegi alkalmazással." #, c-format, boost-format msgid "" "The configuration package is incompatible with current application.\n" "%s will update the configuration package, Otherwise it won't be able to start" msgstr "" -"The configuration package is incompatible with the current application.\n" -"%s will update the configuration package to allow the application to start." +"A konfigurációs csomag nem kompatibilis a jelenlegi alkalmazással.\n" +"%s frissíti a konfigurációs csomagot, hogy az alkalmazás elindulhasson." #, c-format, boost-format msgid "Exit %s" @@ -4468,59 +4897,69 @@ msgstr "Kilépés %s" msgid "the Configuration package is incompatible with current APP." msgstr "" -"The configuration package is incompatible with the current version of Bambu " -"Studio." +"A konfigurációs csomag nem kompatibilis a Bambu Studio jelenlegi verziójával." msgid "Configuration updates" msgstr "Konfiguráció frissítések" msgid "No updates available." -msgstr "No updates available." +msgstr "Nincs elérhető frissítés." msgid "The configuration is up to date." -msgstr "The configuration is up to date." +msgstr "A konfiguráció naprakész." + +msgid "Flushing volumes for filament change" +msgstr "Filament csere tiszítási mennyisége" msgid "Auto-Calc" msgstr "Automatikus számítás" -msgid "Flushing volumes for filament change" -msgstr "Filament csere öblítési mennyisége" - msgid "Flushing volume (mm³) for each filament pair." -msgstr "Egyes filament párok öblítési mennyisége (mm³)." +msgstr "Egyes filamentpárok tiszítási mennyisége (mm³)." -msgid "Flush multiplier" -msgstr "Öblítési szorzó" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "unloaded" msgid "loaded" -msgstr "loaded" +msgstr "betöltve" msgid "Filament #" msgstr "Filament #" msgid "From" -msgstr "From" +msgstr "Ettől:" msgid "To" -msgstr "To" +msgstr "Eddig:" msgid "Login" msgstr "Bejelentkezés" msgid "The configuration package is changed in previous Config Guide" -msgstr "The configuration package is changed in previous Config Guide" +msgstr "A konfigurációs csomag az előző konfigurációs útmutatóban módosult" msgid "Configuration package changed" msgstr "Konfigurációs csomag megváltozott" msgid "Toolbar" -msgstr "Toolbar" +msgstr "Eszköztár" msgid "Objects list" -msgstr "Objects list" +msgstr "Objektumok listája" msgid "Import geometry data from STL/STEP/3MF/OBJ/AMF files." msgstr "Geometriai adatok importálása STL/STEP/3MF/OBJ/AMF fájlokból." @@ -4568,7 +5007,7 @@ msgid "⌘+Any arrow" msgstr "⌘+Bármilyen nyíl gomb" msgid "Movement in camera space" -msgstr "Movement in camera space" +msgstr "Mozgás a kameratérben" msgid "⌥+Left mouse button" msgstr "" @@ -4601,31 +5040,31 @@ msgid "Arrow Up" msgstr "Felfelé nyíl" msgid "Move selection 10 mm in positive Y direction" -msgstr "Move selection 10mm in positive Y direction" +msgstr "Kijelölés mozgatása 10 mm-rel pozitív Y irányban" msgid "Arrow Down" msgstr "Lefelé nyíl" msgid "Move selection 10 mm in negative Y direction" -msgstr "Move selection 10mm in negative Y direction" +msgstr "Kijelölés mozgatása 10 mm-rel negatív Y irányban" msgid "Arrow Left" msgstr "Balra nyíl" msgid "Move selection 10 mm in negative X direction" -msgstr "Move selection 10mm in negative X direction" +msgstr "Kijelölés mozgatása 10 mm-rel negatív X irányban" msgid "Arrow Right" msgstr "Jobbra nyíl" msgid "Move selection 10 mm in positive X direction" -msgstr "Move selection 10mm in positive X direction" +msgstr "Kijelölés mozgatása 10 mm-rel pozitív X irányban" msgid "Shift+Any arrow" msgstr "Shift+Bármelyik nyílgomb" msgid "Movement step set to 1 mm" -msgstr "Movement step set to 1mm" +msgstr "Mozgatás lépéstávolsága 1mm-re állítva" msgid "keyboard 1-9: set filament for object/part" msgstr "filament hozzárendelése az objektumhoz/tárgyhoz" @@ -4685,13 +5124,13 @@ msgid "⌘+Mouse wheel" msgstr "⌘+Egérgörgő" msgid "Support/Color Painting: adjust pen radius" -msgstr "Support/Color Painting: adjust pen radius" +msgstr "Támasz/Színfestés: toll méretének beállítása" msgid "⌥+Mouse wheel" msgstr "" msgid "Support/Color Painting: adjust section position" -msgstr "Support/Color Painting: adjust section position" +msgstr "Támasz/Színfestés: metszet pozíciójának beállítása" msgid "Ctrl+Mouse wheel" msgstr "Ctrl+Egérgörgő" @@ -4709,7 +5148,7 @@ msgid "Delete objects, parts, modifiers " msgstr "Objektumok, tárgyak, módosítók törlése " msgid "Space" -msgstr "Space" +msgstr "Szóköz" msgid "Select the object/part and press space to change the name" msgstr "" @@ -4717,7 +5156,7 @@ msgstr "" "megváltoztatásához" msgid "Mouse click" -msgstr "Mouse click" +msgstr "Egérkattintás" msgid "Select the object/part and mouse click to change the name" msgstr "" @@ -4725,25 +5164,25 @@ msgstr "" "megváltoztatásához" msgid "Objects List" -msgstr "Objects List" +msgstr "Tárgyak listája" msgid "Vertical slider - Move active thumb Up" -msgstr "Vertical slider - Move active thumb Up" +msgstr "Függőleges csúszka - Az aktív csúszka felfelé mozgatása" msgid "Vertical slider - Move active thumb Down" -msgstr "Vertical slider - Move active thumb Down" +msgstr "Függőleges csúszka - Az aktív csúszka lefelé mozgatása" msgid "Horizontal slider - Move active thumb Left" -msgstr "Horizontal slider - Move active thumb Left" +msgstr "Vízszintes csúszka - Az aktív csúszka balra mozgatása" msgid "Horizontal slider - Move active thumb Right" -msgstr "Horizontal slider - Move active thumb Right" +msgstr "Vízszintes csúszka - Az aktív csúszka jobbra mozgatása" msgid "On/Off one layer mode of the vertical slider" -msgstr "On/Off one layer mode of the vertical slider" +msgstr "Függőleges csúszka egyréteges módjának ki/bekapcsolása" msgid "Move slider 5x faster" -msgstr "Move slider 5x faster" +msgstr "Csúszka 5x gyorsabb mozgatása" msgid "Shift+Mouse wheel" msgstr "Shift+Egérgörgő" @@ -4770,7 +5209,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4782,13 +5221,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4808,6 +5247,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "Az objektumok mentése a 3mf-be sikertelen volt." @@ -4830,7 +5272,7 @@ msgid "Repair failed." msgstr "Sikertelen javítás." msgid "Loading repaired objects" -msgstr "Loading repaired objects" +msgstr "Javított objektumok betöltése" msgid "Exporting 3mf file failed" msgstr "3MF fájl exportálása sikertelen" @@ -4845,7 +5287,7 @@ msgid "Repaired 3mf file contains more than one object" msgstr "A megjavított 3mf fájl egynél több objektumot tartalmaz" msgid "Repaired 3mf file does not contain any volume" -msgstr "The repaired 3mf file does not contain any volume." +msgstr "A javított 3mf fájl nem tartalmaz térfogatot." msgid "Repaired 3mf file contains more than one volume" msgstr "The repaired 3mf file contains more than one volume." @@ -4865,38 +5307,41 @@ msgid "Copying directory %1% to %2% failed: %3%" msgstr "%1% mappa másolása sikertelen a következő helyre: %2% Hiba: %3%" msgid "Need to check the unsaved changes before configuration updates." -msgstr "Please check any unsaved changes before updating the configuration." +msgstr "" +"Kérjük, ellenőrizd a nem mentett módosításokat a konfiguráció frissítése " +"előtt." msgid "Configuration package updated to " msgstr "Konfigurációs csomag frissítve a következőre " msgid "Open G-code file:" -msgstr "Open G-code file:" +msgstr "G-kód fájl megnyitása:" msgid "" "One object has empty initial layer and can't be printed. Please Cut the " "bottom or enable supports." msgstr "" -"One object has empty initial layer and can't be printed. Please Cut the " -"bottom or enable supports." +"Az egyik objektum üres kezdőréteggel rendelkezik, ezért nem nyomtatható. " +"Kérjük, vágd le az alját, vagy engedélyezd a támaszokat." #, boost-format msgid "Object can't be printed for empty layer between %1% and %2%." -msgstr "The object has empty layers between %1% and %2% and can’t be printed." +msgstr "" +"Az objektumnak üres rétegei vannak %1% és %2% között, ezért nem nyomtatható." #, boost-format msgid "Object: %1%" -msgstr "Object: %1%" +msgstr "Objektum: %1%" msgid "" "Maybe parts of the object at these height are too thin, or the object has " "faulty mesh" msgstr "" -"Parts of the object at these heights may be too thin or the object may have " -"a faulty mesh." +"Az objektum ezen magasságban lévő részei túl vékonyak lehetnek, vagy az " +"objektum hibás hálóval rendelkezik." msgid "No object can be printed. Maybe too small" -msgstr "No object can be printed. It may be too small." +msgstr "Objektum nem nyomtatható ki. Lehet, hogy túl kicsi." msgid "" "Failed to generate gcode for invalid custom G-code.\n" @@ -4945,44 +5390,45 @@ msgid "Support interface" msgstr "Támasz érintkező felület" msgid "Support transition" -msgstr "Support transition" +msgstr "Támasz átmenet" msgid "Multiple" -msgstr "Multiple" +msgstr "Többszörös" #, boost-format msgid "Failed to calculate line width of %1%. Can not get value of \"%2%\" " -msgstr "Failed to calculate line width of %1%. Cannot get value of “%2%” " +msgstr "" +"Nem sikerült kiszámítani %1% vonalszélességét. “%2%” értéke nem érhető el " msgid "undefined error" -msgstr "undefined error" +msgstr "meghatározatlan hiba" msgid "too many files" -msgstr "too many files" +msgstr "túl sok fájl" msgid "file too large" msgstr "fájl túl nagy" msgid "unsupported method" -msgstr "unsupported method" +msgstr "nem támogatott módszer" msgid "unsupported encryption" -msgstr "unsupported encryption" +msgstr "nem támogatott titkosítás" msgid "unsupported feature" -msgstr "unsupported feature" +msgstr "nem támogatott funkció" msgid "failed finding central directory" msgstr "nem sikerült megtalálni a központi könyvtárat" msgid "not a ZIP archive" -msgstr "not a ZIP archive" +msgstr "nem ZIP archívum" msgid "invalid header or corrupted" -msgstr "invalid header or corrupted" +msgstr "érvénytelen fejléc vagy sérült" msgid "unsupported multidisk" -msgstr "Saving to RAID is not supported." +msgstr "A RAID-re mentés nem támogatott." msgid "decompression failed" msgstr "sikertelen kicsomagolás" @@ -4991,13 +5437,13 @@ msgid "compression failed" msgstr "tömörítés sikertelen" msgid "unexpected decompressed size" -msgstr "unexpected decompressed size" +msgstr "váratlan kitömörítési méret" msgid "CRC check failed" msgstr "CRC-ellenőrzés sikertelen" msgid "unsupported central directory size" -msgstr "unsupported central directory size" +msgstr "nem támogatott központi mappa méret" msgid "allocation failed" msgstr "sikertelen allokáció" @@ -5024,16 +5470,16 @@ msgid "file stat failed" msgstr "fájl stat sikertelen" msgid "invalid parameter" -msgstr "invalid parameter" +msgstr "érvénytelen paraméter" msgid "invalid filename" -msgstr "invalid filename" +msgstr "érvénytelen fájlnév" msgid "buffer too small" msgstr "túl kicsi puffer" msgid "internal error" -msgstr "internal error" +msgstr "belső hiba" msgid "file not found" msgstr "fájl nem található" @@ -5042,22 +5488,16 @@ msgid "archive too large" msgstr "archívum túl nagy" msgid "validation failed" -msgstr "validation failed" +msgstr "sikertelen érvényesítés" msgid "write callback failed" -msgstr "write callback failed" +msgstr "írás callback sikertelen" #, boost-format msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "" @@ -5069,7 +5509,7 @@ msgid "%1% is too tall, and collisions will be caused." msgstr "%1% túl magas, a nyomtatás során előfordulhatnak ütközések." msgid " is too close to others, there may be collisions when printing.\n" -msgstr "" +msgstr " is too close to others, there may be collisions when printing.\n" msgid "" " is too close to exclusion area, there may be collisions when printing.\n" @@ -5097,7 +5537,7 @@ msgstr "" "megsérülhet nyomtatás közben" msgid "No extrusions under current settings." -msgstr "No extrusions under current settings." +msgstr "A jelenlegi beállítások mellett nincsenek extrudálások." msgid "" "Smooth mode of timelapse is not supported when \"by object\" sequence is " @@ -5115,8 +5555,8 @@ msgid "" "The spiral vase mode does not work when an object contains more than one " "materials." msgstr "" -"Spiral (vase) mode does not work when an object contains more than one " -"material." +"A spirál (váza) mód nem működik, ha egy objektum egynél több anyagot " +"tartalmaz." msgid "The prime tower is not supported in \"By object\" print." msgstr "A prime tower is not supported in “By object” print." @@ -5149,11 +5589,16 @@ msgstr "" "A prime tower requires that all objects are sliced with the same layer " "height." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" -msgstr "Line width too small" +msgstr "Túl kicsi a vonalszélesség" msgid "Too large line width" -msgstr "Line width too large" +msgstr "Túl nagy vonalszélesség" msgid "" "The prime tower requires that support has the same layer height with object." @@ -5163,14 +5608,15 @@ msgstr "" msgid "" "Support enforcers are used but support is not enabled. Please enable support." msgstr "" -"Support enforcers are used but support is not enabled. Please enable support." +"Támasz kényszerítőket használtál, de a támaszok nincsenek engedélyezve. " +"Kérjük, engedélyezd a támaszokat." msgid "Layer height cannot exceed nozzle diameter" -msgstr "Layer height cannot exceed nozzle diameter." +msgstr "A rétegmagasság nem lehet nagyobb a fúvóka átmérőjénél." #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "%d. tálca: %s nem használható %s filamenttel.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Szoknya & perem generálása" @@ -5196,6 +5642,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Elefántláb kompenzáció" @@ -5218,8 +5670,8 @@ msgstr "Nyomtatási magasság" msgid "Maximum printable height which is limited by mechanism of printer" msgstr "" -"This is the maximum printable height which is limited by the height of the " -"build area." +"Ez a maximális nyomtatható magasság, amelyet a nyomtatótér magassága " +"korlátoz." msgid "Printer preset names" msgstr "Nyomtató beállítások neve" @@ -5341,7 +5793,7 @@ msgid "Initial layer" msgstr "Kezdőréteg" msgid "Initial layer bed temperature" -msgstr "First layer bed temperature" +msgstr "Első réteg asztalhőmérséklete" msgid "" "Bed temperature of the initial layer. Value 0 means the filament does not " @@ -5372,14 +5824,8 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Nyomtató által támogatott asztaltípusok" -msgid "Cool Plate" -msgstr "Cool Plate" - -msgid "Engineering Plate" -msgstr "Engineering Plate" - msgid "This G-code is inserted at every layer change before lifting z" -msgstr "This G-code is inserted at every layer change before lifting z." +msgstr "Ez a G-kód minden rétegváltáshoz bekerül a Z tengely emelése előtt." msgid "Bottom shell layers" msgstr "Alsó héj rétegek" @@ -5389,9 +5835,9 @@ msgid "" "surface layer. When the thickness calculated by this value is thinner than " "bottom shell thickness, the bottom shell layers will be increased" msgstr "" -"This is the number of solid layers of bottom shell, including the bottom " -"surface layer. When the thickness calculated by this value is thinner than " -"bottom shell thickness, the bottom shell layers will be increased" +"Ez az alsó héj szilárd rétegeinek száma, beleértve az alsó felületi réteget " +"is. Ha az ezzel az értékkel számított vastagság kisebb, mint az alsó héj " +"vastagsága, akkor az alsó héj rétegei növekedni fognak" msgid "Bottom shell thickness" msgstr "Alsó héj vastagság" @@ -5403,11 +5849,11 @@ msgid "" "is disabled and thickness of bottom shell is absolutely determained by " "bottom shell layers" msgstr "" -"The number of bottom solid layers is increased when slicing if the thickness " -"calculated by bottom shell layers is thinner than this value. This can avoid " -"having too thin a shell when layer height is small. 0 means that this " -"setting is disabled and the thickness of the bottom shell is determined " -"simply by the number of bottom shell layers." +"Az alsó szilárd rétegek száma szeleteléskor megnő, ha az alsó héjrétegek " +"vastagsága kisebb ennél az értéknél. Ezzel elkerülhető, hogy túl vékony " +"legyen a héj, ha a rétegmagasság kicsi. A 0 azt jelenti, hogy ez a beállítás " +"ki van kapcsolva, és az alsó héj vastagságát egyszerűen az alsó héjrétegek " +"száma határozza meg." msgid "Force cooling for overhang and bridge" msgstr "Hűtés kényszerítése túlnyúlásoknál és áthidalásoknál" @@ -5427,21 +5873,30 @@ msgid "" "wall which has large overhang degree. Forcing cooling for overhang and " "bridge can get better quality for these part" msgstr "" -"Force part cooling fan to be this speed when printing bridges or overhang " -"walls which have a large overhang degree. Forcing cooling for overhangs and " -"bridges can achieve better quality for these parts." +"A nagy túlnyúlású áthidalások vagy túlnyúló falak nyomtatásakor a tárgyhűtő " +"ventilátor kényszerítve lesz, hogy ezt a fordulatszámot használja. A " +"túlnyúlások és áthidalások hűtésének kikényszerítésével jobb minőség érhető " +"el ezeken a részeken." msgid "Cooling overhang threshold" msgstr "Túlnyúlás hűtésének küszöbértéke" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"This forces the cooling fan to use a specific speed when overhang degrees of " -"parts exceed the set value. It is expressed as percentage which indicates " -"how much line is acceptable without support from lower layers." msgid "Bridge flow" msgstr "Áthidalás áramlási sebessége" @@ -5460,8 +5915,8 @@ msgid "" "Use only one wall on flat top surface, to give more space to the top infill " "pattern" msgstr "" -"Use only one wall on flat top surfaces, to give more space to the top infill " -"pattern" +"Csak egy falat használ a sík felső felületeken, hogy több hely maradjon a " +"felső kitöltési mintának" msgid "Slow down for overhang" msgstr "Lassítás túlnyúlásoknál" @@ -5491,9 +5946,9 @@ msgid "" "holes or both. Auto means both the brim position and brim width is analysed " "and calculated automatically" msgstr "" -"This controls brim position including outer side of models, inner side of " -"holes, or both. Auto means both the brim position and brim width are " -"analyzed and calculated automatically." +"Ez szabályozza a perem típusát a modellek külső oldalán, a furatok belső " +"oldalán, vagy mindkét helyen. Az Auto beállítás azt jelenti, hogy mind a " +"perem pozícióját, mind a perem szélességét a szeletelő szabályozza." msgid "Brim-object gap" msgstr "Perem-tárgy közötti rés" @@ -5508,6 +5963,9 @@ msgstr "" msgid "Compatible machine" msgstr "Kompatibilis gép" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Kompatibilis gépállapot" @@ -5551,8 +6009,8 @@ msgid "" "The default acceleration of both normal printing and travel except initial " "layer" msgstr "" -"This is the default acceleration for both normal printing and travel after " -"the first layer." +"Ez az alapértelmezett gyorsulás mind a normál nyomtatáshoz, mind az első " +"réteg utáni mozgáshoz." msgid "mm/s²" msgstr "mm/s²" @@ -5595,9 +6053,6 @@ msgstr "" msgid "Thick bridges" msgstr "Vastag áthidalások" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5616,9 +6071,10 @@ msgid "" "bridges to be supported, and set it to a very large value if you don't want " "any bridges to be supported." msgstr "" -"This is the maximum length of bridges that don't need support. Set it to 0 " -"if you want all bridges to be supported, and set it to a very large value if " -"you don't want any bridges to be supported." +"Ez a maximális hossza azoknak az áthidalásoknak, amelyeknek nincs szükségük " +"alátámasztásra. Állítsd 0-ra, ha azt szeretnéd, hogy minden áthidalás alá " +"legyen támasztva, vagy állítsd egy nagyon nagy értékre, ha azt szeretnéd, " +"hogy egyetlen áthidalás se legyen alátámasztva." msgid "End G-code" msgstr "Befejező G-kód" @@ -5629,11 +6085,30 @@ msgstr "Befejező G-kód az egész nyomtatás befejezésekor" msgid "End G-code when finish the printing of this filament" msgstr "Befejező G-kód a filament nyomtatásának befejezésekor" +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Felső felület mintázata" msgid "Line pattern of top surface infill" -msgstr "This is the line pattern for top surface infill." +msgstr "Ez a felső felület kitöltésének mintája." msgid "Concentric" msgstr "Koncentrikus" @@ -5653,16 +6128,20 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Alsó felület mintázata" msgid "Line pattern of bottom surface infill, not bridge infill" -msgstr "" -"This is the line pattern of bottom surface infill, not including bridge " -"infill." +msgstr "Ez az alsó felület kitöltésének mintája, kivéve az áthidalásokat." msgid "Line width of outer wall" -msgstr "Line width of outer wall" +msgstr "A külső fal vonalszélessége" msgid "" "Speed of outer wall which is outermost and visible. It's used to be slower " @@ -5690,7 +6169,7 @@ msgid "infill/outer/inner" msgstr "kitöltés/külső/belső" msgid "Height to rod" -msgstr "Height to rod" +msgstr "Magasság a rúdig" msgid "" "Distance of the nozzle tip to the lower rod. Used for collision avoidance in " @@ -5698,16 +6177,13 @@ msgid "" msgstr "" msgid "Height to lid" -msgstr "Height to lid" +msgstr "Magasság a fedélig" msgid "" "Distance of the nozzle tip to the lid. Used for collision avoidance in by-" "object printing." msgstr "" -msgid "Radius" -msgstr "Radius" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5725,7 +6201,7 @@ msgid "Extruder Color" msgstr "Extruder szín" msgid "Only used as a visual help on UI" -msgstr "Only used as a visual help on UI" +msgstr "Csak vizuális segédként használatos a felhasználói felületen" msgid "Extruder offset" msgstr "Extruder offszet" @@ -5740,11 +6216,11 @@ msgid "" "and 1.05. Maybe you can tune this value to get nice flat surface when there " "has slight overflow or underflow" msgstr "" -"The material may have volumetric change after switching between molten and " -"crystalline states. This setting changes all extrusion flow of this filament " -"in G-code proportionally. The recommended value range is between 0.95 and " -"1.05. You may be able to tune this value to get a nice flat surface if there " -"is slight overflow or underflow." +"Az anyag térfogata megváltozhat az olvadt és a kristályos állapot közötti " +"átmenet során. Ez a beállítás arányosan megváltoztatja az anyagáramlást a G-" +"kódban. Az ajánlott értéktartomány 0,95 és 1,05 között van. Ennek az " +"értéknek a változtatásával szép sík felületet kaphatsz, ha úgy tapasztalod, " +"hogy túl sok vagy kevés az anyagáramlás." msgid "Default line width if some line width is set to be zero" msgstr "" @@ -5778,26 +6254,37 @@ msgstr "" msgid "s" msgstr "mp" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Szín" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Max. volumetrikus sebesség" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Use this to set the maximum volume of filament that can be melted and " -"extruded per second. Printing speed is limited by maximum volumetric speed " -"if settings are unreasonably high. 0 means there is no limit." msgid "mm³/s" msgstr "mm³/s" msgid "Minimal purge on wipe tower" -msgstr "Minimal purge on wipe tower" +msgstr "Minimális tisztítás a törlőtoronyban" msgid "mm³" msgstr "mm³" @@ -5807,16 +6294,16 @@ msgstr "Filament betöltési idő" msgid "Time to load new filament when switch filament. For statistics only" msgstr "" -"Time to load new filament when switching filament, for statistical purposes " -"only." +"Az új filament betöltésének ideje filament váltáskor, csak statisztikai " +"célokra van használva." msgid "Filament unload time" msgstr "Filament kitöltési idő" msgid "Time to unload old filament when switch filament. For statistics only" msgstr "" -"Time to unload old filament when switching filament, for statistical " -"purposes only." +"A régi filament kitöltésének ideje filament váltáskor, csak statisztikai " +"célokra van használva." msgid "" "Filament diameter is used to calculate extrusion in gcode, so it's important " @@ -5838,7 +6325,7 @@ msgid "Type" msgstr "Típus" msgid "The material type of filament" -msgstr "Filament material type" +msgstr "Filament anyagának típusa" msgid "Soluble material" msgstr "Oldható anyag" @@ -5850,12 +6337,13 @@ msgstr "" "használják" msgid "Support material" -msgstr "Support material" +msgstr "Támaszanyag" msgid "" "Support material is commonly used to print support and support interface" msgstr "" -"Support material is commonly used to print support and support interfaces." +"A támaszanyag a támaszok és a támasz érintkező felületeinek nyomtatásához " +"van használva." msgid "Temperature of vitrificaiton" msgstr "Üvegesedési hőmérséklet" @@ -5864,8 +6352,8 @@ msgid "" "Material becomes soft at this temperature. Thus the heatbed cannot be hotter " "than this tempature" msgstr "" -"Material becomes soft at this temperature. Thus, the heat bed cannot be " -"hotter than this temperature." +"Az anyag ezen a hőmérsékleten meglágyul. Ezért a tárgyasztal hőmérséklete " +"nem lehet ennél magasabb." msgid "Price" msgstr "Költség" @@ -5874,7 +6362,7 @@ msgid "Filament price. For statistics only" msgstr "Filament költsége. Csak statisztikákhoz kerül felhasználásra" msgid "money/kg" -msgstr "money/kg" +msgstr "pénz/kg" msgid "(Undefined)" msgstr "(Undefined)" @@ -5895,14 +6383,14 @@ msgstr "Kitöltés sűrűsége" #, c-format msgid "Density of internal sparse infill, 100% means solid throughout" msgstr "" -"This is the density of internal sparse infill. 100% means that the object " -"will be solid throughout." +"Ez a belső ritkás kitöltés sűrűsége. A 100%% azt jelenti, hogy az objektum " +"végig tömör lesz." msgid "Sparse infill pattern" msgstr "Kitöltési mintázat" msgid "Line pattern for internal sparse infill" -msgstr "This is the line pattern for internal sparse infill." +msgstr "Ez a belső ritkás kitöltés mintája." msgid "Grid" msgstr "Rács" @@ -5925,6 +6413,12 @@ msgstr "Méhsejt" msgid "Adaptive Cubic" msgstr "Adaptív kocka" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5935,6 +6429,9 @@ msgstr "" "A felső felületi kitöltés gyorsulása. Alacsonyabb érték használata " "javíthatja a felső felület minőségét" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5943,7 +6440,7 @@ msgstr "" "tárgyasztalhoz való tapadást" msgid "Line width of initial layer" -msgstr "Line width of first layer" +msgstr "Az első réteg vonalszélessége" msgid "Initial layer height" msgstr "Kezdő rétegmagasság" @@ -5955,22 +6452,6 @@ msgstr "" "Kezdőréteg magassága. A vastagabb kezdőréteg javíthatja a tárgy asztalhoz " "való tapadását" -msgid "Adaptive layer height" -msgstr "Adaptív rétegmagasság" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Ha engedélyezed ezt az opciót, akkor az első réteg kivételével minden réteg " -"magassága automatikusan kiszámításra kerül a szeletelés során a " -"modellfelület lejtésének megfelelően.\n" -"Felhívjuk a figyelmed, hogy ez az opció csak akkor működik, ha az aktuális " -"tálcán nincs törlő torony generálva." - msgid "Speed of initial layer except the solid infill part" msgstr "A kezdőréteg nyomtatási sebessége a szilárd kitöltési rész kivételével" @@ -5981,10 +6462,10 @@ msgid "Speed of solid infill part of initial layer" msgstr "A kezdőréteg szilárd kitöltési részének sebessége" msgid "Initial layer nozzle temperature" -msgstr "First layer nozzle temperature" +msgstr "Az első réteg fúvóka hőmérséklete" msgid "Nozzle temperature to print initial layer when using this filament" -msgstr "Nozzle temperature for printing the first layer with this filament" +msgstr "A fúvóka hőmérséklete az első réteg nyomtatásakor ezzel a filamenttel" msgid "Full fan speed at layer" msgstr "Teljes ventilátor fordulatszám ennél a rétegnél" @@ -6009,8 +6490,8 @@ msgid "" "The width within which to jitter. It's adversed to be below outer wall line " "width" msgstr "" -"The width of jittering: it’s recommended to keep this lower than the outer " -"wall line width." +"A rezgés szélessége: ezt ajánlott kisebbre állítani, mint a külső fal " +"szélessége." msgid "Fuzzy skin point distance" msgstr "Fuzzy skin pontok távolsága" @@ -6019,8 +6500,7 @@ msgid "" "The average diatance between the random points introducded on each line " "segment" msgstr "" -"The average distance between the random points introduced on each line " -"segment" +"Az egyes vonalszakaszokon használt véletlen pontok közötti átlagos távolság" msgid "" "Speed of gap infill. Gap usually has irregular line width and should be " @@ -6044,7 +6524,8 @@ msgstr "Vonalszám hozzáadása" msgid "Enable this to add line number(Nx) at the beginning of each G-Code line" msgstr "" -"Enable this to add line number(Nx) at the beginning of each G-Code line." +"Ha engedélyezed ezt a beállítást, minden G-kód sor elejére sorszám (Nx) " +"kerül." msgid "Scan first layer" msgstr "Az első réteg szkennelése" @@ -6063,8 +6544,8 @@ msgid "" "The metallic material of nozzle. This determines the abrasive resistance of " "nozzle, and what kind of filament can be printed" msgstr "" -"The metallic material of the nozzle: This determines the abrasive resistance " -"of the nozzle and what kind of filament can be printed." +"A fúvóka anyaga: Ez határozza meg a fúvóka kopásállóságát és azt, hogy " +"milyen filamentekkel képes nyomtatni." msgid "Undefine" msgstr "" @@ -6078,6 +6559,17 @@ msgstr "Rozsdamentes acél" msgid "Brass" msgstr "Sárgaréz" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" "Engedélyezd ezt az opciót, ha a gép rendelkezik kiegészítő tárgyhűtő " @@ -6087,7 +6579,7 @@ msgid "G-code flavor" msgstr "G-kód változat" msgid "What kind of gcode the printer is compatible with" -msgstr "What kind of G-code the printer is compatible with." +msgstr "Milyen G-kóddal kompatibilis a nyomtató." msgid "Infill combination" msgstr "Kitöltés összevonása" @@ -6104,7 +6596,7 @@ msgid "Filament to print internal sparse infill." msgstr "Filament a belső ritkás kitöltésekhez." msgid "Line width of internal sparse infill" -msgstr "Line width of internal sparse infill" +msgstr "A belső ritkás kitöltés vonalszélessége" msgid "Infill/Wall overlap" msgstr "Kitöltés/fal átfedés" @@ -6113,9 +6605,9 @@ msgid "" "Infill area is enlarged slightly to overlap with wall for better bonding. " "The percentage value is relative to line width of sparse infill" msgstr "" -"This allows the infill area to be enlarged slightly to overlap with walls " -"for better bonding. The percentage value is relative to line width of sparse " -"infill." +"Ez lehetővé teszi, hogy a kitöltési terület kissé nagyobb legyen, nagyobb " +"átfedést biztosítva a falakkal a jobb kapcsolódás érdekében. A százalékos " +"érték a ritkás kitöltés vonalszélességéhez viszonyított érték." msgid "Speed of internal sparse infill" msgstr "A belső ritkás kitöltés sebessége" @@ -6127,8 +6619,8 @@ msgid "" "Ironing is using small flow to print on same height of surface again to make " "flat surface more smooth. This setting controls which layer being ironed" msgstr "" -"Ironing uses a small flow to print at the same height of a surface to make " -"flat surfaces smoother. This setting controls which layers are being ironed." +"A vasalás kis anyagáramlás használatával kisimítja a sík felületeket. Ez a " +"beállítás szabályozza, hogy mely rétegeknél történik meg a vasalás." msgid "No ironing" msgstr "Nincs vasalás" @@ -6149,34 +6641,35 @@ msgid "" "The amount of material to extrude during ironing. Relative to flow of normal " "layer height. Too high value results in overextrusion on the surface" msgstr "" -"This is the amount of material to be extruded during ironing. It is relative " -"to the flow of normal layer height. Too high a value will result in " -"overextrusion on the surface." +"A vasalás során extrudálandó anyag mennyisége a normál anyagáramláshoz " +"viszonyítva. A túl magas érték a felületen túlextrudálást eredményez." msgid "Ironing line spacing" msgstr "Vasalási vonalak közötti távolság" msgid "The distance between the lines of ironing" -msgstr "This is the distance between the lines used for ironing." +msgstr "A vasaláshoz használt vonalak közötti távolság." msgid "Ironing speed" -msgstr "Ironing speed" +msgstr "Vasalás sebessége" msgid "Print speed of ironing lines" msgstr "A vasalási vonalak nyomtatási sebessége" msgid "This gcode part is inserted at every layer change after lift z" -msgstr "This G-code is inserted at every layer change after the z lift." +msgstr "" +"Ez a G-kód minden rétegváltásnál beillesztésre kerül a Z tengely megemelése " +"után." msgid "Supports silent mode" -msgstr "Silent Mode" +msgstr "Csendes mód" msgid "" "Whether the machine supports silent mode in which machine use lower " "acceleration to print" msgstr "" -"Whether the machine supports silent mode in which machine uses lower " -"acceleration to print more quietly" +"Csendes üzemmód támogatása, amelyben a gép kisebb gyorsulást használ a " +"csendesebb nyomtatáshoz" msgid "" "This G-code will be used as a code for the pause print. User can insert " @@ -6250,46 +6743,46 @@ msgid "Maximum jerk E" msgstr "Maximális jerk E" msgid "Maximum jerk of the X axis" -msgstr "Maximum jerk of the X axis" +msgstr "Maximális jerk az X tengelyen" msgid "Maximum jerk of the Y axis" -msgstr "Maximum jerk of the Y axis" +msgstr "Maximális jerk az Y tengelyen" msgid "Maximum jerk of the Z axis" -msgstr "Maximum jerk of the Z axis" +msgstr "Maximális jerk a Z tengelyen" msgid "Maximum jerk of the E axis" -msgstr "Maximum jerk of the E axis" +msgstr "Maximális jerk az E tengelyen" msgid "Minimum speed for extruding" -msgstr "Minimum speed for extruding" +msgstr "Extrudálás minimális sebessége" msgid "Minimum speed for extruding (M205 S)" -msgstr "Minimum speed for extruding (M205 S)" +msgstr "Minimális sebesség az extrudáláshoz (M205 S)" msgid "Minimum travel speed" -msgstr "Minimum travel speed" +msgstr "Minimum mozgási sebesség" msgid "Minimum travel speed (M205 T)" -msgstr "Minimum travel speed (M205 T)" +msgstr "Minimum mozgási sebesség (M205 T)" msgid "Maximum acceleration for extruding" -msgstr "Maximum acceleration for extruding" +msgstr "Maximális gyorsulás extrudáláshoz" msgid "Maximum acceleration for extruding (M204 P)" -msgstr "Maximum acceleration for extruding (M204 P)" +msgstr "Maximális gyorsulás extrudáláshoz (M204 P)" msgid "Maximum acceleration for retracting" -msgstr "Maximum acceleration for retracting" +msgstr "Maximális gyorsulás a visszahúzáshoz" msgid "Maximum acceleration for retracting (M204 R)" -msgstr "Maximum acceleration for retracting (M204 R)" +msgstr "Maximális gyorsulás a visszahúzáshoz (M204 R)" msgid "Maximum acceleration for travel" -msgstr "Maximum acceleration for travel" +msgstr "Maximális gyorsulás a mozgáshoz" msgid "Maximum acceleration for travel (M204 T)" -msgstr "Maximum acceleration for travel (M204 T)" +msgstr "Maximális gyorsulás a mozgáshoz (M204 T)" msgid "Fan speed" msgstr "Ventilátor fordulatszám" @@ -6308,11 +6801,12 @@ msgid "" "The largest printable layer height for extruder. Used tp limits the maximum " "layer hight when enable adaptive layer height" msgstr "" -"The highest printable layer height for the extruder: this is used to limit " -"the maximum layer height when adaptive layer height is enabled." +"Az extruder által nyomtatható legnagyobb rétegmagasság: ez a maximális " +"rétegmagasság korlátozására szolgál, ha az adaptív rétegmagasság " +"engedélyezve van." msgid "Minimum speed for part cooling fan" -msgstr "Minimum speed for part cooling fan" +msgstr "Tárgyhűtő ventilátor minimum fordulatszáma" msgid "" "Speed of auxiliary part cooling fan. Auxiliary fan will run at this speed " @@ -6330,17 +6824,18 @@ msgid "" "The lowest printable layer height for extruder. Used tp limits the minimum " "layer hight when enable adaptive layer height" msgstr "" -"The lowest printable layer height for the extruder. This is used to limit " -"the minimum layer height when adaptive layer height is enabled." +"Az extruder által nyomtatható legkisebb rétegmagasság: ez a minimum " +"rétegmagasság korlátozására szolgál, ha az adaptív rétegmagasság " +"engedélyezve van." msgid "Min print speed" -msgstr "Min print speed" +msgstr "Min. nyomtatási sebesség" msgid "The minimum printing speed when slow down for cooling" -msgstr "The minimum printing speed when slowing down for cooling." +msgstr "A minimum nyomtatási sebesség hűtés miatti lassításkor." msgid "Nozzle diameter" -msgstr "Nozzle diameter" +msgstr "Fúvóka átmérője" msgid "Diameter of nozzle" msgstr "Fúvóka átmérője" @@ -6354,10 +6849,10 @@ msgid "" msgstr "" msgid "Nozzle volume" -msgstr "Nozzle volume" +msgstr "Fúvóka térfogata" msgid "Volume of nozzle between the cutter and the end of nozzle" -msgstr "Volume of nozzle between the filament cutter and the end of the nozzle" +msgstr "A fúvóka térfogata a filamentvágó és a fúvóka vége között" msgid "Reduce infill retraction" msgstr "Csökkentett visszahúzás kitöltésnél" @@ -6380,7 +6875,7 @@ msgid "Filename format" msgstr "Fájlnév formátum" msgid "User can self-define the project file name when export" -msgstr "Users can decide project file names when exporting." +msgstr "A felhasználó dönthet a projektfájlok nevéről exportáláskor." msgid "Detect overhang wall" msgstr "Túlnyúló fal felismerése" @@ -6395,13 +6890,13 @@ msgstr "" "beállított sebességet használja." msgid "Line width of inner wall" -msgstr "Line width of inner walls" +msgstr "A belső falak vonalszélessége" msgid "Speed of inner wall" msgstr "A belső fal nyomtatási sebessége" msgid "Number of walls of every layer" -msgstr "This is the number of walls per layer." +msgstr "Ez a falak száma rétegenként." msgid "Raft contact Z distance" msgstr "Tutaj érintkezés Z távolság" @@ -6418,7 +6913,7 @@ msgid "Expand all raft layers in XY plane" msgstr "Összes tutaj réteg kiterjesztése az XY síkban" msgid "Initial layer density" -msgstr "First layer density" +msgstr "Első réteg sűrűsége" msgid "Density of the first raft or support layer" msgstr "Az első tutaj vagy támasz réteg sűrűsége" @@ -6436,11 +6931,8 @@ msgid "" "Object will be raised by this number of support layers. Use this function to " "avoid wrapping when print ABS" msgstr "" -"Object will be raised by this number of support layers. Use this function to " -"avoid warping when printing ABS." - -msgid "Resolution" -msgstr "Felbontás" +"A tárgy ennyi támaszréteggel kerül megemelésre. Ezzel a funkcióval " +"elkerülheted a vetemedést ABS nyomtatásakor." msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " @@ -6458,8 +6950,8 @@ msgid "" "Only trigger retraction when the travel distance is longer than this " "threshold" msgstr "" -"Only trigger retraction when the travel distance is longer than this " -"threshold." +"Csak akkor indít visszahúzást, ha a mozgási távolság nagyobb, mint ez az " +"érték." msgid "Retract amount before wipe" msgstr "Visszahúzott mennyiség törlés előtt" @@ -6467,8 +6959,8 @@ msgstr "Visszahúzott mennyiség törlés előtt" msgid "" "The length of fast retraction before wipe, relative to retraction length" msgstr "" -"This is the length of fast retraction before a wipe, relative to retraction " -"length." +"Ez a törlés előtti gyors visszahúzás hossza a visszahúzási hosszhoz " +"viszonyítva." msgid "Retract when change layer" msgstr "Visszahúzás rétegváltáskor" @@ -6498,10 +6990,10 @@ msgid "" "clearance between nozzle and the print. It prevents nozzle from hitting the " "print when travel move. Using spiral line to lift z can prevent stringing" msgstr "" -"Whenever there is a retraction, the nozzle is lifted a little to create " -"clearance between the nozzle and the print. This prevents the nozzle from " -"hitting the print when traveling more. Using spiral lines to lift z can " -"prevent stringing." +"Visszahúzáskor a fúvóka egy kicsit megemelkedik, hogy a fúvóka és a " +"nyomtatott tárgy között rés keletkezzen. Ez megakadályozza, hogy a fúvóka " +"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 "Retraction Speed" msgstr "Visszahúzás sebessége" @@ -6523,7 +7015,7 @@ msgid "Seam position" msgstr "Varrat pozíció" msgid "The start position to print each part of outer wall" -msgstr "This is the starting position for each part of the outer wall." +msgstr "A külső fal nyomtatásának kiindulási helyzete." msgid "Nearest" msgstr "Legközelebbi" @@ -6559,9 +7051,9 @@ msgid "" "The printing speed in exported gcode will be slowed down, when the estimated " "layer time is shorter than this value, to get better cooling for these layers" msgstr "" -"The printing speed in exported G-code will be slowed down when the estimated " -"layer time is shorter than this value in order to get better cooling for " -"these layers." +"A nyomtatási sebesség az exportált G-kódban csökkentésre kerül, ha a becsült " +"rétegidő kisebb, mint ez az érték, hogy a rétegek jobb hűtése biztosított " +"legyen." msgid "Minimum sparse infill threshold" msgstr "Ritkás kitöltés küszöbértéke" @@ -6577,7 +7069,7 @@ msgid "mm²" msgstr "mm²" msgid "Line width of internal solid infill" -msgstr "Line width of internal solid infill" +msgstr "A belső tömör kitöltés vonalszélessége" msgid "Speed of internal solid infill, not the top and bottom surface" msgstr "" @@ -6607,14 +7099,11 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" msgid "Temperature variation" -msgstr "Temperature variation" +msgstr "Hőmérséklet változás" msgid "Start G-code" msgstr "Kezdő G-kód" @@ -6634,6 +7123,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Támasz engedélyezése" @@ -6644,9 +7150,9 @@ msgid "" "normal(auto) and tree(auto) is used to generate support automatically. If " "normal or tree is selected, only support enforcers are generated" msgstr "" -"normal(auto), hybrid(auto) and tree(auto) are used to generate support " -"automatically. If normal or tree is selected, only support enforcers are " -"generated." +"A normál (auto), hibrid (auto) és fa (auto) támaszok automatikus " +"generálására szolgál. Ha normál vagy fa van kiválasztva, akkor csak a támasz " +"kényszerítők kerülnek legenerálásra." msgid "normal(auto)" msgstr "normál (auto)" @@ -6657,24 +7163,24 @@ msgstr "fa (auto)" msgid "hybrid(auto)" msgstr "hibrid (auto)" -msgid "normal" -msgstr "normál" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "fa" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Támasz/tárgy XY távolság" msgid "XY separation between an object and its support" -msgstr "This controls the XY separation between an object and its support." +msgstr "Ez szabályozza a tárgy és a támasz közötti XY elválasztás távolságát." msgid "Pattern angle" msgstr "Mintázat szöge" msgid "Use this setting to rotate the support pattern on the horizontal plane." msgstr "" -"Use this setting to rotate the support pattern on the horizontal plane." +"Ezzel a beállítással elforgathatod a támasz mintázatát a vízszintes síkon." msgid "On build plate only" msgstr "Csak a tárgyasztaltól" @@ -6694,20 +7200,26 @@ msgid "Top Z distance" msgstr "Z távolság" msgid "The z gap between the top support interface and object" -msgstr "This determines the Z gap between top support interfaces and objects." +msgstr "" +"Meghatározza a Z távolságot a felső támasz érintkező rétege és az objektum " +"között." + +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filament a támasz és perem nyomtatásához. A 0 azt jelenti, hogy nincs erre " -"külön kijelölt filament és a jelenleg használt kerül felhasználásra" msgid "Line width of support" -msgstr "Line width of support" +msgstr "A támasz vonalszélessége" msgid "Interface use loop pattern" -msgstr "Loop pattern interface" +msgstr "Hurokminta felület" msgid "" "Cover the top contact layer of the supports with loops. Disabled by default." @@ -6716,18 +7228,15 @@ msgstr "" "letiltva." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Filament a támasz érintkező felületének nyomtatásához. A 0 azt jelenti, hogy " -"nincs erre külön kijelölt filament és a jelenleg használt kerül " -"felhasználásra" msgid "Top interface layers" msgstr "Felső érintkező rétegek" msgid "Number of top interface layers" -msgstr "This is the number of top interface layers." +msgstr "A felső érintkező rétegek száma." msgid "Bottom interface layers" msgstr "Alsó érintkező rétegek" @@ -6753,7 +7262,7 @@ msgid "Base pattern" msgstr "Alap mintázata" msgid "Line pattern of support" -msgstr "This is the line pattern for support." +msgstr "A támasz mintázata." msgid "Rectilinear grid" msgstr "Vonalrács" @@ -6776,6 +7285,12 @@ msgstr "Alap mintázatának térköze" msgid "Spacing between support lines" msgstr "A támasz vonalai közötti távolság" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Támaszok sebessége" @@ -6783,7 +7298,7 @@ msgid "Style" msgstr "Stílus" msgid "Snug" -msgstr "Snug" +msgstr "Szoros" msgid "Independent support layer height" msgstr "Független támasz rétegmagassága" @@ -6800,56 +7315,47 @@ msgid "" "Support will be generated for overhangs whose slope angle is below the " "threshold." msgstr "" -"Support will be generated for overhangs whose slope angle is below this " -"threshold." +"Az olyan túlnyúlásoknál, amelynek dőlésszöge ez alatt az érték alatt van, " +"támasz fog generálódni." msgid "Tree support branch angle" -msgstr "Tree support branch angle" +msgstr "Fa típusú támasz ágainak szöge" msgid "" "This setting determines the maximum overhang angle that t he branches of " "tree support allowed to make.If the angle is increased, the branches can be " "printed more horizontally, allowing them to reach farther." msgstr "" -"This setting determines the maximum overhang angle that the branches of tree " -"support are allowed to make. If the angle is increased, the branches can be " -"printed more horizontally, allowing them to reach farther." +"Ez a beállítás határozza meg, hogy a fa típusú támasz ágai milyen maximális " +"túlnyúlási szöget érhetnek el. Ha ezt a szöget növeled, az ágak " +"vízszintesebben nyomtathatók, így messzebbre nyúlhatnak." msgid "Tree support branch distance" -msgstr "Tree support branch distance" +msgstr "Fa támasz ágainak távolsága" msgid "" "This setting determines the distance between neighboring tree support nodes." msgstr "" -"This setting determines the distance between neighboring tree support nodes." +"Ez a beállítás határozza meg a szomszédos fa támasz csomópontok közötti " +"távolságot." msgid "Tree support branch diameter" -msgstr "Tree support branch diameter" +msgstr "Fa támasz ágának átmérője" msgid "This setting determines the initial diameter of support nodes." -msgstr "This setting determines the initial diameter of support nodes." +msgstr "Ez a beállítás határozza meg a támasz csomópontok kezdeti átmérőjét." msgid "Tree support wall loops" -msgstr "Tree support wall loops" +msgstr "Fa támasz falak száma" msgid "This setting specify the count of walls around tree support" -msgstr "This setting specifies the wall count around tree support." - -msgid "Tree support with infill" -msgstr "Tree support with infill" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"This setting specifies whether to add infill inside large hollows of tree " -"support." +msgstr "Ez a beállítás határozza meg a falak számát a fa támasz körül." msgid "Nozzle temperature for layers after the initial one" -msgstr "Nozzle temperature after the first layer" +msgstr "Fúvóka hőmérséklete az első réteg után" msgid "Nozzle temperature" -msgstr "Nozzle temperature" +msgstr "Fúvóka hőmérséklet" msgid "Bed temperature difference" msgstr "Asztalhőmérséklet különbség" @@ -6878,11 +7384,11 @@ msgid "" "This gcode is inserted when change filament, including T command to trigger " "tool change" msgstr "" -"This G-code is inserted when filament is changed, including T commands to " -"trigger tool change." +"Ez a G-kód kerül beillesztésre, amikor a filament csere történik, beleértve " +"a szerszámváltást indító T parancsokat is." msgid "Line width for top surfaces" -msgstr "Line width for top surfaces" +msgstr "Felső felületek vonalszélessége" msgid "Speed of top surface infill which is solid" msgstr "A felső felületi kitöltés sebessége, amely szilárd" @@ -6895,12 +7401,12 @@ msgid "" "layer. When the thickness calculated by this value is thinner than top shell " "thickness, the top shell layers will be increased" msgstr "" -"This is the number of solid layers of top shell, including the top surface " -"layer. When the thickness calculated by this value is thinner than the top " -"shell thickness, the top shell layers will be increased" +"Ez a felső héj szilárd rétegeinek száma, beleértve a felső felület réteget. " +"Ha az ezzel az értékkel számított vastagság vékonyabb, mint a felső héj " +"vastagsága, akkor a felső héj rétegeit a program megnöveli" msgid "Top solid layers" -msgstr "Top solid layers" +msgstr "Felső tömör rétegek" msgid "Top shell thickness" msgstr "Felső héj vastagság" @@ -6912,11 +7418,11 @@ msgid "" "is disabled and thickness of top shell is absolutely determained by top " "shell layers" msgstr "" -"The number of top solid layers is increased when slicing if the thickness " -"calculated by top shell layers is thinner than this value. This can avoid " -"having too thin a shell when layer height is small. 0 means that this " -"setting is disabled and thickness of top shell is determined simply by the " -"number of top shell layers." +"A felső szilárd rétegek száma szeleteléskor megnő, ha a felső héjrétegekből " +"számított vastagság kisebb ennél az értéknél. Ezzel elkerülhető, hogy túl " +"vékony legyen a héj kis rétegmagasságnál. A 0 azt jelenti, hogy ez a " +"beállítás ki van kapcsolva, és a felső héj vastagságát egyszerűen a felső " +"héjrétegek száma határozza meg." msgid "Speed of travel which is faster and without extrusion" msgstr "Mozgási sebesség, amikor nem történik extrudálás" @@ -6928,9 +7434,10 @@ 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 "" -"This moves the nozzle along the last extrusion path when retracting to clean " -"any leaked material on the nozzle. This can minimize blobs when printing a " -"new part after traveling." +"Ez visszahúzáskor a fúvókát az utolsó extrudálási útvonal mentén mozgatja, " +"hogy a fúvókából szivárgott anyagot eltávolítsa. Ez minimálisra csökkentheti " +"a pöttyöket, amikor a nyomtatófej a mozgást követően egy egy új alkatrész " +"nyomtatásába kezd." msgid "Wipe Distance" msgstr "Törlési távolság" @@ -6950,53 +7457,44 @@ msgstr "" msgid "Purging volumes" msgstr "Tisztítási mennyiségek" +msgid "Flush multiplier" +msgstr "Öblítési szorzó" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" -msgstr "Öblítési mennyiség" +msgstr "Tisztítási mennyiség" msgid "The volume of material to prime extruder on tower." -msgstr "" -"This is the volume of material to prime the extruder with on the tower." +msgstr "Ez az az anyagmennyiség, amelyet az extruder a toronyban ürít." msgid "Width" msgstr "Szélesség" msgid "Width of prime tower" -msgstr "This is the width of prime towers." - -msgid "Flush into objects' infill" -msgstr "Öblítés a tárgyak kitöltésébe" +msgstr "Ez a törlő torony szélessége." msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"A filament csere utáni tisztítás a tárgyak kitöltésén belül történik. Ez " -"csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ha a falakat " -"átlátszó filamenttel nyomtatod, a vegyes színű kitöltés kívülről látható lesz" - -msgid "Flush into objects' support" -msgstr "Öblítés a tárgyak támaszába" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"A filament csere utáni tisztítás a tárgyak támaszon belül történik. Ez " -"csökkentheti a hulladék mennyiségét és a nyomtatási időt" - -msgid "Flush into this object" -msgstr "Öblítés ebbe a tárgyba" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"This object will be used to purge the nozzle after a filament change to save " -"filament and decrease the print time. Colors of the objects will be mixed as " -"a result." msgid "X-Y hole compensation" msgstr "X-Y furatkompenzáció" @@ -7026,6 +7524,79 @@ msgstr "" "kisebb. Ez a funkció a méret kismértékű módosítására szolgál, ha a " "kinyomtatott tárggyal összeszerelési problémák akadnak" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Keskeny belső szilárd kitöltés felismerése" @@ -7034,9 +7605,10 @@ msgid "" "concentric pattern will be used for the area to speed printing up. " "Otherwise, rectilinear pattern is used defaultly." msgstr "" -"This option will auto-detect narrow internal solid infill areas. If enabled, " -"the concentric pattern will be used for the area to speed up printing. " -"Otherwise, the rectilinear pattern will be used by default." +"Ez a beállítás automatikusan felismeri a keskeny belső tömör kitöltési " +"területeket. Ha engedélyezve van, a nyomtatás felgyorsítása érdekében ezen a " +"területen a koncentrikus mintát fogja használni. Ellenkező esetben " +"alapértelmezés szerint az egyenes vonalú mintát használja." msgid "Export 3MF" msgstr "3MF exportálása" @@ -7044,12 +7616,30 @@ msgstr "3MF exportálása" msgid "Export project as 3MF." msgstr "Projekt exportálása 3MF formátumban." +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 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 "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Kimeneti modell információ" @@ -7062,6 +7652,12 @@ 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 "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Elrendezési lehetőségek" @@ -7077,26 +7673,20 @@ msgstr "Modell mértékegységének átváltása" msgid "Orient the model" msgstr "Modell orientációja" -msgid "Repair" -msgstr "Javítás" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Megjavítja a modell hálóit, ha azok hibásak" - msgid "Scale the model by a float factor" msgstr "A modell méretezése egy lebegő tényezővel" msgid "Load General Settings" -msgstr "Load General Settings" +msgstr "Általános beállítások betöltése" msgid "Load process/machine settings from the specified file" -msgstr "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 "Load Filament Settings" +msgstr "Filamentbeállítások betöltése" msgid "Load filament settings from the specified file list" -msgstr "Load filament settings from the specified file list" +msgstr "Filamentbeállítások betöltése a megadott fájllistából" msgid "Output directory" msgstr "Kimeneti mappa" @@ -7147,7 +7737,7 @@ msgid "Optimizing toolpath" msgstr "Szerszámút optimalizálása" msgid "Empty layers around bottom are replaced by nearest normal layers." -msgstr "Empty layers around bottom are replaced by nearest normal layers." +msgstr "Az alsó üres rétegeket a legközelebbi normál rétegek váltják fel." msgid "The model has too many empty layers." msgstr "" @@ -7155,39 +7745,36 @@ msgstr "" msgid "Slicing mesh" msgstr "Háló szeletelése" -msgid " Object:" -msgstr " Objektum:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" -msgstr "Support: generate toolpath at layer %d" +msgstr "Támasz: szerszámút generálása %d. réteg" msgid "Support: detect overhangs" -msgstr "Support: detect overhangs" +msgstr "Támasz: túlnyúlások észlelése" msgid "Support: generate contact points" -msgstr "Support: generate contact points" +msgstr "Támasz: érintkezési pontok generálása" msgid "Support: propagate branches" -msgstr "Support: propagate branches" +msgstr "Támasz: ágak kiterjesztése" msgid "Support: draw polygons" -msgstr "Support: draw polygons" +msgstr "Támasz: poligonok rajzolása" msgid "Support: generate toolpath" -msgstr "Support: generate toolpath" +msgstr "Támasz: szerszámút generálása" #, c-format, boost-format msgid "Support: generate polygons at layer %d" -msgstr "Support: generate polygons at layer %d" +msgstr "Támogatás: poligonok generálása %d. réteg" #, c-format, boost-format msgid "Support: fix holes at layer %d" -msgstr "Support: fix holes at layer %d" +msgstr "Támasz: lyukak javítása %d. réteg" #, c-format, boost-format msgid "Support: propagate branches at layer %d" -msgstr "Support: propagate branches at layer %d" +msgstr "Támasz: ágak kiterjesztése %d. réteg" #: resources/data/hints.ini: [hint:3D Scene Operations] msgid "" @@ -7353,33 +7940,82 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Festés törlése" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Tollméret beállítása" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Forgatás:" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Magasság:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Válassz ki egy vagy több fájlt (3mf/step/stl/obj/amf):" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "Initalization failed [%d]!" +#~ msgid "Finish" +#~ msgstr "Kész" -#~ msgid "Management" -#~ msgstr "Management" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "3MF/STL/STEP/OBJ/AMF importálása" -#~ msgid "Open" -#~ msgstr "Open" +#~ msgid "Part Cooling" +#~ msgstr "Tárgyhűtés" + +#~ msgid "Aux Cooling" +#~ msgstr "Segédhűtés" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" #~ msgstr "" -#~ "%1% túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " -#~ "ütközések." +#~ "Filament a támasz és perem nyomtatásához. A 0 azt jelenti, hogy nincs " +#~ "erre külön kijelölt filament és a jelenleg használt kerül felhasználásra" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Filament a támasz érintkező felületének nyomtatásához. A 0 azt jelenti, " +#~ "hogy nincs erre külön kijelölt filament és a jelenleg használt kerül " +#~ "felhasználásra" + +#~ msgid "Repair" +#~ msgstr "Javítás" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "Megjavítja a modell hálóit, ha azok hibásak" + +#~ msgid "Heat the nozzle to target temperature" +#~ msgstr "Fúvóka felmelegítése a kívánt hőmérsékletre" + +#~ msgid "" +#~ "Successfully sent. Will automatically jump to the device page in %s s" +#~ msgstr "" +#~ "Sikeresen elküldve. Az eszköz oldala automatikusan megjelenik %s mp belül" + +#~ msgid "Monitoring Recording" +#~ msgstr "Felvétel monitorozása" + +#~ msgid "Tree support with infill" +#~ msgstr "Fa támasz kitöltéssel" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Ez a beállítás határozza meg, hogy a fa támasz nagyobb üregeiben legyen-e " +#~ "kitöltés." #~ msgid "" #~ "\n" @@ -7390,89 +8026,29 @@ msgstr "" #~ "%1% túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " #~ "ütközések." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr "" -#~ " túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " -#~ "ütközések.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." #~ msgstr "" -#~ " túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " -#~ "ütközések.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Falak elkerülése mozgáskor" - -#~ msgid "Max travel detour distance" -#~ msgstr "Max travel detour distance" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Maximum detour distance for avoiding travel across walls. If the distance " -#~ "is larger than this value, there will be no detour." - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Height of the clearance cylinder around extruder: used as input for auto-" -#~ "arranging to avoid collisions when printing object by object" - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Az extruder körüli biztonságos terület sugara. Az automatikus " -#~ "elrendezéshez használatos az ütközések elkerülése érdekében, amikor " -#~ "objektumonként nyomtatsz" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Hiba a következő sorban %1%:\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Háromszögek csökkentése" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - Switch to zig-zag pattern automatically\n" -#~ "No - Reset density to default non-100% value automatically\n" - -#~ msgid "Extruder position" -#~ msgstr "Extruder pozíció" - -#~ msgid "Zig zag" -#~ msgstr "Cikcakk" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "Az asztalhőmérséklet magasabb, mint ennek a filamentnek az üvegesedési " -#~ "hőmérséklete.\n" -#~ "Ez a fúvóka eltömődését és nyomtatási hibákat okozhat" +#~ "%1% túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " +#~ "ütközések." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Adaptív rétegmagasság" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." #~ msgstr "" -#~ "An object is laid over the edge of the plate or exceeds the height " -#~ "limit.\n" -#~ "Please solve the problem by moving it totally on or off the plate, and " -#~ "confirming that the height is within the build volume." +#~ "Egy tárgy a tálcán kívülre került, vagy túllépi a magassághatárt.\n" +#~ "Kérjük, orvosold a problémát a tárgy tálcára helyezésével vagy a tálcáról " +#~ "való eltávolításával és a tárgy magasságának ellenőrzésével." #~ msgid "Auto arrange" -#~ msgstr "Auto Arrange" +#~ msgstr "Automatikus elrendezés" #~ msgid "" #~ "Auto orientates selected objects or all objects.If there are selected " @@ -7484,17 +8060,43 @@ msgstr "" #~ "ellenkező esetben az aktuális projektben lévő összes objektumot " #~ "orientálja." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Falak elkerülése mozgáskor" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "Az asztalhőmérséklet magasabb, mint ennek a filamentnek az üvegesedési " +#~ "hőmérséklete.\n" +#~ "Ez a fúvóka eltömődését és nyomtatási hibákat okozhat" + #~ msgid "Clear all" -#~ msgstr "Clear all" +#~ msgstr "Összes törlése" + +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Az extruder körüli biztonságos terület sugara. Az automatikus " +#~ "elrendezéshez használatos az ütközések elkerülése érdekében, amikor " +#~ "objektumonként nyomtatsz" + +#~ msgid "Color Print" +#~ msgstr "Színes nyomtatás" + +#~ msgid "Comsumption" +#~ msgstr "Felhasználás" #~ msgid "Creating" -#~ msgstr "Creating" +#~ msgstr "Létrehozás" #~ msgid "Ctrl + Any arrow" -#~ msgstr "Ctrl + Any arrow" +#~ msgstr "Ctrl + Bármely nyílgomb" #~ msgid "Ctrl + Left mouse button" -#~ msgstr "Ctrl + Left mouse button" +#~ msgstr "Ctrl + Bal egérgomb" #~ msgid "Debug" #~ msgstr "Debug" @@ -7506,13 +8108,13 @@ msgstr "" #~ msgstr "Eszköz:" #~ msgid "Display printable box" -#~ msgstr "Display printable box" +#~ msgstr "Nyomtatható doboz megjelenítése" #~ msgid "Display shadow of objects" -#~ msgstr "Display shadow of objects" +#~ msgstr "Objektumok árnyékának megjelenítése" #~ msgid "Display triangles of models" -#~ msgstr "Display triangles of models" +#~ msgstr "Modell háromszögeinek megjelenítése" #~ msgid "" #~ "Do you want to synchronize your personal data from Bambu Cloud? \n" @@ -7521,58 +8123,125 @@ msgstr "" #~ "2. The Filament presets\n" #~ "3. The Printer presets\n" #~ msgstr "" -#~ "Do you want to synchronize your personal data from Bambu Cloud? \n" -#~ "Contains the following information:\n" -#~ "1. Process presets\n" -#~ "2. Filament presets\n" -#~ "3. Printer presets\n" +#~ "Szinkronizálni szeretnéd személyes adataid a Bambu Cloud-ból? \n" +#~ "A következő információkat tartalmazza:\n" +#~ "1. Folyamat beállítások\n" +#~ "2. Filament beállítások\n" +#~ "3. Nyomtató beállítások\n" #~ msgid "" #~ "Don't retract when the travel is in infill area absolutely. That means " #~ "the oozing can't been seen" #~ msgstr "" -#~ "This disables retraction when travel is entirely within an infill area " -#~ "and oozing can’t be seen." +#~ "Ez kikapcsolja a visszahúzást, ha a mozgás teljes egészében egy kitöltési " +#~ "területen belül történik." + +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Ha engedélyezed ezt az opciót, akkor az első réteg kivételével minden " +#~ "réteg magassága automatikusan kiszámításra kerül a szeletelés során a " +#~ "modellfelület lejtésének megfelelően.\n" +#~ "Felhívjuk a figyelmed, hogy ez az opció csak akkor működik, ha az " +#~ "aktuális tálcán nincs törlő torony generálva." #~ msgid "Enter a search term" -#~ msgstr "Enter a search term" +#~ msgstr "Add meg a keresési kifejezést" + +#~ msgid "Erase painting" +#~ msgstr "Festés törlése" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Hiba a következő sorban %1%:\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Szeletelt fájl exportálása" + +#~ msgid "Export current Sliced file" +#~ msgstr "Jelenlegi szeletelt fájl exportálása" + +#~ msgid "Export ok." +#~ msgstr "Exportálás kész." + +#~ msgid "Export sliced file" +#~ msgstr "Szeletelt fájl exportálása" + +#~ msgid "Extruder position" +#~ msgstr "Extruder pozíció" #~ msgid "Failed" #~ msgstr "Failed" +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" + #~ msgid "Filaments Selection" -#~ msgstr "Filaments selection" +#~ msgstr "Filamentek kiválasztása" #~ msgid "Finished" -#~ msgstr "Finished" +#~ msgstr "Kész" #~ msgid "Fix model locally" -#~ msgstr "Fix model locally" +#~ msgstr "Modell javítása helyben" #~ msgid "Fix model through cloud" -#~ msgstr "Fix model through cloud" +#~ msgstr "Modell javítása felhőn keresztül" + +#~ msgid "Flushed filament" +#~ msgstr "Öblített filament" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Ez arra kényszeríti a hűtőventilátort, hogy egy adott fordulatszámot " +#~ "használjon, ha az alkatrészek túlnyúlási foka meghaladja a beállított " +#~ "értéket. Ez százalékban van kifejezve, ami azt jelzi, hogy hány vonal " +#~ "fogadható el az alsóbb rétegek alátámasztása nélkül." #~ msgid "Fragment Filter" -#~ msgstr "Fragment Filter" +#~ msgstr "Töredékszűrő" #~ msgid "Fragment area" -#~ msgstr "Fragment area" +#~ msgstr "Töredék terület" #~ msgid "Fragment filter" -#~ msgstr "Fragment filter" +#~ msgstr "Töredékszűrő" #~ msgid "" #~ "Heat the nozzle to target \n" #~ "temperature" #~ msgstr "" -#~ "Heat the nozzle to the target \n" -#~ "temperature" +#~ "Fúvóka felfűtése a\n" +#~ "célhőmérsékletre" + +#~ msgid "Height:" +#~ msgstr "Magasság:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Az extruder körül szabadon hagyott kör alakú terület magassága: az " +#~ "automatikus elrendezéshez van használva az ütközések elkerülése " +#~ "érdekében, amikor a nyomtatás tárgyanként történik." #~ msgid "In the calibration of extrusion flow" -#~ msgstr "In the calibration of extrusion flow" +#~ msgstr "Az anyagáramlás kalibrálásában" #~ msgid "In the calibration of laser scanner" -#~ msgstr "In the calibration of laser scanner" +#~ msgstr "A lézer szkenner kalibrálásában" + +#~ msgid "Initialize failed [%d]!" +#~ msgstr "Az inicializálás sikertelen [%d]!" #~ msgid "Inner wall speed" #~ msgstr "Belső fal sebessége" @@ -7587,55 +8256,98 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Vonal típusa" +#~ msgid "Management" +#~ msgstr "Management" + +#~ msgid "Max travel detour distance" +#~ msgstr "Max. kerülőút távolság" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Maximális kerülőút távolság a falakon való áthaladás elkerülésére. Ha a " +#~ "távolság nagyobb ennél az értéknél, akkor nem lesz kitérő." + #~ msgid "Module" -#~ msgstr "Module" +#~ msgstr "Modul" #~ msgid "Monitoring" -#~ msgstr "Monitoring" +#~ msgstr "Monitorozás" + +#~ msgid "Open" +#~ msgstr "Open" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "PrusaSlicer megnyitása" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "PrusaSlicer megnyitása" #~ msgid "Output file" -#~ msgstr "Output file" +#~ msgstr "Kimeneti fájl" #~ msgid "Pause(heated bed temperature error)" -#~ msgstr "Pause(heated bed temperature error)" +#~ msgstr "Szünet (tárgyasztal hőmérséklet hiba)" #~ msgid "Pause(hotend temperature error)" -#~ msgstr "Pause(hotend temperature error)" +#~ msgstr "Szünet (hotend hőmérséklet hiba)" #~ msgid "Pause(toolhead shell off)" -#~ msgstr "Pause(toolhead shell off)" +#~ msgstr "Szünet (nyomtatófej burkolat hiányzik)" #~ msgid "Per object edit" #~ msgstr "Szerkesztés objektumonként" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "%d. tálca: %s nem használható %s filamenttel.\n" + #~ msgid "Please fill report first." -#~ msgstr "Please fill report first." +#~ msgstr "Kérjük, először töltsd ki a riportot." #~ msgid "Please upgrade your printer first" -#~ msgstr "Please upgrade your printer first" +#~ msgstr "Kérjük, először frissítsd a nyomtatót" #~ msgid "Position:" -#~ msgstr "Position:" +#~ msgstr "Pozíció:" #~ msgid "" #~ "Preview only mode:\n" #~ "The loaded file contains gcode only." #~ msgstr "" -#~ "Preview only mode:\n" -#~ "The loaded file contains G-code only." +#~ "Csak előnézeti mód:\n" +#~ "A betöltött fájl csak G-kódot tartalmaz." #~ msgid "Preview only mode for gcode file." -#~ msgstr "Preview only mode for G-code file." +#~ msgstr "Csak előnézeti mód a G-kód fájlhoz." #~ msgid "Printer Selection" -#~ msgstr "Printer Selection" +#~ msgstr "Nyomtató kiválasztása" + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "A filament csere utáni tisztítás a tárgyak kitöltésén belül történik. Ez " +#~ "csökkentheti a hulladék mennyiségét és a nyomtatási időt. Ha a falakat " +#~ "átlátszó filamenttel nyomtatod, a vegyes színű kitöltés kívülről látható " +#~ "lesz" + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "A filament csere utáni tisztítás a tárgyak támaszon belül történik. Ez " +#~ "csökkentheti a hulladék mennyiségét és a nyomtatási időt" #~ msgid "" #~ "Push new filament \n" #~ "into extruder" #~ msgstr "" -#~ "Push new filament \n" -#~ "into extruder" +#~ "Új filament betöltése\n" +#~ "az extruderbe" #~ msgid "" #~ "Record timelapse video of printing without showing toolhead. In this mode " @@ -7649,67 +8361,112 @@ msgstr "" #~ "kamerával pillanatfelvétel készül. A nyomtatás befejezésekor egy " #~ "timelapse videó áll össze az összes pillanatfelvételből." +#~ msgid "Reduce Triangles" +#~ msgstr "Háromszögek csökkentése" + +#~ msgid "Reload item" +#~ msgstr "Tárgy újbóli betöltése" + +#~ msgid "Reload items" +#~ msgstr "Tárgyak újbóli betöltése" + #~ msgid "Report" -#~ msgstr "Report" +#~ msgstr "Jelentés" + +#~ msgid "Rotation:" +#~ msgstr "Forgatás:" #~ msgid "Save configuration as:" #~ msgstr "Konfiguráció mentése mint:" #~ msgid "Sending" -#~ msgstr "Sending" +#~ msgstr "Küldés" + +#~ msgid "Set pen size" +#~ msgstr "Tollméret beállítása" #~ msgid "Shift + Any arrow" -#~ msgstr "Shift + Any arrow" +#~ msgstr "Shift + Bármely nyílgomb" #~ msgid "Shift + Mouse wheel" -#~ msgstr "Shift + Mouse wheel" +#~ msgstr "Shift + Egérgörgő" #~ msgid "Show Model Mesh(TODO)" -#~ msgstr "Show Model Mesh(TODO)" +#~ msgstr "Modellháló megjelenítése (TODO)" #~ msgid "Show Model Shadow(TODO)" -#~ msgstr "Show Model Shadow(TODO)" +#~ msgstr "Modell árnyék megjelenítése(TODO)" #~ msgid "Show Printable Box(TODO)" -#~ msgstr "Show Printable Box(TODO)" +#~ msgstr "Nyomtatható doboz megjelenítése(TODO)" #~ msgid "Spiral mode" -#~ msgstr "Spiral/Vase mode" +#~ msgstr "Spirál/Váza mód" #~ msgid "Successfully sent.Will automatically jump to the device page in %s s" #~ msgstr "" -#~ "Successfully sent. Will automatically jump to the device page in %s s" +#~ "Sikeresen elküldve. Automatikus átváltás a készülék oldalára %s mp-en " +#~ "belül" #~ msgid "" #~ "Support layer uses layer height independent with object layer. This is to " #~ "support custom support gap,but may cause extra filament switches if " #~ "support is specified as different extruder with object" #~ msgstr "" -#~ "The support layer uses layer height independent of object layers. This is " -#~ "to support custom support gaps, but may cause extra filament switches if " -#~ "support is specified as a different filament from the object." +#~ "A támasz rétegmagassága független az objektumhoz beállított " +#~ "rétegmagasságtól. Ezzel egyéni távolságot lehet beállítani a tárgy és a " +#~ "támasz között, de előfordulhat, hogy extra filament váltást okoz, ha más " +#~ "anyagú filamentet használsz támaszként." + +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "Átváltasz cikcakkos mintára?\n" +#~ "Igen - Automatikus átváltás cikkcakk mintára\n" +#~ "Nem - A kitöltés automatikus visszaállítása az alapértelmezett, nem 100%-" +#~ "os értékre.\n" #~ msgid "Swith cloud environment, Please login again!" -#~ msgstr "Switch cloud environment, Please login again!" +#~ msgstr "Felhőkörnyezet váltása, kérjük, jelentkezz be újra!" #~ msgid "The Config is not compatible and can not be loaded." -#~ msgstr "The configuration is not compatible and cannot be loaded!" +#~ msgstr "A konfiguráció nem kompatibilis és nem tölthető be!" #~ msgid "" #~ "The firmware versions of printer and AMS are too low.Please update to the " #~ "latest version before sending the print job" #~ msgstr "" -#~ "The firmware versions of the printer and AMS are too low. Please update " -#~ "them to the latest version before sending any print jobs." +#~ "A nyomtató és az AMS firmware-verziója túl régi. Kérjük, frissítsd őket a " +#~ "legújabb verzióra, mielőtt új nyomtatásba kezdenél." #~ msgid "" #~ "The model has overlapping or self-intersecting facets. I tried to repair " #~ "it, however you might want to check the results or repair the input file " #~ "and retry." #~ msgstr "" -#~ "The model has overlapping or self-intersecting facets. Repair was " -#~ "attempted, however we recommend checking the results or repairing the " -#~ "input file and retrying." +#~ "A modellnek átfedésben lévő vagy egymást metsző elemei vannak. " +#~ "Megkíséreltük a javítást, azonban javasoljuk az eredmények ellenőrzését " +#~ "vagy a bemeneti fájl javítását és az újbóli próbálkozást." + +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Ez az objektum a fúvóka tisztítására szolgál filamentcsere után, a " +#~ "nyomtatási idő csökkentése és némi filament megtakarításának érdekében. " +#~ "Az objektum színei ennek eredményeképpen keveredni fognak." + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Ezzel állíthatod be a másodpercenként megolvasztható és extrudálható " +#~ "maximális filament mennyiséget. A nyomtatási sebességet a maximális " +#~ "térfogatsebesség korlátozhatja. A 0 azt jelenti, hogy nincs korlátozás." #~ msgid "Timelapse Wipe Tower" #~ msgstr "Timelapse törlő torony" @@ -7718,19 +8475,50 @@ msgstr "" #~ msgstr "Nyomtatófej nélküli timelapse" #~ msgid "Translation" -#~ msgstr "Translation" +#~ msgstr "Fordítás" #~ msgid "Unable to create zip file" -#~ msgstr "Unable to create zip file" +#~ msgstr "Nem sikerült létrehozni a zip fájlt" #~ msgid "Uploading" -#~ msgstr "Uploading" +#~ msgstr "Feltöltés" #~ msgid "User pause" -#~ msgstr "User pause" +#~ msgstr "Felhasználói szünet" #~ msgid "Waiting" -#~ msgstr "Waiting" +#~ msgstr "Várakozás" + +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "Megváltoztattál néhány beállítást.\n" +#~ "Szeretnéd megtartani ezeket a megváltozott beállításokat az előbeállítás " +#~ "váltás után?" + +#~ msgid "Zig zag" +#~ msgstr "Cikcakk" + +#~ msgid " Object:" +#~ msgstr " Objektum:" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr "" +#~ " túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " +#~ "ütközések.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr "" +#~ " túl közel van a tiltott területhez, a nyomtatás során előfordulhatnak " +#~ "ütközések.\n" + +#~ msgid "normal" +#~ msgstr "normál" #~ msgid "the 3mf is not compatible, load geometry data only!" -#~ msgstr "The 3mf is not compatible, loading geometry data only!" +#~ msgstr "A 3mf nem kompatibilis, csak geometriai adatok kerülnek betöltésre!" + +#~ msgid "tree" +#~ msgstr "fa" diff --git a/bbl/i18n/list.txt b/bbl/i18n/list.txt index 36aebc444a..f9c0fda463 100644 --- a/bbl/i18n/list.txt +++ b/bbl/i18n/list.txt @@ -38,6 +38,7 @@ src/slic3r/GUI/Jobs/PlaterJob.cpp src/slic3r/GUI/Jobs/RotoptimizeJob.cpp src/slic3r/GUI/Jobs/BindJob.cpp src/slic3r/GUI/Jobs/PrintJob.cpp +src/slic3r/GUI/Jobs/SendJob.cpp src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp src/slic3r/GUI/AboutDialog.cpp src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -58,7 +59,6 @@ src/slic3r/GUI/GLCanvas3D.cpp src/slic3r/GUI/Calibration.cpp src/slic3r/GUI/CameraPopup.cpp src/slic3r/GUI/ConnectPrinter.cpp -src/slic3r/GUI/ConfirmHintDialog.cpp src/slic3r/GUI/HMSPanel.cpp src/slic3r/GUI/MainFrame.cpp src/slic3r/GUI/MediaPlayCtrl.cpp @@ -89,6 +89,7 @@ src/slic3r/GUI/Selection.cpp src/slic3r/GUI/SelectMachine.cpp src/slic3r/GUI/SendSystemInfoDialog.cpp src/slic3r/GUI/SendToPrinter.cpp +src/slic3r/GUI/SetBedTypeDialog.cpp src/slic3r/GUI/BindDialog.cpp src/slic3r/GUI/Tab.cpp src/slic3r/GUI/Tab.hpp diff --git a/bbl/i18n/nl/BambuStudio_nl.po b/bbl/i18n/nl/BambuStudio_nl.po index 6d6c0f7f05..3dd3539e03 100644 --- a/bbl/i18n/nl/BambuStudio_nl.po +++ b/bbl/i18n/nl/BambuStudio_nl.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -22,6 +22,9 @@ msgstr "Alt + muiswiel" msgid "Section view" msgstr "Doorsnede" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + muiswiel" @@ -67,6 +70,9 @@ msgstr "Gereedschap type" msgid "Smart fill angle" msgstr "Slim vullen hoek" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Maximale hoek automatische support: " @@ -82,6 +88,10 @@ msgstr "Vullen" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Gebieden markeren op basis van overhangende hoek." @@ -139,6 +149,12 @@ msgstr "Emmer vullen" msgid "Height range" msgstr "Hoogtebereik" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Sneltoest " @@ -335,9 +351,6 @@ msgstr "Gezichtsherkenning" msgid "Perform Recognition" msgstr "Herkenning uitvoeren" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -356,15 +369,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -512,8 +516,8 @@ msgstr "Een modusweergave laden" msgid "Choose one file (3mf):" msgstr "Kies een bestand (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Kies een of meer bestanden (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Kies een bestand (.gcode/.gco/.g/.ngc/ngc):" @@ -596,6 +600,9 @@ msgstr "Vulling" msgid "Support" msgstr "Support" +msgid "Flush options" +msgstr "Flush-opties" + msgid "Speed" msgstr "Snelheid" @@ -729,6 +736,18 @@ msgstr "Schaal aanpassen aan printbed formaat" msgid "Scale an object to fit the build volume" msgstr "Object schalen zodat het op het prinbed past" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Flush in de opvulling van objecten" + +msgid "Flush into this object" +msgstr "Flush in dit object" + +msgid "Flush into objects' support" +msgstr "Flush in de support van objecten" + msgid "Convert from inch" msgstr "Converenten vanuit inch" @@ -782,6 +801,9 @@ msgstr "Spiegel object" msgid "Add Primitive" msgstr "Primitief toevoegen" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "Naar objecten" @@ -849,6 +871,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -942,6 +967,16 @@ msgstr "Algemeen" msgid "Add Modifier" msgstr "Aanpasser toevoegen" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "" +"Schakel over naar instellingsmodus per object om instellingen van de " +"aanpassing te bewerken." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "Het is niet toegestaand om het laaste vaste deel te verwijderen." @@ -1094,6 +1129,9 @@ msgstr "Meer" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1106,6 +1144,15 @@ msgstr "" msgid "OK" msgstr "Offline" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1127,7 +1174,7 @@ msgstr "" msgid "No printer" msgstr "Geen printer" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1340,12 +1387,34 @@ msgid "Sending print configuration" msgstr "Print configuratie verzenden" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "Downloaden" @@ -1355,8 +1424,8 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" -msgstr "Klaar" +msgid "Install successfully." +msgstr "" msgid "Installing" msgstr "" @@ -1449,6 +1518,9 @@ msgstr "De invoerwaarde moet groter zijn dan %1% en kleiner dan %2%" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Bevestigen" @@ -1474,6 +1546,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "AMS Instellingen" @@ -1522,6 +1607,23 @@ msgstr "" "door de AMS tijdens het opstarten. De tijdens de laatste keer uitzetten " "opgeslagen informatie zal gebruikt worden." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Bestand" @@ -1730,6 +1832,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1807,6 +1914,17 @@ msgstr "" "Ja - Pas de instellingen aan en zet de vaas modus automatisch aan\n" "Nee - Pas de vaas modus deze keer niet toe" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1958,6 +2076,9 @@ msgstr "Updaten mislukt." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "Standaard" + msgid "parameter name" msgstr "" @@ -2025,6 +2146,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "G-codes worden geladen" @@ -2034,6 +2161,9 @@ msgstr "Geometrische hoekpuntgegevens genereren" msgid "Generating geometry index data" msgstr "Geometrie-indexgegevens genereren" +msgid "Display" +msgstr "Tonen" + msgid "up to" msgstr "tot" @@ -2049,14 +2179,11 @@ msgstr "naar" msgid "Color Scheme" msgstr "Kleurschema" -msgid "Percent" -msgstr "Procent" - msgid "Time" msgstr "Tijd" -msgid "Display" -msgstr "Tonen" +msgid "Percent" +msgstr "Procent" msgid "Layer Height (mm)" msgstr "Laaghoogte (mm)" @@ -2079,14 +2206,11 @@ msgstr "Volumestroom (mm³/s)" msgid "Used filament" msgstr "Verbruikt filament" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Kleuren print" - -msgid "Comsumption" -msgstr "Verbruik" +msgid "Total" +msgstr "Totaal" msgid "Travel" msgstr "Verplaatsen" @@ -2115,18 +2239,12 @@ msgstr "verplaatsen" msgid "Extruder" msgstr "Extruder" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "Flushed filament" - -msgid "Total" -msgstr "Totaal" - msgid "Filament change times" msgstr "Filamentwisseltijden" +msgid "Cost" +msgstr "Kosten" + msgid "Color change" msgstr "Kleur veranderen" @@ -2145,24 +2263,75 @@ msgstr "Print instellingen" msgid "Total Estimation" msgstr "Schatting totaal" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Normale modus" -msgid "Cost" -msgstr "Kosten" - msgid "Prepare time" msgstr "Voorbereidingstijd" msgid "Model printing time" msgstr "Model print tijd" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Omzetten naar stille modus" msgid "Switch to normal mode" msgstr "Omzetten naar normale modus" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Straal" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Reeks" @@ -2274,6 +2443,18 @@ msgstr "" msgid "Calibration" msgstr "Kalibratie" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Kalibratie programma" @@ -2298,11 +2479,23 @@ msgstr "" msgid "Calibrating" msgstr "Kalibreren" -msgid "Timelapse" -msgstr "Timelapse" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Monitoring en opname" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Resolutie" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Printer aansluiten (LAN)" @@ -2347,6 +2540,15 @@ msgstr "Apparaat" msgid "Project" msgstr "Project" +msgid "Yes" +msgstr "Ja" + +msgid "No" +msgstr "Nee" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Slice" @@ -2356,17 +2558,26 @@ msgstr "Alles slicen" msgid "Slice plate" msgstr "Slice printbed" -msgid "Print all" -msgstr "Print alles" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Exporteer het \"sliced\" bestand" +msgid "Send" +msgstr "Versturen" -msgid "Export Sliced File" -msgstr "Exporteer het \"sliced\" bestand" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Print alles" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Sneltoesten" @@ -2380,17 +2591,23 @@ msgstr "Installatiewizard" msgid "Show Configuration Folder" msgstr "Toon de configuratie map" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Zoeken naar updates" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&Over %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2461,8 +2678,8 @@ msgstr "Bewaar project als" msgid "Save current project as" msgstr "Bewaar huidig project als" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Importeer 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Laad een model" @@ -2485,8 +2702,11 @@ msgstr "Generiek 3MF exporteren" msgid "Export 3mf file without using some 3mf-extensions" msgstr "3mf-bestand exporteren zonder enkele 3mf-toevoegingen te gebruiken" -msgid "Export current Sliced file" -msgstr "Exporteer het huidig \"sliced\" bestand" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Exporteer G-code" @@ -2578,6 +2798,9 @@ msgstr "Weergave" msgid "Help" msgstr "Help" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "&Open G-code" @@ -2596,11 +2819,11 @@ msgstr "Exporteer &Toolpaths als OBJ" msgid "Export toolpaths as OBJ" msgstr "Toolpaths exporteren als OBJ" -msgid "Open &PrusaSlicer" -msgstr "Open &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Open PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Afsluiten" @@ -2668,6 +2891,11 @@ msgid "" "2. The Filament presets\n" "3. The Printer presets\n" msgstr "" +"Do you want to synchronize your personal data from Bambu Cloud? \n" +"It contains the following information:\n" +"1. The Process presets\n" +"2. The Filament presets\n" +"3. The Printer presets\n" msgid "Synchronization" msgstr "Synchronisatie" @@ -2690,7 +2918,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2707,6 +2938,27 @@ msgstr "" msgid "Stopped." msgstr "Gestopt." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Afspelen..." @@ -2732,6 +2984,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Timelapse" + msgid "Switch to timelapse files." msgstr "" @@ -2759,7 +3014,7 @@ msgstr "" msgid "No printers." msgstr "Geen printers" -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2767,7 +3022,7 @@ msgstr "Verbinden..." #, c-format, boost-format msgid "Connect failed [%d]!" -msgstr "" +msgstr "Verbinding mislukt [%d]!" msgid "Loading file list..." msgstr "Bestandslijst laden..." @@ -2775,6 +3030,12 @@ msgstr "Bestandslijst laden..." msgid "No files" msgstr "Geen bestanden" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2819,6 +3080,12 @@ msgstr "Wissel Y/Z assen om" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Print voortgang" @@ -2846,11 +3113,11 @@ msgstr "100%" msgid "Lamp" msgstr "Licht" -msgid "Part Cooling" -msgstr "Koeling van de printkop" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Extra koeling" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Printbed" @@ -2861,6 +3128,12 @@ msgstr "Lossen" msgid "Debug Info" msgstr "Informatie over Debuggen" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Print lijst" @@ -2870,9 +3143,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "Downloaden..." +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2888,6 +3190,9 @@ msgstr "Sport" msgid "Ludicrous" msgstr "Ludicrous" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Verbinding maken met de server is mislukt" @@ -2906,11 +3211,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Verbinding maken met de printer is mislukt" -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nee" +msgid "Don't show again" +msgstr "Niet nogmaals tonen" #, c-format, boost-format msgid "%s error" @@ -3022,8 +3324,8 @@ msgstr "Fout:" msgid "Warning:" msgstr "Waarschuwing:" -msgid "Export ok." -msgstr "Exporteren ok" +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Repareren)" @@ -3052,9 +3354,6 @@ msgstr "Lagen" msgid "Range" msgstr "Bereik" -msgid "default" -msgstr "Standaard" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3087,22 +3386,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Onderste" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." +msgid "Auto-recovery from step loss" msgstr "" -"Schakel over naar instellingsmodus per object om instellingen van de " -"aanpassing te bewerken." - -msgid "Don't show again" -msgstr "Niet nogmaals tonen" msgid "Global" msgstr "Globale" @@ -3171,7 +3473,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3192,6 +3494,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Naamloos" @@ -3221,6 +3529,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Bestand laden: %s" @@ -3336,9 +3650,6 @@ msgstr "Het geselecteerde object kan niet opgesplitst worden." msgid "Another export job is running." msgstr "Er is reeds een export taak actief." -msgid "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3363,6 +3674,9 @@ msgstr "waarschuwingen" msgid "Invalid data" msgstr "Interne solide vulling (infill)" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Slicing printbed %d" @@ -3390,6 +3704,28 @@ msgstr "Start een nieuw project" msgid "Load project" msgstr "Project laden" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "Het geselecteerde bestand" @@ -3449,6 +3785,12 @@ msgstr "Bewaar G-code bestand als:" msgid "Save Sliced file as:" msgstr "Bewaar het geslicede bestand als:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3470,6 +3812,9 @@ msgstr "" msgid "Invalid number" msgstr "Ongeldig nummer" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Onderdeel naam: %1%\n" @@ -3498,6 +3843,18 @@ msgstr "Volume: %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Driehoeken: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "" "Om de taal te wijzigen dient de toepassing opnieuw opgestart te worden.\n" @@ -3617,6 +3974,12 @@ msgstr "Backupinterval" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Startpagina en dagelijkse tips" @@ -3728,6 +4091,15 @@ msgstr "Voorinstelling bewerken" msgid "Project-inside presets" msgstr "Voorinstellingen binnen project" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "" "Slice alle printbedden om een inschatting te krijgen van de printtijd en het " @@ -3886,9 +4258,6 @@ msgstr "Bed leveling" msgid "Flow Calibration" msgstr "Flow calibratie" -msgid "Send" -msgstr "Versturen" - msgid "send completed" msgstr "Versturen gelukt" @@ -3904,8 +4273,8 @@ msgstr "Informatie over het apparaat synchroniseren" msgid "Synchronizing device information time out" msgstr "Time-out tijdens synchronisatie van apparaatinformatie" -msgid "Cannot send the print task when the upgrade is in progress" -msgstr "Kan de printtaak niet verzenden wanneer de upgrade wordt uitgevoerd" +msgid "Cannot send the print job when the printer is updating firmware" +msgstr "" msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3960,10 +4329,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3972,18 +4354,49 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Print opdracht voorbereiden" msgid "Modifying the device name" msgstr "De naam van het apparaat wijzigen" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "Kan de printtaak niet verzenden wanneer de upgrade wordt uitgevoerd" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Cool (koud) printbed" + +msgid "Engineering Plate" +msgstr "Engineering plate (technisch printbed)" + +msgid "High Temp Plate" +msgstr "High Temp Plate (hoge temperatuur printbed)" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Inloggen op printer" @@ -4025,13 +4438,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -4050,6 +4463,9 @@ msgstr "Naad" msgid "Precision" msgstr "Precisie" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Wanden" @@ -4081,15 +4497,15 @@ msgstr "Verplaatsing-sneleheid" msgid "Acceleration" msgstr "Versnelling" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Support filament" msgid "Prime tower" msgstr "Prime toren" -msgid "Flush options" -msgstr "Flush-opties" - msgid "Special mode" msgstr "Speciale modus" @@ -4170,9 +4586,6 @@ msgstr "" "waarde van 0 betekent dat het filament afdrukken op de Engineering Plate " "niet ondersteunt." -msgid "High Temp Plate" -msgstr "High Temp Plate (hoge temperatuur printbed)" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4181,9 +4594,6 @@ msgstr "" "Een waarde van 0 betekent dat het filament printen op de High Temp Plate " "niet ondersteunt." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4406,13 +4816,18 @@ msgstr "" "Voorinstelling \"%1%\" is niet compatibel met het niet proces profiel en " "bevat de navolgende nog niet opgeslagen aanpassingen:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"U hebt enkele voorinstellingen gewijzigd.\n" -"Wilt u deze gewijzigde instellingen behouden na het wisselen van " -"voorinstelling?" msgid "Extruders count" msgstr "Extruder aantal" @@ -4423,6 +4838,11 @@ msgstr "Algemeen" msgid "Capabilities" msgstr "Mogelijkheden" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4510,17 +4930,28 @@ msgstr "Geen updates beschikbaar." msgid "The configuration is up to date." msgstr "De configuratie is up to date." -msgid "Auto-Calc" -msgstr "Automatisch berekenen" - msgid "Flushing volumes for filament change" msgstr "Volumes reinigen voor filament wijziging" +msgid "Auto-Calc" +msgstr "Automatisch berekenen" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Spoelvolume (mm³) voor elk filamentpaar." -msgid "Flush multiplier" -msgstr "Flush-vermenigvuldiger" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "uitgeladen" @@ -4799,7 +5230,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4811,13 +5242,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4837,6 +5268,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "Het opslaan van de objecten naar het 3mf bestand is mislukt." @@ -5085,12 +5519,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "%1% staat te dicht bij anderen en er kunnen botsingen ontstaan." @@ -5182,6 +5610,11 @@ msgstr "" "Een prime toren vereist dat alle objecten met dezelfde laaghoogte gesliced " "worden." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "Te kleine lijnbreedte" @@ -5203,8 +5636,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "De laaghoogte kan niet groter zijn dan de diameter van de nozzle" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "Printbed %d: %s onderstand filament %s niet.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Skirt en brim worden gegenereerd" @@ -5230,6 +5663,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "\"Elephant foot\" compensatie" @@ -5408,12 +5847,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Printbedden ondersteund door de printer" -msgid "Cool Plate" -msgstr "Cool (koud) printbed" - -msgid "Engineering Plate" -msgstr "Engineering plate (technisch printbed)" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "" "De G-code wordt bij iedere laagwisseling toegevoegd voor het optillen van Z" @@ -5472,13 +5905,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Drempel voor overhang koeling" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"Forceer de snelheid van de koelventilator wanneer de overhanggraad van het " -"onderdeel deze waarde overschrijdt. Uitgedrukt als percentage " msgid "Bridge flow" msgstr "Brugflow" @@ -5545,6 +5987,9 @@ msgstr "" msgid "Compatible machine" msgstr "Geschikte machine" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Conditie van geschikte machine" @@ -5636,9 +6081,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5667,6 +6109,25 @@ 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." +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Patroon bovenvlak" @@ -5692,6 +6153,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Bodem oppvlakte patroon" @@ -5745,9 +6212,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Straal" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5817,21 +6281,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Kleur" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Maximale volumetrische snelheid" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Deze instelling staat voor het volume filament dat per seconde kan worden " -"gesmolten en geëxtrudeerd. De printsnelheid wordt beperkt door de maximale " -"volumetrische snelheid in het geval van een te hoge en onredelijke " -"snelheidsinstelling. 0 betekent geen limiet." msgid "mm³/s" msgstr "mm³/s" @@ -5966,6 +6440,12 @@ msgstr "Honinggraad" msgid "Adaptive Cubic" msgstr "Adaptief kubiek" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5976,6 +6456,9 @@ msgstr "" "Versnelling van de topoppervlakte-invulling. Gebruik van een lagere waarde " "kan de kwaliteit van de bovenlaag verbeteren." +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5996,22 +6479,6 @@ msgstr "" "Dit is de hoogte van de eerste laag. Door de hoogte van de eerste laag hoger " "te maken, kan de hechting op het printbed worden verbeterd." -msgid "Adaptive layer height" -msgstr "Adaptieve laaghoogte" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Als u deze optie inschakelt, betekent dit dat de hoogte van elke laag, " -"behalve die van de eerste laag, automatisch wordt berekend op basis van de " -"helling van het oppervlak van het model.\n" -"Houd er rekening mee dat deze optie alleen van kracht is als er geen prime-" -"toren is gegenereerd op het huidige printbed." - msgid "Speed of initial layer except the solid infill part" msgstr "" "Dit is de snelheid voor de eerste laag behalve solide vulling (infill) delen" @@ -6125,6 +6592,17 @@ msgstr "Roestvrij staal" msgid "Brass" msgstr "Messing" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "" "Schakel deze optie in als de machine een ventilator voor de enclosure heeft" @@ -6488,9 +6966,6 @@ msgstr "" "Het object wordt verhoogd met dit aantal support lagen. Gebruik deze functie " "om kromtrekken te voorkomen bij het afdrukken met ABS." -msgid "Resolution" -msgstr "Resolutie" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6656,9 +7131,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6683,6 +7155,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Support inschakelen" @@ -6706,11 +7195,11 @@ msgstr "tree(auto)" msgid "hybrid(auto)" msgstr "Hybride (automatisch)" -msgid "normal" -msgstr "Normaal" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "tree" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Support/object XY afstand" @@ -6747,12 +7236,16 @@ msgid "The z gap between the top support interface and object" msgstr "" "Dit bepaald de Z-afstand tussen de bovenste support interfaces en het object." -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filament om randen (skirt) en support te printen. Indien u kiest voor 0 dan " -"is er geen specifiek filament en wordt het huidige filament gebruikt" msgid "Line width of support" msgstr "Lijn dikte van support" @@ -6767,11 +7260,9 @@ msgstr "" "uitgeschakeld." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Filament om support te printen. Indien u kiest voor 0 dan is er geen " -"specifiek filament en wordt het huidige filament gebruikt" msgid "Top interface layers" msgstr "Bovenste interface lagen" @@ -6827,6 +7318,12 @@ msgstr "Basis patroon afstand" msgid "Spacing between support lines" msgstr "Dit bepaald de ruimte tussen de support lijnen." +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Dit is de snelheid voor het printen van support." @@ -6887,16 +7384,6 @@ msgstr "Tree support wand lussen" msgid "This setting specify the count of walls around tree support" msgstr "Deze instelling specificeert het aantal wanden rond de tree support." -msgid "Tree support with infill" -msgstr "Tree support met vulling" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"Deze instelling geeft aan of er opvulling moet worden toegevoegd in grote " -"holtes van de tree support." - msgid "Nozzle temperature for layers after the initial one" msgstr "Nozzle temperatuur voor de lagen na de eerstse laag" @@ -7005,6 +7492,14 @@ msgstr "" msgid "Purging volumes" msgstr "Volumes opschonen" +msgid "Flush multiplier" +msgstr "Flush-vermenigvuldiger" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Prime-volume" @@ -7019,41 +7514,24 @@ msgstr "Breedte" msgid "Width of prime tower" msgstr "Dit is de breedte van de prime toren." -msgid "Flush into objects' infill" -msgstr "Flush in de opvulling van objecten" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"Het wisselen van filament wordt uitgevoerd in de vulling van objecten. Dit " -"kan de hoeveelheid afval verminderen en de print tijd verkorten. Let op: " -"indien de wanden zijn geprint met transparant filament, is de vulling met " -"gemengde kleuren zichtbaar." - -msgid "Flush into objects' support" -msgstr "Flush in de support van objecten" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"Het wisselen van filament vindt plaats in de support van objecten. Dit kan " -"de hoeveelheid afval verminderen en de print tijd verkorten." - -msgid "Flush into this object" -msgstr "Flush in dit object" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"Dit object wordt gebruikt om de nozzle te reinigen na een filamentwissel om " -"filament te besparen en de print tijd te verkorten. De kleuren van de " -"objecten worden gemengd als resultaat" msgid "X-Y hole compensation" msgstr "X-Y-gaten compensatie" @@ -7082,6 +7560,79 @@ msgstr "" "negatieve waarden maken contouren kleiner. Deze functie wordt gebruikt om de " "afmetingen enigszins aan te passen wanneer objecten montageproblemen hebben." +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Detecteer dichte interne solide vulling (infill)" @@ -7101,12 +7652,30 @@ msgstr "Exporteer 3mf" msgid "Export project as 3MF." msgstr "Dit exporteert het project als 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 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 "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Model informatie weergeven" @@ -7119,6 +7688,12 @@ msgstr "Exporteer instellingen" msgid "Export settings to a file." msgstr "Exporteer instellingen naar een bestand" +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Rangschik opties" @@ -7134,12 +7709,6 @@ msgstr "Converteer de eenheden van het model" msgid "Orient the model" msgstr "Oriënteer het model" -msgid "Repair" -msgstr "Repareren" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Repareer de meshes van het model als ze niet-manifold zijn." - msgid "Scale the model by a float factor" msgstr "Schaal het model met een float-factor" @@ -7214,9 +7783,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Slicing mesh" -msgid " Object:" -msgstr "Object" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Support: toolpad genereren op laag %d" @@ -7412,33 +7978,73 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Getekende delen wissen" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Selecteer pen formaat" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Rotatie:" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Hoogte:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Kies een of meer bestanden (3mf/step/stl/obj/amf):" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "Het initialiseren is mislukt [%d]!" +#~ msgid "Finish" +#~ msgstr "Klaar" -#~ msgid "Management" -#~ msgstr "Management" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Importeer 3MF/STL/STEP/OBJ/AMF" -#~ msgid "Open" -#~ msgstr "Open" +#~ msgid "Part Cooling" +#~ msgstr "Koeling van de printkop" + +#~ msgid "Aux Cooling" +#~ msgstr "Extra koeling" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" #~ msgstr "" -#~ "%1% bevindt zich te dicht bij een uitgesloten gebied, er zullen botsingen " -#~ "optreden tijdens het printen." +#~ "Filament om randen (skirt) en support te printen. Indien u kiest voor 0 " +#~ "dan is er geen specifiek filament en wordt het huidige filament gebruikt" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Filament om support te printen. Indien u kiest voor 0 dan is er geen " +#~ "specifiek filament en wordt het huidige filament gebruikt" + +#~ msgid "Repair" +#~ msgstr "Repareren" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "Repareer de meshes van het model als ze niet-manifold zijn." + +#~ msgid "Monitoring Recording" +#~ msgstr "Monitoring en opname" + +#~ msgid "Tree support with infill" +#~ msgstr "Tree support met vulling" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Deze instelling geeft aan of er opvulling moet worden toegevoegd in grote " +#~ "holtes van de tree support." #~ msgid "" #~ "\n" @@ -7449,79 +8055,19 @@ msgstr "" #~ "%1% bevindt zich te dicht bij een uitgesloten gebied, er kunnen botsingen " #~ "optreden tijdens het printen." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr "" -#~ " bevindt zich te dichtbij andere objecten, er zullen botsingen optreden " -#~ "tijdens het printen.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." #~ msgstr "" -#~ " komt te dichtbij het uitgesloten gebied, er zullen botsingen optreden " -#~ "tijdens het printen.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Vermijd wanden tijdens het verplaatsen" - -#~ msgid "Max travel detour distance" -#~ msgstr "Maximale afstand voor printpad omleiding" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Maximale omleidingsafstand om beweging over muren te vermijden. Als de " -#~ "afstand groter is dan deze waarde, is er geen omleiding." - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Hoogte van de spelingsruimte rond de printkop: wordt gebruikt als invoer " -#~ "voor automatisch rangschikken om botsingen te voorkomen bij object voor " -#~ "object printen." - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Vrije ruimte rond de printkop: deze wordt gebruikt als invoer voor " -#~ "automatisch rangschikken om botsingen te voorkomen bij het afdrukken van " -#~ "object voor object" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Fout op laag %1%:\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Aantal driehoeken verkleinen (vereenvoudigen)" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "Overschakelen naar zigzagpatroon?\n" -#~ "Ja - Automatisch overschakelen naar zigzagpatroon\n" -#~ "Nee - Reset vulling automatisch naar de standaard niet-100% waarde\n" - -#~ msgid "Extruder position" -#~ msgstr "Positie van de extruder" - -#~ msgid "Zig zag" -#~ msgstr "Zig-zag" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "De bedtemperatuur is hoger dan de verglazingstemperatuur van dit " -#~ "filament. Hierdoor kan de nozzle verstopt raken en kan het printen " -#~ "mislukken" +#~ "%1% bevindt zich te dicht bij een uitgesloten gebied, er zullen botsingen " +#~ "optreden tijdens het printen." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Adaptieve laaghoogte" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." @@ -7542,9 +8088,35 @@ msgstr "" #~ "deze georiënteert. Anders worden alle objecten op de huidige project " #~ "georiënteert." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Vermijd wanden tijdens het verplaatsen" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "De bedtemperatuur is hoger dan de verglazingstemperatuur van dit " +#~ "filament. Hierdoor kan de nozzle verstopt raken en kan het printen " +#~ "mislukken" + #~ msgid "Clear all" #~ msgstr "Alles wissen" +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Vrije ruimte rond de printkop: deze wordt gebruikt als invoer voor " +#~ "automatisch rangschikken om botsingen te voorkomen bij het afdrukken van " +#~ "object voor object" + +#~ msgid "Color Print" +#~ msgstr "Kleuren print" + +#~ msgid "Comsumption" +#~ msgstr "Verbruik" + #~ msgid "Creating" #~ msgstr "Bezig met creëren" @@ -7592,12 +8164,52 @@ msgstr "" #~ "Dit schakelt terugtrekken (retraction) uit wanneer reizen volledig binnen " #~ "een opvulgebied is en het druppelen uit de nozzle niet kan worden gezien." +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Als u deze optie inschakelt, betekent dit dat de hoogte van elke laag, " +#~ "behalve die van de eerste laag, automatisch wordt berekend op basis van " +#~ "de helling van het oppervlak van het model.\n" +#~ "Houd er rekening mee dat deze optie alleen van kracht is als er geen " +#~ "prime-toren is gegenereerd op het huidige printbed." + #~ msgid "Enter a search term" #~ msgstr "Voer een zoekterm in" +#~ msgid "Erase painting" +#~ msgstr "Getekende delen wissen" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Fout op laag %1%:\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Exporteer het \"sliced\" bestand" + +#~ msgid "Export current Sliced file" +#~ msgstr "Exporteer het huidig \"sliced\" bestand" + +#~ msgid "Export ok." +#~ msgstr "Exporteren ok" + +#~ msgid "Export sliced file" +#~ msgstr "Exporteer het \"sliced\" bestand" + +#~ msgid "Extruder position" +#~ msgstr "Positie van de extruder" + #~ msgid "Failed" #~ msgstr "Mislukt" +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" + #~ msgid "Filaments Selection" #~ msgstr "Filaments selectie" @@ -7610,6 +8222,17 @@ msgstr "" #~ msgid "Fix model through cloud" #~ msgstr "Repareer model in de cloud" +#~ msgid "Flushed filament" +#~ msgstr "Flushed filament" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Forceer de snelheid van de koelventilator wanneer de overhanggraad van " +#~ "het onderdeel deze waarde overschrijdt. Uitgedrukt als percentage " + #~ msgid "Fragment Filter" #~ msgstr "Fragmentfilter" @@ -7624,12 +8247,26 @@ msgstr "" #~ "temperature" #~ msgstr "Nozzle opwarmen tot doel temperatuur" +#~ msgid "Height:" +#~ msgstr "Hoogte:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Hoogte van de spelingsruimte rond de printkop: wordt gebruikt als invoer " +#~ "voor automatisch rangschikken om botsingen te voorkomen bij object voor " +#~ "object printen." + #~ msgid "In the calibration of extrusion flow" #~ msgstr "Bij de kalibratie van de extrusieflow" #~ msgid "In the calibration of laser scanner" #~ msgstr "Bij de kalibratie van laserscanner" +#~ msgid "Initialize failed [%d]!" +#~ msgstr "Het initialiseren is mislukt [%d]!" + #~ msgid "Inner wall speed" #~ msgstr "Binnenste wand snelheid" @@ -7643,12 +8280,34 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Lijn-type" +#~ msgid "Management" +#~ msgstr "Management" + +#~ msgid "Max travel detour distance" +#~ msgstr "Maximale afstand voor printpad omleiding" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Maximale omleidingsafstand om beweging over muren te vermijden. Als de " +#~ "afstand groter is dan deze waarde, is er geen omleiding." + #~ msgid "Module" #~ msgstr "Module" #~ msgid "Monitoring" #~ msgstr "Monitoren" +#~ msgid "Open" +#~ msgstr "Open" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "Open &PrusaSlicer" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "Open PrusaSlicer" + #~ msgid "Output file" #~ msgstr "Bestand weergeven" @@ -7664,6 +8323,9 @@ msgstr "" #~ msgid "Per object edit" #~ msgstr "Instellingen per object" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "Printbed %d: %s onderstand filament %s niet.\n" + #~ msgid "Please fill report first." #~ msgstr "Gelieve eerst het rapport in te vullen." @@ -7686,6 +8348,24 @@ msgstr "" #~ msgid "Printer Selection" #~ msgstr "Printer selectie" +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "Het wisselen van filament wordt uitgevoerd in de vulling van objecten. " +#~ "Dit kan de hoeveelheid afval verminderen en de print tijd verkorten. Let " +#~ "op: indien de wanden zijn geprint met transparant filament, is de vulling " +#~ "met gemengde kleuren zichtbaar." + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "Het wisselen van filament vindt plaats in de support van objecten. Dit " +#~ "kan de hoeveelheid afval verminderen en de print tijd verkorten." + #~ msgid "" #~ "Push new filament \n" #~ "into extruder" @@ -7702,15 +8382,30 @@ msgstr "" #~ "then a snapshot is taken with the chamber camera. When printing finishes, " #~ "a timelapse video is created from all the snapshots." +#~ msgid "Reduce Triangles" +#~ msgstr "Aantal driehoeken verkleinen (vereenvoudigen)" + +#~ msgid "Reload item" +#~ msgstr "Onderdeel opnieuw laden" + +#~ msgid "Reload items" +#~ msgstr "Onderdelen opnieuw laden" + #~ msgid "Report" #~ msgstr "Rapport" +#~ msgid "Rotation:" +#~ msgstr "Rotatie:" + #~ msgid "Save configuration as:" #~ msgstr "Bewaar configuratie als:" #~ msgid "Sending" #~ msgstr "Verzenden" +#~ msgid "Set pen size" +#~ msgstr "Selecteer pen formaat" + #~ msgid "Shift + Any arrow" #~ msgstr "Shift + willekeurige pijl" @@ -7743,6 +8438,15 @@ msgstr "" #~ "filament wisselingen veroorzaken indien support is gespecificeerd als een " #~ "andere extruder dan het object" +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "Overschakelen naar zigzagpatroon?\n" +#~ "Ja - Automatisch overschakelen naar zigzagpatroon\n" +#~ "Nee - Reset vulling automatisch naar de standaard niet-100% waarde\n" + #~ msgid "Swith cloud environment, Please login again!" #~ msgstr "De cloud omgeving is aangepast. Log opnieuw in aub." @@ -7765,6 +8469,25 @@ msgstr "" #~ "heeft geprobeerd om het te repareren, maar misschien wilt u de resultaten " #~ "controleren of het invoerbestand repareren en het opnieuw proberen." +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Dit object wordt gebruikt om de nozzle te reinigen na een filamentwissel " +#~ "om filament te besparen en de print tijd te verkorten. De kleuren van de " +#~ "objecten worden gemengd als resultaat" + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Deze instelling staat voor het volume filament dat per seconde kan worden " +#~ "gesmolten en geëxtrudeerd. De printsnelheid wordt beperkt door de " +#~ "maximale volumetrische snelheid in het geval van een te hoge en " +#~ "onredelijke snelheidsinstelling. 0 betekent geen limiet." + #~ msgid "Timelapse Wipe Tower" #~ msgstr "Timelapse Wipe Tower" @@ -7783,7 +8506,38 @@ msgstr "" #~ msgid "Waiting" #~ msgstr "Wachten" +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "U hebt enkele voorinstellingen gewijzigd.\n" +#~ "Wilt u deze gewijzigde instellingen behouden na het wisselen van " +#~ "voorinstelling?" + +#~ msgid "Zig zag" +#~ msgstr "Zig-zag" + +#~ msgid " Object:" +#~ msgstr "Object" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr "" +#~ " komt te dichtbij het uitgesloten gebied, er zullen botsingen optreden " +#~ "tijdens het printen.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr "" +#~ " bevindt zich te dichtbij andere objecten, er zullen botsingen optreden " +#~ "tijdens het printen.\n" + +#~ msgid "normal" +#~ msgstr "Normaal" + #~ msgid "the 3mf is not compatible, load geometry data only!" #~ msgstr "" #~ "Het 3mf bestand is niet compatibel, enkel de geometrische data wordt " #~ "geladen!" + +#~ msgid "tree" +#~ msgstr "tree" diff --git a/bbl/i18n/sv/BambuStudio_sv.po b/bbl/i18n/sv/BambuStudio_sv.po index e5bc351984..49046d80cf 100644 --- a/bbl/i18n/sv/BambuStudio_sv.po +++ b/bbl/i18n/sv/BambuStudio_sv.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Bambu Studio\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -22,6 +22,9 @@ msgstr "Alt + mushjul" msgid "Section view" msgstr "Sektionsvy" +msgid "Reset direction" +msgstr "" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + Mushjul" @@ -67,6 +70,9 @@ msgstr "Verktygs typ" msgid "Smart fill angle" msgstr "Smart fyllningsvinkel" +msgid "On overhangs only" +msgstr "" + msgid "Auto support threshold angle: " msgstr "Automatisk support tröskelsvinkel: " @@ -82,6 +88,10 @@ msgstr "Fyll" msgid "Gap Fill" msgstr "" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "" + msgid "Highlight faces according to overhang angle." msgstr "Markera ytor enligt överhängs vinkeln." @@ -139,6 +149,12 @@ msgstr "Hinkfyllning" msgid "Height range" msgstr "Höjd intervall" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "" + msgid "Shortcut Key " msgstr "Snabbkommando " @@ -334,9 +350,6 @@ msgstr "Ansiktsigenkänning" msgid "Perform Recognition" msgstr "Utför igenkänning" -msgid "Reset direction" -msgstr "" - msgid "Brush size" msgstr "" @@ -355,15 +368,6 @@ msgstr "" msgid "Remove selection" msgstr "" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "" @@ -508,8 +512,8 @@ msgstr "Laddar modell vy" msgid "Choose one file (3mf):" msgstr "Välj en fil (3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "Välj en eller flera filer (3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "Välj en fil (.gcode/.gco/.g/.ngc/ngc):" @@ -592,6 +596,9 @@ msgstr "Ifyllnad" msgid "Support" msgstr "Support" +msgid "Flush options" +msgstr "Rensnings alternativ" + msgid "Speed" msgstr "Hastighet" @@ -725,6 +732,18 @@ msgstr "Skala till bygg volymen" msgid "Scale an object to fit the build volume" msgstr "Anpassa skalning av ett objekt till byggvolymen" +msgid "Flush Options" +msgstr "" + +msgid "Flush into objects' infill" +msgstr "Rensa in i föremålens ifyllnad" + +msgid "Flush into this object" +msgstr "Rensa in i det här objektet" + +msgid "Flush into objects' support" +msgstr "Rensa in i objektets support" + msgid "Convert from inch" msgstr "Konvertera ifrån inch" @@ -776,6 +795,9 @@ msgstr "Spegelvänd objektet" msgid "Add Primitive" msgstr "Lägg till Primitiv" +msgid "Show Labels" +msgstr "" + msgid "To objects" msgstr "Till objekten" @@ -842,6 +864,9 @@ msgstr "" msgid "Center" msgstr "" +msgid "Edit Process Settings" +msgstr "" + msgid "Edit in Parameter Table" msgstr "" @@ -929,6 +954,14 @@ msgstr "Allmän" msgid "Add Modifier" msgstr "Lägg till Modifierare" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "Ändra till per objekt inställningsläge till redigerings inställningar." + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "" + msgid "Deleting the last solid part is not allowed." msgstr "Ej tillåtet att radera den senaste fasta delen." @@ -1079,6 +1112,9 @@ msgstr "Mer" msgid "Open Preferences." msgstr "" +msgid "Open next tip." +msgstr "" + msgid "Open Documentation in web browser." msgstr "" @@ -1091,6 +1127,15 @@ msgstr "" msgid "OK" msgstr "OK" +msgid "Jump to layer" +msgstr "" + +msgid "Please enter the layer number" +msgstr "" + +msgid "Jump to Layer" +msgstr "" + msgid "Add Pause" msgstr "" @@ -1112,7 +1157,7 @@ msgstr "" msgid "No printer" msgstr "Ingen skrivare" -msgid "Heat the nozzle to target temperature" +msgid "Heat the nozzle" msgstr "" msgid "Cut filament" @@ -1322,12 +1367,34 @@ msgid "Sending print configuration" msgstr "Skicka utskrifts konfiguration" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "" msgid "An SD card needs to be inserted before printing via LAN." msgstr "" +msgid "Send to Printer failed. Please try again." +msgstr "" + +msgid "Sending gcode file over LAN" +msgstr "" + +msgid "Sending gcode file through cloud service" +msgstr "" + +msgid "Sending gcode file to sdcard" +msgstr "" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "" + +msgid "Please log out and login to the printer again." +msgstr "" + msgid "Downloading" msgstr "Laddar ner" @@ -1337,8 +1404,8 @@ msgstr "" msgid "Cancelled" msgstr "" -msgid "Finish" -msgstr "Slutför" +msgid "Install successfully." +msgstr "" msgid "Installing" msgstr "" @@ -1430,6 +1497,9 @@ msgstr "Inmatningsvärdet ska vara större än %1% och mindre än %2%" msgid "SN" msgstr "SN" +msgid "Setting AMS slot information while printing is not supported" +msgstr "" + msgid "Confirm" msgstr "Acceptera" @@ -1455,6 +1525,19 @@ msgstr "" msgid "Print with the filament mounted on the back of chassis" msgstr "" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "" + +msgid "Filament used in this print job" +msgstr "" + +msgid "AMS slot used for this filament" +msgstr "" + +msgid "Click to select AMS slot manually" +msgstr "" + msgid "AMS Settings" msgstr "AMS Inställningar" @@ -1502,6 +1585,23 @@ msgstr "" "AMS kommer inte att automatiskt läsa informationen ifrån imatat filament " "under uppstart och senast använd information kommer att användas." +msgid "Update remaining capacity" +msgstr "" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" + +msgid "AMS auto switch filament" +msgstr "" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "" + msgid "File" msgstr "Fil" @@ -1704,6 +1804,11 @@ msgid "" "circulation or reduce the temperature of the hot bed" msgstr "" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1778,6 +1883,17 @@ msgstr "" "JA -Ändra dessa inställningar och möjliggör Spiral läge automatiskt\n" "NEJ -Avbryt Spiral läge denna gång" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1822,6 +1938,9 @@ msgid "" "Yes - switch to rectilinear pattern automaticlly\n" "No - reset density to default non 100% value automaticlly\n" msgstr "" +"Switch to rectilinear pattern?\n" +"Yes - switch to rectilinear pattern automaticlly\n" +"No - reset density to default non 100% value automaticlly\n" msgid "Auto bed leveling" msgstr "Auto justera byggplattan" @@ -1928,6 +2047,9 @@ msgstr "Uppdatering misslyckades." msgid "Failed to start printing job" msgstr "" +msgid "default" +msgstr "standard" + msgid "parameter name" msgstr "" @@ -1995,6 +2117,12 @@ msgstr "" msgid "Flow: " msgstr "" +msgid "Fan Speed: " +msgstr "" + +msgid "Temperature: " +msgstr "" + msgid "Loading G-codes" msgstr "Laddar G-koder" @@ -2004,6 +2132,9 @@ msgstr "Genererar geometrisk vertex data" msgid "Generating geometry index data" msgstr "Genererar geometrisk index data" +msgid "Display" +msgstr "Visa" + msgid "up to" msgstr "upp till" @@ -2019,14 +2150,11 @@ msgstr "till" msgid "Color Scheme" msgstr "Färgschema" -msgid "Percent" -msgstr "Procent" - msgid "Time" msgstr "Tid" -msgid "Display" -msgstr "Visa" +msgid "Percent" +msgstr "Procent" msgid "Layer Height (mm)" msgstr "Lagerhöjd (mm)" @@ -2049,14 +2177,11 @@ msgstr "Volymetrisk flödeshastighet (mm³/s)" msgid "Used filament" msgstr "Använt filament" -msgid "Filament N XX" -msgstr "Filament N XX" +msgid "Flushed" +msgstr "" -msgid "Color Print" -msgstr "Färg Utskrift" - -msgid "Comsumption" -msgstr "Konsumtion" +msgid "Total" +msgstr "Totalt" msgid "Travel" msgstr "Flytta" @@ -2085,18 +2210,12 @@ msgstr "flytta" msgid "Extruder" msgstr "Extruder" -msgid "Filament 1" -msgstr "Filament 1" - -msgid "Flushed filament" -msgstr "Rensat filament" - -msgid "Total" -msgstr "Totalt" - msgid "Filament change times" msgstr "Filament bytes tider" +msgid "Cost" +msgstr "Kostnad" + msgid "Color change" msgstr "Färg byte" @@ -2115,24 +2234,75 @@ msgstr "Utskrifts inställningar" msgid "Total Estimation" msgstr "Total Uppskattning" +msgid "Time Estimation" +msgstr "" + msgid "Normal mode" msgstr "Normalt läge" -msgid "Cost" -msgstr "Kostnad" - msgid "Prepare time" msgstr "Förbered tid" msgid "Model printing time" msgstr "Utskriftstid för modellen" +msgid "Total time" +msgstr "" + msgid "Switch to silent mode" msgstr "Ändra till tyst läge" msgid "Switch to normal mode" msgstr "Ändra till normal läge" +msgid "Variable layer height" +msgstr "" + +msgid "Adaptive" +msgstr "" + +msgid "Quality / Speed" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Radius" +msgstr "Radie" + +msgid "Keep min" +msgstr "" + +msgid "Left mouse button:" +msgstr "" + +msgid "Add detail" +msgstr "" + +msgid "Right mouse button:" +msgstr "" + +msgid "Remove detail" +msgstr "" + +msgid "Shift + Left mouse button:" +msgstr "" + +msgid "Reset to base" +msgstr "" + +msgid "Shift + Right mouse button:" +msgstr "" + +msgid "Smoothing" +msgstr "" + +msgid "Mouse wheel:" +msgstr "" + +msgid "Increase/decrease edit area" +msgstr "" + msgid "Sequence" msgstr "Sekvens" @@ -2244,6 +2414,18 @@ msgstr "" msgid "Calibration" msgstr "Kalibrering" +msgid "Calibration step selection" +msgstr "" + +msgid "Micro lidar calibration" +msgstr "" + +msgid "Bed leveling" +msgstr "" + +msgid "Resonance frequency identification" +msgstr "" + msgid "Calibration program" msgstr "Kalibrerings program" @@ -2268,11 +2450,23 @@ msgstr "" msgid "Calibrating" msgstr "Kalibrerar" -msgid "Timelapse" -msgstr "Timelapse" +msgid "Auto-record Monitoring" +msgstr "" -msgid "Monitoring Recording" -msgstr "Övervaknings Inspelning" +msgid "Go Live" +msgstr "" + +msgid "Resolution" +msgstr "Upplösning" + +msgid "Show \"Live Video\" guide page." +msgstr "" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" msgid "ConnectPrinter(LAN)" msgstr "Anslut skrivare (LAN)" @@ -2317,6 +2511,15 @@ msgstr "Enhet" msgid "Project" msgstr "Projekt" +msgid "Yes" +msgstr "Ja" + +msgid "No" +msgstr "Nej" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "" + msgid "Slice" msgstr "Bered" @@ -2326,17 +2529,26 @@ msgstr "Bered allt" msgid "Slice plate" msgstr "Bered plattan" -msgid "Print all" -msgstr "Skriv ut allt" - msgid "Export G-code file" msgstr "" -msgid "Export sliced file" -msgstr "Exportera beredd fil" +msgid "Send" +msgstr "Skicka" -msgid "Export Sliced File" -msgstr "Exportera Beredd fil" +msgid "Print plate" +msgstr "" + +msgid "Export plate sliced file" +msgstr "" + +msgid "Export all sliced file" +msgstr "" + +msgid "Print all" +msgstr "Skriv ut allt" + +msgid "Send all" +msgstr "" msgid "Keyboard Shortcuts" msgstr "Kortkommando" @@ -2350,17 +2562,23 @@ msgstr "Installationsguide" msgid "Show Configuration Folder" msgstr "Visa Konfigurations Mapp" +msgid "Show Tip of the Day" +msgstr "" + msgid "Check for Update" msgstr "Sök efter Uppdatering" +msgid "Open Network Test" +msgstr "" + #, c-format, boost-format msgid "&About %s" msgstr "&Om %s" -msgid "Show Tip of the Day" +msgid "Upload Models" msgstr "" -msgid "Open Network Test" +msgid "Download Models" msgstr "" msgid "Default View" @@ -2431,8 +2649,8 @@ msgstr "Spara Projekt som" msgid "Save current project as" msgstr "Spara nuvarande projekt som" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "Importera 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "" msgid "Load a model" msgstr "Ladda modell" @@ -2455,8 +2673,11 @@ msgstr "Exportera generisk 3mf" msgid "Export 3mf file without using some 3mf-extensions" msgstr "Exportera 3mf fil utan några 3mf-tillägg" -msgid "Export current Sliced file" -msgstr "Exportera nuvarande Beredda fil" +msgid "Export current sliced file" +msgstr "" + +msgid "Export all plate sliced file" +msgstr "" msgid "Export G-code" msgstr "Exportera G-kod" @@ -2548,6 +2769,9 @@ msgstr "Vy" msgid "Help" msgstr "Hjälp" +msgid "3D Models" +msgstr "" + msgid "&Open G-code" msgstr "&Öppna G-kod" @@ -2566,11 +2790,11 @@ msgstr "Exportera &Toolpaths som OBJ" msgid "Export toolpaths as OBJ" msgstr "Exportera toolpaths som OBJ" -msgid "Open &PrusaSlicer" -msgstr "Öppna &PrusaSlicer" +msgid "Open &Studio" +msgstr "" -msgid "Open PrusaSlicer" -msgstr "Öppna PrusaSlicer" +msgid "Open Studio" +msgstr "" msgid "&Quit" msgstr "&Avsluta" @@ -2660,7 +2884,10 @@ msgstr "" msgid "Initialize failed (Not accessible in LAN-only mode)!" msgstr "" -msgid "Initialize failed (Not supported without remote video tunnel)!" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "" + +msgid "Initialize failed (Not supported by printer)!" msgstr "" #, c-format, boost-format @@ -2677,6 +2904,27 @@ msgstr "" msgid "Stopped." msgstr "Avbruten." +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "" + +msgid "Downloading Virtual Camera Tools" +msgstr "" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "" + +msgid "Information" +msgstr "" + msgid "Playing..." msgstr "Spelar..." @@ -2702,6 +2950,9 @@ msgstr "" msgid "Show all files, recent first." msgstr "" +msgid "Timelapse" +msgstr "Timelapse" + msgid "Switch to timelapse files." msgstr "" @@ -2729,7 +2980,7 @@ msgstr "" msgid "No printers." msgstr "Ingen printer." -msgid "Not supported." +msgid "Not supported by this model of printer!" msgstr "" msgid "Connecting..." @@ -2737,7 +2988,7 @@ msgstr "Sammankopplar..." #, c-format, boost-format msgid "Connect failed [%d]!" -msgstr "" +msgstr "Sammankoppling misslyckades [%d]" msgid "Loading file list..." msgstr "Laddar fil lista..." @@ -2745,6 +2996,12 @@ msgstr "Laddar fil lista..." msgid "No files" msgstr "Inga filer" +msgid "Not accessible in LAN-only mode!" +msgstr "" + +msgid "Missing LAN ip of printer!" +msgstr "" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "" @@ -2789,6 +3046,12 @@ msgstr "Byta Y/Z axes" msgid "Camera" msgstr "" +msgid "SD Card" +msgstr "" + +msgid "Camera Setting" +msgstr "" + msgid "Printing Progress" msgstr "Utskriftsförlopp" @@ -2816,11 +3079,11 @@ msgstr "100%" msgid "Lamp" msgstr "Lampa" -msgid "Part Cooling" -msgstr "Del Kylning" +msgid "Aux" +msgstr "" -msgid "Aux Cooling" -msgstr "Extra Kylning" +msgid "Cham" +msgstr "" msgid "Bed" msgstr "Byggplattan" @@ -2831,6 +3094,12 @@ msgstr "Mata ut" msgid "Debug Info" msgstr "Felsöknings Information" +msgid "No SD Card" +msgstr "" + +msgid "SD Card Abnormal" +msgstr "" + msgid "Printing List" msgstr "Utskrifts Lista" @@ -2840,9 +3109,38 @@ msgstr "" msgid "Are you sure you want to cancel this print?" msgstr "" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" + msgid "Downloading..." msgstr "Laddar ner..." +msgid "Cloud Slicing..." +msgstr "" + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "" + +msgid "Still unload" +msgstr "" + +msgid "Still load" +msgstr "" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "" + msgid "This only takes effect during printing" msgstr "" @@ -2858,6 +3156,9 @@ msgstr "Sport" msgid "Ludicrous" msgstr "Galet" +msgid "Can't start this without SD card." +msgstr "" + msgid "Failed to connect to the server" msgstr "Uppkoppling till servern misslyckades" @@ -2876,11 +3177,8 @@ msgstr "HMS" msgid "Failed to connect to the printer" msgstr "Uppkoppling till printern misslyckades" -msgid "Yes" -msgstr "Ja" - -msgid "No" -msgstr "Nej" +msgid "Don't show again" +msgstr "Visa inte igen" #, c-format, boost-format msgid "%s error" @@ -2984,8 +3282,8 @@ msgstr "Fel:" msgid "Warning:" msgstr "Varning:" -msgid "Export ok." -msgstr "Exportering OK." +msgid "Export successfully." +msgstr "" msgid " (Repair)" msgstr " (Reparera)" @@ -3014,9 +3312,6 @@ msgstr "Lager" msgid "Range" msgstr "Räckvidd" -msgid "default" -msgstr "standard" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3048,20 +3343,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "Bottenlager" -msgid "Spaghetti and Excess Chute Pileup Detection" +msgid "Enable AI monitoring of printing" msgstr "" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +msgid "Sensitivity of pausing is" +msgstr "" + +msgid "Enable detection of build plate position" +msgstr "" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." msgstr "" msgid "First Layer Inspection" msgstr "" -msgid "Switch to per-object setting mode to edit modifier settings." -msgstr "Ändra till per objekt inställningsläge till redigerings inställningar." - -msgid "Don't show again" -msgstr "Visa inte igen" +msgid "Auto-recovery from step loss" +msgstr "" msgid "Global" msgstr "Global" @@ -3130,7 +3430,7 @@ msgstr "" msgid "Remove last filament" msgstr "" -msgid "Sync material list from AMS" +msgid "Synchronize filament list from AMS" msgstr "" msgid "Set filaments to use" @@ -3151,6 +3451,12 @@ msgstr "" msgid "There are no compatible filaments, and sync is not performed." msgstr "" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" + msgid "Untitled" msgstr "Ej namngiven" @@ -3179,6 +3485,12 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" + #, c-format, boost-format msgid "Loading file: %s" msgstr "Laddar fil: %s" @@ -3290,9 +3602,6 @@ msgstr "Det valda objektet kan inte delas." msgid "Another export job is running." msgstr "En annan exportering pågår." -msgid "Another export job is currently running." -msgstr "" - msgid "Select a new file" msgstr "" @@ -3317,6 +3626,9 @@ msgstr "varningar" msgid "Invalid data" msgstr "Ogiltlig data" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "Bereder plattan %d" @@ -3343,6 +3655,28 @@ msgstr "Skapar nytt projekt" msgid "Load project" msgstr "Ladda projekt" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "" + +msgid "Save project" +msgstr "" + +msgid "Importing Model" +msgstr "" + +msgid "prepare 3mf file..." +msgstr "" + +msgid "downloading project ..." +msgstr "" + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "" + msgid "The selected file" msgstr "Den valda filen" @@ -3400,6 +3734,12 @@ msgstr "Spara G-kod som:" msgid "Save Sliced file as:" msgstr "Spara beredningen som:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3419,6 +3759,9 @@ msgstr "Custom support och färgläggning raderades innan reparation." msgid "Invalid number" msgstr "Ogiltligt nummer" +msgid "Select Bed Type" +msgstr "" + #, boost-format msgid "Part name: %1%\n" msgstr "Delens namn: %1%\n" @@ -3447,6 +3790,18 @@ msgstr "Volym: %1% mm³\n" msgid "Triangles: %1%\n" msgstr "Trianglar: %1%\n" +msgid "Tips:" +msgstr "" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "" + msgid "Switching the language requires application restart.\n" msgstr "Byte av språk krävs för omstart.\n" @@ -3557,6 +3912,12 @@ msgstr "Säkerhetskopierings intervall" msgid "Downloads" msgstr "" +msgid "Dark Mode" +msgstr "" + +msgid "Enable Dark mode" +msgstr "" + msgid "Home page and daily tips" msgstr "Hemsida och dagliga förslag" @@ -3668,6 +4029,15 @@ msgstr "Redigera förinställningar" msgid "Project-inside presets" msgstr "Projekt förinställningar" +msgid "Add/Remove filaments" +msgstr "" + +msgid "Add/Remove materials" +msgstr "" + +msgid "Add/Remove printers" +msgstr "" + msgid "Slice all plate to obtain time and filament estimation" msgstr "Bered alla plattor för att mottaga tid och filament uppskattning" @@ -3821,9 +4191,6 @@ msgstr "Justering av Byggplattan" msgid "Flow Calibration" msgstr "Flödes Kalibrering" -msgid "Send" -msgstr "Skicka" - msgid "send completed" msgstr "Skicka komplett" @@ -3839,8 +4206,8 @@ msgstr "Synkroniserar enhetsinformation" msgid "Synchronizing device information time out" msgstr "Time-out för synkronisering av enhetsinformation" -msgid "Cannot send the print task when the upgrade is in progress" -msgstr "Det går inte att skicka utskriftsuppgiften när uppgraderingen pågår" +msgid "Cannot send the print job when the printer is updating firmware" +msgstr "" msgid "" "The printer is executing instructions. Please restart printing after it ends" @@ -3895,10 +4262,23 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "" -msgid "Please check the following infomation:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "" + +msgid "Cannot send the print job for empty plate" +msgstr "" + +msgid "Errors" +msgstr "" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" msgstr "" msgid "" @@ -3907,18 +4287,49 @@ msgid "" "selecting the same printer type.\n" msgstr "" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 "" + msgid "Preparing print job" msgstr "Förbereder utskriftsjobb" msgid "Modifying the device name" msgstr "Ändra enhetens namn" -msgid "Send to Printer" +msgid "Send to Printer SD card" msgstr "" +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "Det går inte att skicka utskriftsuppgiften när uppgraderingen pågår" + msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "" +msgid "The printer does not support sending to printer SD card." +msgstr "" + +msgid "Same as Global Bed Type" +msgstr "" + +msgid "Cool Plate" +msgstr "Cool Plate" + +msgid "Engineering Plate" +msgstr "Engineering Plate" + +msgid "High Temp Plate" +msgstr "High Temp Plate" + +msgid "Textured PEI Plate" +msgstr "" + msgid "Log in printer" msgstr "Logga in skrivare" @@ -3958,13 +4369,13 @@ msgid "Click to reset all settings to the last saved preset." msgstr "" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" msgid "" @@ -3983,6 +4394,9 @@ msgstr "Söm" msgid "Precision" msgstr "Precision" +msgid "Wall generator" +msgstr "" + msgid "Walls" msgstr "Väggar" @@ -4013,15 +4427,15 @@ msgstr "Förflyttnings hastighet" msgid "Acceleration" msgstr "Acceleration" +msgid "Raft" +msgstr "" + msgid "Support filament" msgstr "Support filament" msgid "Prime tower" msgstr "Prime torn" -msgid "Flush options" -msgstr "Rensnings alternativ" - msgid "Special mode" msgstr "Special läge" @@ -4045,7 +4459,7 @@ msgstr[0] "" "Radera den, annars påverkas G-kodens visualisering och den uppskattade " "utskriftstiden." msgstr[1] "" -"@Följande linjer %s innehåller reserverade nyckelord.\n" +"Följande linjer %s innehåller reserverade nyckelord.\n" "Radera dem, annars påverkas G-kodens visualisering och den uppskattade " "utskriftstiden." @@ -4101,9 +4515,6 @@ msgstr "" "Detta är byggplattans temperatur när Engineering Plate är installerad. Ett " "värde på 0 betyder att filamentet inte stöder utskrift på Engineering Plate." -msgid "High Temp Plate" -msgstr "High Temp Plate" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" @@ -4111,9 +4522,6 @@ msgstr "" "Detta är byggplattans temperatur när High Temp Plate är installerad. Värdet " "0 betyder att filamentet inte stöder utskrift på High Temp Plate." -msgid "Textured PEI Plate" -msgstr "" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4335,12 +4743,18 @@ msgstr "" "Förinställningen \"%1%\" är inte kompatibel med den nya process profilen och " "innehåller följande osparade ändringar:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" msgstr "" -"Förinställningarna har ändrats. \n" -"Behålla dessa ändrade inställningar efter byte av förinställningar?" msgid "Extruders count" msgstr "Extruder kalkylering" @@ -4351,6 +4765,11 @@ msgstr "Allmän" msgid "Capabilities" msgstr "Förmågor" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "" + msgid "Show all presets (including incompatible)" msgstr "" @@ -4436,17 +4855,28 @@ msgstr "Inga uppdateringar tillgängliga." msgid "The configuration is up to date." msgstr "Konfigurationen är aktuell." -msgid "Auto-Calc" -msgstr "Autoberäkna" - msgid "Flushing volumes for filament change" msgstr "Rensnings volym för filament byte" +msgid "Auto-Calc" +msgstr "Autoberäkna" + msgid "Flushing volume (mm³) for each filament pair." msgstr "Rensnings volym (mm³) för varje filament." -msgid "Flush multiplier" -msgstr "Rensnings multiplikator" +msgid "Multiplier" +msgstr "" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "" msgid "unloaded" msgstr "utmatad" @@ -4721,7 +5151,7 @@ msgstr "" msgid "Version:" msgstr "" -msgid "Upgrade firmware" +msgid "Update firmware" msgstr "" msgid "Printing" @@ -4733,13 +5163,13 @@ msgstr "" msgid "Latest version" msgstr "" -msgid "Upgrading" +msgid "Updating" msgstr "" -msgid "Upgrading failed" +msgid "Updating failed" msgstr "" -msgid "Upgrading successful" +msgid "Updating successful" msgstr "" msgid "" @@ -4759,6 +5189,9 @@ msgid "" "update next time starting the studio." msgstr "" +msgid "Extension Board" +msgstr "" + msgid "Saving objects into the 3mf failed." msgstr "Sparande av objektet till 3mf misslyckades." @@ -5002,12 +5435,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "%1% är för nära andra och kan orsaka kollisioner." @@ -5017,11 +5444,13 @@ msgid "%1% is too tall, and collisions will be caused." msgstr "%1% är för hög, och kollisioner kommer att uppstå." msgid " is too close to others, there may be collisions when printing.\n" -msgstr "" +msgstr " is too close to others, there may be collisions when printing.\n" msgid "" " is too close to exclusion area, there may be collisions when printing.\n" msgstr "" +" is too close to exclusion area, there may be collisions when printing.\n" +"\n" msgid "Prime Tower" msgstr "Prime Torn" @@ -5091,6 +5520,11 @@ msgid "" "heights." msgstr "Ett Prime Torn kräver att alla object är beredda med samma lagerhöjd." +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "" + msgid "Too small line width" msgstr "För liten linjebredd" @@ -5110,8 +5544,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "Lagerhöjden kan inte överstiga nozzel diametern" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "Plattan %d: %s stöds ej av filament %s.\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "" msgid "Generating skirt & brim" msgstr "Skapar Skirt & Brim" @@ -5137,6 +5571,12 @@ msgid "" "polygon by points in following format: \"XxY, XxY, ...\"" msgstr "" +msgid "Bed custom texture" +msgstr "" + +msgid "Bed custom model" +msgstr "" + msgid "Elephant foot compensation" msgstr "Elefant fots kompensation" @@ -5310,12 +5750,6 @@ msgstr "" msgid "Bed types supported by the printer" msgstr "Byggplattans typ stöds av skrivaren" -msgid "Cool Plate" -msgstr "Cool Plate" - -msgid "Engineering Plate" -msgstr "Engineering Plate" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "Denna G-kod används för varje lager innan Z axis lyfts" @@ -5372,13 +5806,22 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "Överhängs kylningens tröskel" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" +msgstr "" + +msgid "Bridge direction" +msgstr "" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." msgstr "" -"Tvinga kylfläktens hastighet när överhängsgraderna överstiger detta värde. " -"Uttryckt i procent som indikerar linjebredden utan stöd från lägre lager" msgid "Bridge flow" msgstr "Bridge/Brygg flöde" @@ -5444,6 +5887,9 @@ msgstr "" msgid "Compatible machine" msgstr "Kompatibel maskin" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "Kompatibel maskin status" @@ -5531,9 +5977,6 @@ msgstr "" msgid "Thick bridges" msgstr "" -msgid "Layers and Perimeters" -msgstr "" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5561,6 +6004,25 @@ msgstr "Lägg till slut G-kod när utskriften har avslutas" 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" +msgid "Ensure vertical shell thickness" +msgstr "" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "" + +msgid "Internal bridge support thickness" +msgstr "" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" + msgid "Top surface pattern" msgstr "Topp ytans mönster" @@ -5585,6 +6047,12 @@ msgstr "" msgid "Hilbert Curve" msgstr "" +msgid "Archimedean Chords" +msgstr "" + +msgid "Octagram Spiral" +msgstr "" + msgid "Bottom surface pattern" msgstr "Botten ytans mönster" @@ -5635,9 +6103,6 @@ msgid "" "object printing." msgstr "" -msgid "Radius" -msgstr "Radie" - msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." @@ -5705,21 +6170,31 @@ msgstr "" msgid "s" msgstr "s" +msgid "Default color" +msgstr "" + +msgid "Default filament color" +msgstr "" + msgid "Color" msgstr "Färg" +msgid "Required nozzle HRC" +msgstr "" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "" + msgid "Max volumetric speed" msgstr "Max volymetrisk hastighet" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" -"Denna inställning står för volymen av filament som kan smältas och " -"extruderas per sekund. Utskriftshastigheten begränsas av max volymetrisk " -"hastighet vid för hög och orimlig hastighetsinställning. 0 betyder ingen " -"gräns" msgid "mm³/s" msgstr "mm³/s" @@ -5852,6 +6327,12 @@ msgstr "Honeycomb" msgid "Adaptive Cubic" msgstr "Adaptiv Cubic" +msgid "3D Honeycomb" +msgstr "" + +msgid "Support Cubic" +msgstr "" + msgid "Lightning" msgstr "" @@ -5862,6 +6343,9 @@ msgstr "" "Acceleration av fyllning av toppytan. Att använda ett lägre värde kan " "förbättra ytkvaliteten" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5882,22 +6366,6 @@ msgstr "" "Första lagerhöjd. Högre första lager kan förbättra objektets fäste på " "byggplattan" -msgid "Adaptive layer height" -msgstr "Adaptiv lagerhöjd" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"Aktivera detta alternativet så innebär det att höjden på varje lager efter " -"det första kommer att beräknas automatiskt enligt lutningen på modellens " -"yta.\n" -"Observera att detta alternativ endast träder i kraft om det inte finns något " -"prime torn genererat på den aktuella plattan." - msgid "Speed of initial layer except the solid infill part" msgstr "" "Hastigheten för det första lagret förutom för solida ifyllnads sektioner" @@ -6007,6 +6475,17 @@ msgstr "Rostfritt stål" msgid "Brass" msgstr "Mässing" +msgid "Nozzle HRC" +msgstr "" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "" + +msgid "HRC" +msgstr "" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "Aktivera detta val om maskinen har extra kylfläkt" @@ -6363,9 +6842,6 @@ msgstr "" "Objekt kommer att höjas med detta antal support lager. Använd denna funktion " "för att undvika warping vid utskrift av ABS" -msgid "Resolution" -msgstr "Upplösning" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6523,9 +6999,6 @@ msgid "" "wipe nozzle." msgstr "" -msgid "Smooth" -msgstr "" - msgid "Traditional" msgstr "" @@ -6550,6 +7023,23 @@ msgid "" "resolution, therefore it is advisable to keep the value reasonably low." msgstr "" +msgid "Slicing Mode" +msgstr "" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" + +msgid "Regular" +msgstr "" + +msgid "Even-odd" +msgstr "" + +msgid "Close holes" +msgstr "" + msgid "Enable support" msgstr "Aktivera support" @@ -6573,11 +7063,11 @@ msgstr "träd(auto)" msgid "hybrid(auto)" msgstr "hybrid(auto)" -msgid "normal" -msgstr "normal" +msgid "normal(manual)" +msgstr "" -msgid "tree" -msgstr "träd" +msgid "tree(manual)" +msgstr "" msgid "Support/object xy distance" msgstr "Support/objekt xy distans" @@ -6614,12 +7104,16 @@ msgid "The z gap between the top support interface and object" msgstr "" "Detta bestämmer Z-avståndet mellan det övre support gränssnittet och objektet" -msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" +msgid "Bottom Z distance" +msgstr "" + +msgid "The z gap between the bottom support interface and object" +msgstr "" + +msgid "" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" msgstr "" -"Filament för att skriva ut support och skirt med. 0 betyder inget speciellt " -"filament för support och nuvarande filament används" msgid "Line width of support" msgstr "Linjebredd för support" @@ -6634,11 +7128,9 @@ msgstr "" "standard." msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" msgstr "" -"Support filament för utskrift. 0 betyder att inget specifikt filament för " -"support gränssnitt och nuvarande filament används" msgid "Top interface layers" msgstr "Översta gränssnitts lager" @@ -6692,6 +7184,12 @@ msgstr "Basens mönster mellanrum" msgid "Spacing between support lines" msgstr "Mellanrum mellan support linjer" +msgid "Normal Support expansion" +msgstr "" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "" + msgid "Speed of support" msgstr "Support hastighet" @@ -6749,16 +7247,6 @@ msgstr "Tree support vägg varv" msgid "This setting specify the count of walls around tree support" msgstr "Inställningen bestämmer antal väggar runt tree support" -msgid "Tree support with infill" -msgstr "Tree support med ifyllnad" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "" -"Inställningen bestämmer om det ska läggas till ifyllnad i stora hålrum av " -"tree support" - msgid "Nozzle temperature for layers after the initial one" msgstr "Nozzel temperatur efter första lager" @@ -6863,6 +7351,14 @@ msgstr "" msgid "Purging volumes" msgstr "Rensnings volym" +msgid "Flush multiplier" +msgstr "Rensnings multiplikator" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "" + msgid "Prime volume" msgstr "Prime volym (volymen av ut pressat material)" @@ -6875,41 +7371,24 @@ msgstr "Bredd" msgid "Width of prime tower" msgstr "Prime tornets bredd" -msgid "Flush into objects' infill" -msgstr "Rensa in i föremålens ifyllnad" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" -"Rensning efter filamentbyte kommer att göras inuti objektens fyllningar. " -"Detta kan minska mängden avfall och minska utskriftstiden. Om väggarna är " -"tryckta med transparent filament kommer den blandade färgfyllningen att " -"synas." - -msgid "Flush into objects' support" -msgstr "Rensa in i objektets support" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"Rensning efter filamentändring kommer att göras inuti objektens support. " -"Detta kan minska mängden avfall och minska utskriftstiden." - -msgid "Flush into this object" -msgstr "Rensa in i det här objektet" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" -"Detta objekt kommer att användas för att rensa nozzlen efter ett filament " -"byte för att spara filament och minska utskriftstiden. Objektens färger " -"blandas som ett resultat" msgid "X-Y hole compensation" msgstr "X-Y håls kompensation" @@ -6938,6 +7417,79 @@ msgstr "" "Denna funktion används för att justera storleken något när det finns " "monterings svårigheter" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" + +msgid "Classic" +msgstr "" + +msgid "Arachne" +msgstr "" + +msgid "Wall transition length" +msgstr "" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning filter margin" +msgstr "" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Wall transitioning threshold angle" +msgstr "" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" + +msgid "Wall distribution count" +msgstr "" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" + +msgid "Minimum feature size" +msgstr "" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" + +msgid "Minimum wall width" +msgstr "" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" + msgid "Detect narrow internal solid infill" msgstr "Upptäck tight inre solid ifyllnad" @@ -6957,12 +7509,30 @@ msgstr "Exportera 3mf" msgid "Export project as 3MF." msgstr "Exportera projekt som3mf." +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 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 "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "Mata ut modell information" @@ -6975,6 +7545,12 @@ msgstr "Exportera inställningar" msgid "Export settings to a file." msgstr "Exportera inställningar till en fil." +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "Placera Val" @@ -6990,12 +7566,6 @@ msgstr "Konvertera modellens enheter" msgid "Orient the model" msgstr "Orientera modellen" -msgid "Repair" -msgstr "Reparera" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "Reparera modellens mesh om den inte är mångfaldig" - msgid "Scale the model by a float factor" msgstr "Skala modellen med en plus faktor" @@ -7068,9 +7638,6 @@ msgstr "" msgid "Slicing mesh" msgstr "Bereder mesh" -msgid " Object:" -msgstr " Objekt:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "Support: generera verktygsbana vid lager %d" @@ -7266,31 +7833,73 @@ msgid "" "one time?" msgstr "" -#~ msgid "Erase painting" -#~ msgstr "Radera färgläggning" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" -#~ msgid "Set pen size" -#~ msgstr "Välj penn storlek" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" -#~ msgid "Rotation:" -#~ msgstr "Rotation:" +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" -#~ msgid "Height:" -#~ msgstr "Höjd:" +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "Välj en eller flera filer (3mf/step/stl/obj/amf):" -#~ msgid "Initialize failed [%d]!" -#~ msgstr "Start misslyckad [%d]!" +#~ msgid "Finish" +#~ msgstr "Slutför" -#~ msgid "Management" -#~ msgstr "Handhavande" +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "Importera 3MF/STL/STEP/OBJ/AMF" -#~ msgid "Open" -#~ msgstr "Öppna" +#~ msgid "Part Cooling" +#~ msgstr "Del Kylning" + +#~ msgid "Aux Cooling" +#~ msgstr "Extra Kylning" #~ msgid "" -#~ "%1% is too close to exclusion area, there will be collisions when " -#~ "printing." -#~ msgstr "%1% för tätt inpå den isolerade ytan, utskriften kolliderar." +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" +#~ msgstr "" +#~ "Filament för att skriva ut support och skirt med. 0 betyder inget " +#~ "speciellt filament för support och nuvarande filament används" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "" +#~ "Support filament för utskrift. 0 betyder att inget specifikt filament för " +#~ "support gränssnitt och nuvarande filament används" + +#~ msgid "Repair" +#~ msgstr "Reparera" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "Reparera modellens mesh om den inte är mångfaldig" + +#~ msgid "Monitoring Recording" +#~ msgstr "Övervaknings Inspelning" + +#~ msgid "Tree support with infill" +#~ msgstr "Tree support med ifyllnad" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "" +#~ "Inställningen bestämmer om det ska läggas till ifyllnad i stora hålrum av " +#~ "tree support" #~ msgid "" #~ "\n" @@ -7300,74 +7909,17 @@ msgstr "" #~ "\n" #~ "%1% för tätt inpå den isolerade ytan, utskriften kolliderar." -#~ msgid " is too close to others, there will be collisions when printing.\n" -#~ msgstr " för tätt inpå andra, utskriften kolliderar.\n" - #~ msgid "" -#~ " is too close to exclusion area, there will be collisions when printing.\n" -#~ msgstr " för tätt inpå den isolerade ytan, utskriften kolliderar.\n" - -#~ msgid "Avoid crossing wall when travel" -#~ msgstr "Undvik väggar vid förflyttning" - -#~ msgid "Max travel detour distance" -#~ msgstr "Max undvikande förflyttnings avstånd" - -#~ msgid "" -#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " -#~ "detour distance is large than this value" -#~ msgstr "" -#~ "Max undvikande förflyttnings avstånd för att undvika väggar. Om avståndet " -#~ "överstiger detta värde, kommer ingen undvikande förflyttning att ske" - -#~ msgid "" -#~ "Height of the clearance cylinder around extruder. Used as input of auto-" -#~ "arrange to avoid collision when print object by object" -#~ msgstr "" -#~ "Höjden på fritt cylinder område runt extrudern: Används som input för " -#~ "auto-placering för att undvika kollision när man skriver ut objekt för " -#~ "objekt" - -#~ msgid "" -#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " -#~ "collision when print object by object" -#~ msgstr "" -#~ "Fri radie område runt extrudern: Används som input för auto-placering för " -#~ "att undvika kollision när man skriver ut objekt för objekt" - -#~ msgid "Error at line %1%:\n" -#~ msgstr "Fel i linje %1%:\n" - -#~ msgid "Reduce Triangles" -#~ msgstr "Reducera Trianglar" - -#~ msgid "" -#~ "Switch to zig-zag pattern?\n" -#~ "Yes - switch to zig-zag pattern automaticlly\n" -#~ "No - reset density to default non 100% value automaticlly\n" -#~ msgstr "" -#~ "Ändra till Zig-Zag mönster?\n" -#~ "JA - Byta till Zig-Zag mönster automatiskt\n" -#~ "NEJ - Återställ densiteten till standard inte 100% värdet automatiskt\n" - -#~ msgid "Extruder position" -#~ msgstr "Extruder position" - -#~ msgid "Zig zag" -#~ msgstr "Zig zag" - -#~ msgid "" -#~ "Bed temperature is higher than vitrification temperature of this " -#~ "filament.\n" -#~ "This may cause nozzle blocked and printing failure" -#~ msgstr "" -#~ "Byggplattans temperatur överstiger kristalliserings temperaturen av detta " -#~ "filament.\n" -#~ "Detta kan orsaka att nozzeln blockeras och utskriften misslyckas" +#~ "%1% is too close to exclusion area, there will be collisions when " +#~ "printing." +#~ msgstr "%1% för tätt inpå den isolerade ytan, utskriften kolliderar." #~ msgid "0%" #~ msgstr "0%" +#~ msgid "Adaptive layer height" +#~ msgstr "Adaptiv lagerhöjd" + #~ msgid "" #~ "An object is layed over the boundary of plate.\n" #~ "Please solve the problem by moving it totally inside or outside plate." @@ -7386,9 +7938,34 @@ msgstr "" #~ "Auto placera valda objekt eller alla objekt. Om det finns valda objekt så " #~ "placeras endast dem. Alternativt så placeras alla objekt i projektet." +#~ msgid "Avoid crossing wall when travel" +#~ msgstr "Undvik väggar vid förflyttning" + +#~ msgid "" +#~ "Bed temperature is higher than vitrification temperature of this " +#~ "filament.\n" +#~ "This may cause nozzle blocked and printing failure" +#~ msgstr "" +#~ "Byggplattans temperatur överstiger kristalliserings temperaturen av detta " +#~ "filament.\n" +#~ "Detta kan orsaka att nozzeln blockeras och utskriften misslyckas" + #~ msgid "Clear all" #~ msgstr "Rensa allt" +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arrange to avoid " +#~ "collision when print object by object" +#~ msgstr "" +#~ "Fri radie område runt extrudern: Används som input för auto-placering för " +#~ "att undvika kollision när man skriver ut objekt för objekt" + +#~ msgid "Color Print" +#~ msgstr "Färg Utskrift" + +#~ msgid "Comsumption" +#~ msgstr "Konsumtion" + #~ msgid "Creating" #~ msgstr "Skapar" @@ -7436,12 +8013,52 @@ msgstr "" #~ "Detta inaktiverar retraktion när rörelsen är helt inom ett ifyllnads " #~ "området och det inte kan läcka filament" +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "Aktivera detta alternativet så innebär det att höjden på varje lager " +#~ "efter det första kommer att beräknas automatiskt enligt lutningen på " +#~ "modellens yta.\n" +#~ "Observera att detta alternativ endast träder i kraft om det inte finns " +#~ "något prime torn genererat på den aktuella plattan." + #~ msgid "Enter a search term" #~ msgstr "Ange ett sökord" +#~ msgid "Erase painting" +#~ msgstr "Radera färgläggning" + +#~ msgid "Error at line %1%:\n" +#~ msgstr "Fel i linje %1%:\n" + +#~ msgid "Export Sliced File" +#~ msgstr "Exportera Beredd fil" + +#~ msgid "Export current Sliced file" +#~ msgstr "Exportera nuvarande Beredda fil" + +#~ msgid "Export ok." +#~ msgstr "Exportering OK." + +#~ msgid "Export sliced file" +#~ msgstr "Exportera beredd fil" + +#~ msgid "Extruder position" +#~ msgstr "Extruder position" + #~ msgid "Failed" #~ msgstr "Misslyckades" +#~ msgid "Filament 1" +#~ msgstr "Filament 1" + +#~ msgid "Filament N XX" +#~ msgstr "Filament N XX" + #~ msgid "Filaments Selection" #~ msgstr "Filament Val" @@ -7454,6 +8071,18 @@ msgstr "" #~ msgid "Fix model through cloud" #~ msgstr "Åtgärda modellen via molnet" +#~ msgid "Flushed filament" +#~ msgstr "Rensat filament" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "Tvinga kylfläktens hastighet när överhängsgraderna överstiger detta " +#~ "värde. Uttryckt i procent som indikerar linjebredden utan stöd från lägre " +#~ "lager" + #~ msgid "Fragment Filter" #~ msgstr "Fragment Filter" @@ -7470,12 +8099,26 @@ msgstr "" #~ "Värm nozzel till vald \n" #~ "temperatur" +#~ msgid "Height:" +#~ msgstr "Höjd:" + +#~ msgid "" +#~ "Height of the clearance cylinder around extruder. Used as input of auto-" +#~ "arrange to avoid collision when print object by object" +#~ msgstr "" +#~ "Höjden på fritt cylinder område runt extrudern: Används som input för " +#~ "auto-placering för att undvika kollision när man skriver ut objekt för " +#~ "objekt" + #~ msgid "In the calibration of extrusion flow" #~ msgstr "Vid kalibrering av extruderingsflödet" #~ msgid "In the calibration of laser scanner" #~ msgstr "Vid kalibrering av laserskanner" +#~ msgid "Initialize failed [%d]!" +#~ msgstr "Start misslyckad [%d]!" + #~ msgid "Inner wall speed" #~ msgstr "Inre vägg hastighet" @@ -7489,12 +8132,34 @@ msgstr "" #~ msgid "Line type" #~ msgstr "Linje typ" +#~ msgid "Management" +#~ msgstr "Handhavande" + +#~ msgid "Max travel detour distance" +#~ msgstr "Max undvikande förflyttnings avstånd" + +#~ msgid "" +#~ "Maximum detour distance for avoiding crossing wall. Don't detour if the " +#~ "detour distance is large than this value" +#~ msgstr "" +#~ "Max undvikande förflyttnings avstånd för att undvika väggar. Om avståndet " +#~ "överstiger detta värde, kommer ingen undvikande förflyttning att ske" + #~ msgid "Module" #~ msgstr "Modul" #~ msgid "Monitoring" #~ msgstr "Övervakar" +#~ msgid "Open" +#~ msgstr "Öppna" + +#~ msgid "Open &PrusaSlicer" +#~ msgstr "Öppna &PrusaSlicer" + +#~ msgid "Open PrusaSlicer" +#~ msgstr "Öppna PrusaSlicer" + #~ msgid "Output file" #~ msgstr "Utdatafil" @@ -7510,6 +8175,9 @@ msgstr "" #~ msgid "Per object edit" #~ msgstr "Redigera per objekt" +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "Plattan %d: %s stöds ej av filament %s.\n" + #~ msgid "Please fill report first." #~ msgstr "Fyll i rapporten först." @@ -7532,6 +8200,24 @@ msgstr "" #~ msgid "Printer Selection" #~ msgstr "Skrivar Val" +#~ msgid "" +#~ "Purging after filament change will be done inside objects' infills. This " +#~ "may lower the amount of waste and decrease the print time. If the walls " +#~ "are printed with transparent filament, the mixed color infill will be " +#~ "seen outside" +#~ msgstr "" +#~ "Rensning efter filamentbyte kommer att göras inuti objektens fyllningar. " +#~ "Detta kan minska mängden avfall och minska utskriftstiden. Om väggarna är " +#~ "tryckta med transparent filament kommer den blandade färgfyllningen att " +#~ "synas." + +#~ msgid "" +#~ "Purging after filament change will be done inside objects' support. This " +#~ "may lower the amount of waste and decrease the print time" +#~ msgstr "" +#~ "Rensning efter filamentändring kommer att göras inuti objektens support. " +#~ "Detta kan minska mängden avfall och minska utskriftstiden." + #~ msgid "" #~ "Push new filament \n" #~ "into extruder" @@ -7550,15 +8236,30 @@ msgstr "" #~ "then a snapshot is taken with the chamber camera. When printing finishes, " #~ "a timelapse video is created from all the snapshots." +#~ msgid "Reduce Triangles" +#~ msgstr "Reducera Trianglar" + +#~ msgid "Reload item" +#~ msgstr "Ladda om objektet" + +#~ msgid "Reload items" +#~ msgstr "Ladda om objekten" + #~ msgid "Report" #~ msgstr "Rapportera" +#~ msgid "Rotation:" +#~ msgstr "Rotation:" + #~ msgid "Save configuration as:" #~ msgstr "Spara konfigurationen som:" #~ msgid "Sending" #~ msgstr "Skickar" +#~ msgid "Set pen size" +#~ msgstr "Välj penn storlek" + #~ msgid "Shift + Any arrow" #~ msgstr "Skift+valfri pil" @@ -7591,6 +8292,15 @@ msgstr "" #~ "stöda custom support mellanrum, detta kan orsaka extra filament byten om " #~ "support (materialet) är vald som en annan extruder än objektets" +#~ msgid "" +#~ "Switch to zig-zag pattern?\n" +#~ "Yes - switch to zig-zag pattern automaticlly\n" +#~ "No - reset density to default non 100% value automaticlly\n" +#~ msgstr "" +#~ "Ändra till Zig-Zag mönster?\n" +#~ "JA - Byta till Zig-Zag mönster automatiskt\n" +#~ "NEJ - Återställ densiteten till standard inte 100% värdet automatiskt\n" + #~ msgid "Swith cloud environment, Please login again!" #~ msgstr "Byte av moln miljö, Logga in igen!" @@ -7612,6 +8322,25 @@ msgstr "" #~ "Modellen har överlappande eller självkorsande aspekter.Reparation utförd, " #~ "men kontrollera resultaten eller reparera indatafilen och försöka igen." +#~ msgid "" +#~ "This object will be used to purge the nozzle after a filament change to " +#~ "save filament and decrease the print time. Colours of the objects will be " +#~ "mixed as a result" +#~ msgstr "" +#~ "Detta objekt kommer att användas för att rensa nozzlen efter ett filament " +#~ "byte för att spara filament och minska utskriftstiden. Objektens färger " +#~ "blandas som ett resultat" + +#~ msgid "" +#~ "This setting stands for how much volume of filament can be melted and " +#~ "extruded per second. Printing speed is limited by max volumetric speed, " +#~ "in case of too high and unreasonable speed setting. Zero means no limit" +#~ msgstr "" +#~ "Denna inställning står för volymen av filament som kan smältas och " +#~ "extruderas per sekund. Utskriftshastigheten begränsas av max volymetrisk " +#~ "hastighet vid för hög och orimlig hastighetsinställning. 0 betyder ingen " +#~ "gräns" + #~ msgid "Timelapse Wipe Tower" #~ msgstr "Timelapse Wipe Tower" @@ -7630,5 +8359,31 @@ msgstr "" #~ msgid "Waiting" #~ msgstr "Väntar" +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "Förinställningarna har ändrats. \n" +#~ "Behålla dessa ändrade inställningar efter byte av förinställningar?" + +#~ msgid "Zig zag" +#~ msgstr "Zig zag" + +#~ msgid " Object:" +#~ msgstr " Objekt:" + +#~ msgid "" +#~ " is too close to exclusion area, there will be collisions when printing.\n" +#~ msgstr " för tätt inpå den isolerade ytan, utskriften kolliderar.\n" + +#~ msgid " is too close to others, there will be collisions when printing.\n" +#~ msgstr " för tätt inpå andra, utskriften kolliderar.\n" + +#~ msgid "normal" +#~ msgstr "normal" + #~ msgid "the 3mf is not compatible, load geometry data only!" #~ msgstr "3mf ej kompatibel, laddar endast geometrin !" + +#~ msgid "tree" +#~ msgstr "träd" diff --git a/bbl/i18n/zh_cn/BambuStudio_zh_CN.po b/bbl/i18n/zh_cn/BambuStudio_zh_CN.po index 3b73c53869..ab55b0215e 100644 --- a/bbl/i18n/zh_cn/BambuStudio_zh_CN.po +++ b/bbl/i18n/zh_cn/BambuStudio_zh_CN.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Slic3rPE\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-05 12:18+0800\n" -"PO-Revision-Date: 2022-11-05 12:10+0800\n" +"POT-Creation-Date: 2022-12-13 20:02+0800\n" +"PO-Revision-Date: 2022-12-13 20:18+0800\n" "Last-Translator: Jiang Yue \n" "Language-Team: \n" "Language: zh_CN\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 3.2\n" +"X-Generator: Poedit 3.0.1\n" msgid "Supports Painting" msgstr "支撑绘制" @@ -26,6 +26,9 @@ msgstr "Alt + 鼠标滚轮" msgid "Section view" msgstr "剖面视图" +msgid "Reset direction" +msgstr "重置方向" + msgid "Ctrl + Mouse wheel" msgstr "Ctrl + 鼠标滚轮" @@ -71,6 +74,9 @@ msgstr "工具类型" msgid "Smart fill angle" msgstr "智能填充角度" +msgid "On overhangs only" +msgstr "仅对悬空区生效" + msgid "Auto support threshold angle: " msgstr "自动支撑角度阈值:" @@ -86,6 +92,10 @@ msgstr "填充" msgid "Gap Fill" msgstr "缝隙填充" +#, boost-format +msgid "Allows painting only on facets selected by: \"%1%\"" +msgstr "绘制仅对由%1%选中的面片生效" + msgid "Highlight faces according to overhang angle." msgstr "根据当前设置的悬空角度来高亮片面。" @@ -141,6 +151,12 @@ msgstr "批量填充" msgid "Height range" msgstr "高度范围" +msgid "Ctrl + Shift + Enter" +msgstr "" + +msgid "Toggle Wireframe" +msgstr "显示/隐藏线框" + msgid "Shortcut Key " msgstr "快捷键 " @@ -333,9 +349,6 @@ msgstr "外观面检测" msgid "Perform Recognition" msgstr "执行检测" -msgid "Reset direction" -msgstr "重置方向" - msgid "Brush size" msgstr "画刷尺寸" @@ -354,15 +367,6 @@ msgstr "Z缝绘制" msgid "Remove selection" msgstr "移除绘制" -msgid "Entering Seam painting" -msgstr "" - -msgid "Leaving Seam painting" -msgstr "推出Z缝绘制" - -msgid "Paint-on seam editing" -msgstr "" - msgid "Text shape" msgstr "文本形状" @@ -503,8 +507,8 @@ msgstr "加载模式视图" msgid "Choose one file (3mf):" msgstr "选择一个文件(3mf):" -msgid "Choose one or more files (3mf/step/stl/obj/amf):" -msgstr "选择一个或多个文件(3mf/step/stl/obj/amf):" +msgid "Choose one or more files (3mf/step/stl/svg/obj/amf):" +msgstr "选择一个或多个文件(3mf/step/stl/svg/obj/amf):" msgid "Choose one file (gcode/.gco/.g/.ngc/ngc):" msgstr "选择一个文件(gcode/.gco/.g/.ngc/ngc):" @@ -583,6 +587,9 @@ msgstr "填充" msgid "Support" msgstr "支撑" +msgid "Flush options" +msgstr "换料冲刷选项" + msgid "Speed" msgstr "速度" @@ -716,6 +723,18 @@ msgstr "缩放到构建空间大小" msgid "Scale an object to fit the build volume" msgstr "缩放对象以适应构建空间大小" +msgid "Flush Options" +msgstr "换料冲刷选项" + +msgid "Flush into objects' infill" +msgstr "冲刷到对象的填充" + +msgid "Flush into this object" +msgstr "冲刷到这个对象" + +msgid "Flush into objects' support" +msgstr "冲刷到对象的支撑" + msgid "Convert from inch" msgstr "从英寸转换" @@ -767,6 +786,9 @@ msgstr "镜像对象" msgid "Add Primitive" msgstr "添加标准模型" +msgid "Show Labels" +msgstr "显示标签" + msgid "To objects" msgstr "拆分到对象" @@ -833,6 +855,9 @@ msgstr "简化模型" msgid "Center" msgstr "居中" +msgid "Edit Process Settings" +msgstr "编辑工艺参数" + msgid "Edit in Parameter Table" msgstr "在参数表格中编辑" @@ -900,10 +925,10 @@ msgid "Click the icon to toggle printable property of the object" msgstr "点击此图标可切换这个对象的可打印属性" msgid "Click the icon to edit support painting of the object" -msgstr "点击这个图标可编辑这个对象的支撑绘制" +msgstr "点击此图标可编辑这个对象的支撑绘制" msgid "Click the icon to edit color painting of the object" -msgstr "点击这个图标可编辑这个对象的颜色绘制" +msgstr "点击此图标可编辑这个对象的颜色绘制" msgid "Loading file" msgstr "载入文件中" @@ -917,6 +942,14 @@ msgstr "通用" msgid "Add Modifier" msgstr "添加修改器" +msgid "Switch to per-object setting mode to edit modifier settings." +msgstr "切换到对象模式以编辑修改器的设置。" + +msgid "" +"Switch to per-object setting mode to edit process settings of selected " +"objects." +msgstr "切换到对象设置模式,以编辑所选对象的工艺参数" + msgid "Deleting the last solid part is not allowed." msgstr "不允许删除对象的最后一个实体零件。" @@ -1058,7 +1091,10 @@ msgid "More" msgstr "详情" msgid "Open Preferences." -msgstr "打开首选项。" +msgstr "打开首选项" + +msgid "Open next tip." +msgstr "打开下一条提示" msgid "Open Documentation in web browser." msgstr "在web浏览器中打开文档。" @@ -1067,11 +1103,20 @@ msgid "Custom G-code" msgstr "自定义 G-code" msgid "Enter Custom G-code used on current layer:" -msgstr "输入当前层上使用的自定义G-code" +msgstr "输入当前层上使用的自定义G-code:" msgid "OK" msgstr "确认" +msgid "Jump to layer" +msgstr "跳转到层" + +msgid "Please enter the layer number" +msgstr "请输入层数" + +msgid "Jump to Layer" +msgstr "跳转到层" + msgid "Add Pause" msgstr "添加暂停打印" @@ -1093,20 +1138,20 @@ msgstr "" msgid "No printer" msgstr "无打印机" -msgid "Heat the nozzle to target temperature" -msgstr "加热喷嘴到目标温度" +msgid "Heat the nozzle" +msgstr "加热喷嘴" msgid "Cut filament" msgstr "切断耗材丝" msgid "Pull back current filament" -msgstr "抽回当前耗材丝" +msgstr "抽回耗材丝" msgid "Push new filament into extruder" msgstr "送出新的耗材丝到挤出机" msgid "Purge old filament" -msgstr "清除旧料" +msgstr "冲刷旧耗材丝" msgid "?" msgstr "?" @@ -1235,10 +1280,10 @@ msgid "Failure of printer login" msgstr "登录设备失败" msgid "Failed to get ticket" -msgstr "" +msgstr "获取Ticket失败" msgid "User authorization timeout" -msgstr "" +msgstr "用户鉴权超时" msgid "Failure of bind" msgstr "设备登录失败" @@ -1291,12 +1336,34 @@ msgid "Sending print configuration" msgstr "正在发送打印配置" #, c-format, boost-format -msgid "Successfully sent. Will automatically jump to the device page in %s s" +msgid "Successfully sent. Will automatically jump to the device page in %ss" msgstr "已发送完成,即将自动跳转到设备页面(%s秒)" msgid "An SD card needs to be inserted before printing via LAN." msgstr "需要插入SD卡后方可发送局域网打印" +msgid "Send to Printer failed. Please try again." +msgstr "发送到打印机失败。请重试。" + +msgid "Sending gcode file over LAN" +msgstr "通过局域网发送gcode文件" + +msgid "Sending gcode file through cloud service" +msgstr "通过云服务发送gcode文件" + +msgid "Sending gcode file to sdcard" +msgstr "发送gcode文件到sd卡" + +#, c-format, boost-format +msgid "Successfully sent. Close current page in %s s" +msgstr "成功发送。即将关闭当前页面(%s秒)" + +msgid "An SD card needs to be inserted before sending to printer." +msgstr "需要插入SD卡后方可发送到打印机。" + +msgid "Please log out and login to the printer again." +msgstr "请先退出登录然后再重新登录打印机。" + msgid "Downloading" msgstr "下载中" @@ -1306,8 +1373,8 @@ msgstr "下载失败" msgid "Cancelled" msgstr "已取消" -msgid "Finish" -msgstr "完成" +msgid "Install successfully." +msgstr "安装成功。" msgid "Installing" msgstr "安装中" @@ -1397,7 +1464,10 @@ msgid "The input value should be greater than %1% and less than %2%" msgstr "输入的范围在 %1% 和 %2% 之间" msgid "SN" -msgstr "" +msgstr "序列号" + +msgid "Setting AMS slot information while printing is not supported" +msgstr "不支持在打印时修改AMS槽位信息" msgid "Confirm" msgstr "确定" @@ -1424,6 +1494,19 @@ msgstr "不启用AMS" msgid "Print with the filament mounted on the back of chassis" msgstr "使用机箱背后挂载的材料打印" +msgid "" +"Config which AMS slot should be used for a filament used in the print job" +msgstr "配置当前打印任务应使用哪个AMS槽位" + +msgid "Filament used in this print job" +msgstr "当前打印打印使用的料丝" + +msgid "AMS slot used for this filament" +msgstr "当前料丝对应的AMS槽位" + +msgid "Click to select AMS slot manually" +msgstr "点击以手动选择AMS槽位" + msgid "AMS Settings" msgstr "AMS 设置" @@ -1468,6 +1551,25 @@ msgid "" "last shutdown." msgstr "AMS不会在启动时自动读取耗材丝信息。它会使用上次关机前记录的信息。" +msgid "Update remaining capacity" +msgstr "更新剩余容量" + +msgid "" +"The AMS will estimate Bambu filament's remaining capacity after the filament " +"info is updated. During printing, remaining capacity will be updated " +"automatically." +msgstr "" +"AMS读取Bambu Lab耗材丝信息同时推算料卷的剩余容量。在打印过程中,剩余容量会自" +"动更新。" + +msgid "AMS auto switch filament" +msgstr "AMS自动续料" + +msgid "" +"AMS will continue to another spool with the same properties of filament " +"automatically when current filament runs out" +msgstr "AMS料材丝耗尽后将自动切换到属性完全相同的耗材丝" + msgid "File" msgstr "文件" @@ -1479,7 +1581,7 @@ msgstr "插件下载失败。请检查您的防火墙设置和vpn软件,检查 msgid "" "Failed to install the plug-in. Please check whether it is blocked or deleted " "by anti-virus software." -msgstr "安装插件失败。请检查是否被杀毒软件屏蔽或删除了。" +msgstr "安装插件失败。请检查是否被杀毒软件屏蔽或删除。" msgid "click here to see more info" msgstr "点击这里查看更多信息" @@ -1664,6 +1766,13 @@ msgstr "" "热床温度超过了耗材丝的软化温度,材料软化可能造成喷头堵塞。\n" "请保持打印机在打印过程中敞开,保证空气流通或降低热床温度" +msgid "" +"Too small max volumetric speed.\n" +"Reset to 0.5" +msgstr "" +"最大体积流量设置过小\n" +"重置为0.5" + msgid "" "Too small layer height.\n" "Reset to 0.2" @@ -1729,6 +1838,22 @@ msgstr "" "是 - 自动调整这些设置并开启旋转模式\n" "否 - 暂不使用旋转模式" +msgid "" +"Arachne engine only works when overhang slowing down is disabled.\n" +"This may cause decline in the quality of overhang surface when print fastly\n" +msgstr "" +"Arachne引擎只在关闭悬垂降速时起作用。\n" +"这可能会导致高速打印时悬垂表面质量的下降\n" + +msgid "" +"Disable overhang slowing down automatically? \n" +"Yes - Enable arachne and disable overhang slowing down\n" +"No - Give up using arachne this time" +msgstr "" +"自动关闭悬垂降速?\n" +"是 - 使用arachne并关闭悬垂降速\n" +"否 - 此次放弃使用arachne" + msgid "" "Prime tower does not work when Adaptive Layer Height or Independent Support " "Layer Height is on.\n" @@ -1843,7 +1968,7 @@ msgid "MC" msgstr "" msgid "MainBoard" -msgstr "" +msgstr "主板" msgid "AMS" msgstr "AMS" @@ -1881,6 +2006,9 @@ msgstr "更新失败。" msgid "Failed to start printing job" msgstr "发起打印任务失败" +msgid "default" +msgstr "缺省" + msgid "parameter name" msgstr "参数名称" @@ -1937,16 +2065,22 @@ msgid "Tool" msgstr "工具" msgid "Height: " -msgstr "" +msgstr "层高: " msgid "Width: " -msgstr "" +msgstr "线宽: " msgid "Speed: " -msgstr "" +msgstr "速度: " msgid "Flow: " -msgstr "" +msgstr "挤出流量: " + +msgid "Fan Speed: " +msgstr "风扇速度: " + +msgid "Temperature: " +msgstr "温度: " msgid "Loading G-codes" msgstr "正在加载G-code" @@ -1957,6 +2091,9 @@ msgstr "正在生成几何顶点数据" msgid "Generating geometry index data" msgstr "正在生成几何索引数据" +msgid "Display" +msgstr "显示" + msgid "up to" msgstr "达到" @@ -1972,14 +2109,11 @@ msgstr "到" msgid "Color Scheme" msgstr "颜色方案" -msgid "Percent" -msgstr "百分比" - msgid "Time" msgstr "时间" -msgid "Display" -msgstr "显示" +msgid "Percent" +msgstr "百分比" msgid "Layer Height (mm)" msgstr "层高(mm)" @@ -2002,14 +2136,11 @@ msgstr "体积流量速度(mm³/s)" msgid "Used filament" msgstr "使用的耗材丝" -msgid "Filament N XX" -msgstr "打印丝 N XX" +msgid "Flushed" +msgstr "冲刷" -msgid "Color Print" -msgstr "彩色打印" - -msgid "Comsumption" -msgstr "消耗" +msgid "Total" +msgstr "总计" msgid "Travel" msgstr "空驶" @@ -2038,18 +2169,12 @@ msgstr "空驶" msgid "Extruder" msgstr "挤出机" -msgid "Filament 1" -msgstr "耗材丝 1" - -msgid "Flushed filament" -msgstr "换料冲刷消耗" - -msgid "Total" -msgstr "总计" - msgid "Filament change times" msgstr "换料次数" +msgid "Cost" +msgstr "成本" + msgid "Color change" msgstr "颜色更换" @@ -2068,24 +2193,75 @@ msgstr "打印设置" msgid "Total Estimation" msgstr "总预估" +msgid "Time Estimation" +msgstr "时间预估" + msgid "Normal mode" msgstr "普通模式" -msgid "Cost" -msgstr "成本" - msgid "Prepare time" msgstr "准备时间" msgid "Model printing time" msgstr "模型打印时间" +msgid "Total time" +msgstr "总时间" + msgid "Switch to silent mode" msgstr "切换到静音模式" msgid "Switch to normal mode" msgstr "切换到普通模式" +msgid "Variable layer height" +msgstr "可变层高" + +msgid "Adaptive" +msgstr "自适应" + +msgid "Quality / Speed" +msgstr "细节/速度" + +msgid "Smooth" +msgstr "平滑模式" + +msgid "Radius" +msgstr "半径" + +msgid "Keep min" +msgstr "保留最小" + +msgid "Left mouse button:" +msgstr "鼠标左键:" + +msgid "Add detail" +msgstr "减小层高" + +msgid "Right mouse button:" +msgstr "鼠标右键:" + +msgid "Remove detail" +msgstr "增大层高" + +msgid "Shift + Left mouse button:" +msgstr "Shift + 鼠标左键:" + +msgid "Reset to base" +msgstr "设置到基础层高" + +msgid "Shift + Right mouse button:" +msgstr "Shift + 鼠标右键:" + +msgid "Smoothing" +msgstr "平滑" + +msgid "Mouse wheel:" +msgstr "鼠标滚轮:" + +msgid "Increase/decrease edit area" +msgstr "增加/减小编辑区域" + msgid "Sequence" msgstr "顺序" @@ -2200,6 +2376,18 @@ msgstr "" msgid "Calibration" msgstr "校准" +msgid "Calibration step selection" +msgstr "校准步骤选择" + +msgid "Micro lidar calibration" +msgstr "微激光雷达校准" + +msgid "Bed leveling" +msgstr "热床调平" + +msgid "Resonance frequency identification" +msgstr "共振频率辨识" + msgid "Calibration program" msgstr "校准程序" @@ -2223,12 +2411,24 @@ msgstr "已完成" msgid "Calibrating" msgstr "校准中" -msgid "Timelapse" -msgstr "延时摄影" - -msgid "Monitoring Recording" +msgid "Auto-record Monitoring" msgstr "监控录像" +msgid "Go Live" +msgstr "开启直播" + +msgid "Resolution" +msgstr "分辨率" + +msgid "Show \"Live Video\" guide page." +msgstr "显示\"直播视频流\"指南" + +msgid "720p" +msgstr "" + +msgid "1080p" +msgstr "" + msgid "ConnectPrinter(LAN)" msgstr "连接打印机(局域网)" @@ -2272,6 +2472,15 @@ msgstr "设备" msgid "Project" msgstr "项目" +msgid "Yes" +msgstr "是" + +msgid "No" +msgstr "否" + +msgid " will be closed before creating a new model. Do you want to continue?" +msgstr "会被关闭以创建新模型。是否继续?" + msgid "Slice" msgstr "切片" @@ -2281,17 +2490,26 @@ msgstr "切片所有盘" msgid "Slice plate" msgstr "切片单盘" -msgid "Print all" -msgstr "打印所有盘" - msgid "Export G-code file" msgstr "导出G-code文件" -msgid "Export sliced file" -msgstr "导出切片文件" +msgid "Send" +msgstr "发送" -msgid "Export Sliced File" -msgstr "导出切片文件" +msgid "Print plate" +msgstr "打印单盘" + +msgid "Export plate sliced file" +msgstr "导出单盘切片文件" + +msgid "Export all sliced file" +msgstr "导出所有切片文件" + +msgid "Print all" +msgstr "打印所有盘" + +msgid "Send all" +msgstr "发送所有盘" msgid "Keyboard Shortcuts" msgstr "快捷键" @@ -2305,18 +2523,24 @@ msgstr "配置向导" msgid "Show Configuration Folder" msgstr "打开配置文件夹" +msgid "Show Tip of the Day" +msgstr "展示每日小贴士" + msgid "Check for Update" msgstr "检查新版本" +msgid "Open Network Test" +msgstr "打开网络测试" + #, c-format, boost-format msgid "&About %s" msgstr "关于 %s" -msgid "Show Tip of the Day" -msgstr "展示每日小贴士" +msgid "Upload Models" +msgstr "上传模型" -msgid "Open Network Test" -msgstr "打开网络测试" +msgid "Download Models" +msgstr "下载模型" msgid "Default View" msgstr "默认视图" @@ -2360,7 +2584,7 @@ msgid "Right View" msgstr "右视图" msgid "Start a new window" -msgstr "" +msgstr "打开新窗口" msgid "New Project" msgstr "新建项目" @@ -2386,8 +2610,8 @@ msgstr "项目另存为" msgid "Save current project as" msgstr "项目另存为" -msgid "Import 3MF/STL/STEP/OBJ/AMF" -msgstr "导入 3MF/STL/STEP/OBJ/AMF" +msgid "Import 3MF/STL/STEP/SVG/OBJ/AMF" +msgstr "导入 3MF/STL/STEP/SVG/OBJ/AMF" msgid "Load a model" msgstr "加载模型" @@ -2396,7 +2620,7 @@ msgid "Import Configs" msgstr "导入预设" msgid "Load configs" -msgstr "" +msgstr "加载配置" msgid "Import" msgstr "导入" @@ -2410,9 +2634,12 @@ msgstr "导出通用 3MF" msgid "Export 3mf file without using some 3mf-extensions" msgstr "导出不含 3mf 扩展的 3mf 文件" -msgid "Export current Sliced file" +msgid "Export current sliced file" msgstr "导出当前已切片的文件" +msgid "Export all plate sliced file" +msgstr "导出所有盘已切片的文件" + msgid "Export G-code" msgstr "导出 G-code" @@ -2503,6 +2730,9 @@ msgstr "视图" msgid "Help" msgstr "帮助" +msgid "3D Models" +msgstr "3D模型" + msgid "&Open G-code" msgstr "打开G-code" @@ -2521,10 +2751,10 @@ msgstr "" msgid "Export toolpaths as OBJ" msgstr "" -msgid "Open &PrusaSlicer" +msgid "Open &Studio" msgstr "" -msgid "Open PrusaSlicer" +msgid "Open Studio" msgstr "" msgid "&Quit" @@ -2616,10 +2846,13 @@ msgid "Initialize failed (Not supported with LAN-only mode)!" msgstr "初始化失败(不支持局域网模式的视频连接)" msgid "Initialize failed (Not accessible in LAN-only mode)!" -msgstr "初始化失败(局域网描述不可访问)" +msgstr "初始化失败(在局域网模式中不可访问)!" -msgid "Initialize failed (Not supported without remote video tunnel)!" -msgstr "初始化失败(不支持远程视频连接)" +msgid "Initialize failed (Missing LAN ip of printer)!" +msgstr "初始化失败(未找到打印机的局域网地址)!" + +msgid "Initialize failed (Not supported by printer)!" +msgstr "初始化失败(打印机不支持该功能)!" #, c-format, boost-format msgid "Initialize failed (%s)!" @@ -2630,11 +2863,35 @@ msgstr "网络不可访问" #, c-format, boost-format msgid "Stopped [%d]!" -msgstr "" +msgstr "已停止 [%d]!" msgid "Stopped." msgstr "已经停止。" +msgid "" +"Virtual Camera Tools is required for this task!\n" +"Do you want to install them?" +msgstr "该功能需要“虚拟摄像头工具包”,是否下载并安装该工具包?" + +msgid "Downloading Virtual Camera Tools" +msgstr "正在下载“虚拟摄像头工具包”" + +msgid "" +"Another virtual camera is running.\n" +"Bambu Studio supports only a single virtual camera.\n" +"Do you want to stop this virtual camera?" +msgstr "" +"另一个虚拟摄像头正在工作。\n" +"Bambu Studio 同时只能支持一个虚拟摄像头。\n" +"是否停止前一个虚拟摄像头?" + +#, c-format, boost-format +msgid "Virtual camera initialize failed (%s)!" +msgstr "虚拟摄像头初始化失败(%s)!" + +msgid "Information" +msgstr "信息" + msgid "Playing..." msgstr "正在播放中……" @@ -2660,6 +2917,9 @@ msgstr "按月份分组,从最近的开始展示" msgid "Show all files, recent first." msgstr "显示所有文件,从最近的开始展示" +msgid "Timelapse" +msgstr "延时摄影" + msgid "Switch to timelapse files." msgstr "切换到延时摄影文件列表" @@ -2687,8 +2947,8 @@ msgstr "批量管理文件" msgid "No printers." msgstr "未选择打印机" -msgid "Not supported." -msgstr "不支持" +msgid "Not supported by this model of printer!" +msgstr "该型号的打印机不支持该功能!" msgid "Connecting..." msgstr "连接中..." @@ -2703,12 +2963,18 @@ msgstr "加载文件列表..." msgid "No files" msgstr "文件列表为空" +msgid "Not accessible in LAN-only mode!" +msgstr "在局域网模式中不可访问!" + +msgid "Missing LAN ip of printer!" +msgstr "未找到打印机的局域网地址!" + #, c-format, boost-format msgid "File '%s' was lost! Please download it again." msgstr "文件%s丢失,请重新下载。" msgid "Download waiting..." -msgstr "正在下载中..." +msgstr "等待下载中..." msgid "Play" msgstr "播放" @@ -2747,6 +3013,12 @@ msgstr "交换Y/Z轴" msgid "Camera" msgstr "摄像机" +msgid "SD Card" +msgstr "SD卡" + +msgid "Camera Setting" +msgstr "相机设置" + msgid "Printing Progress" msgstr "打印进度" @@ -2774,11 +3046,11 @@ msgstr "100%" msgid "Lamp" msgstr "LED灯" -msgid "Part Cooling" -msgstr "部件冷却" +msgid "Aux" +msgstr "辅助" -msgid "Aux Cooling" -msgstr "辅助冷却" +msgid "Cham" +msgstr "机箱" msgid "Bed" msgstr "热床" @@ -2789,6 +3061,12 @@ msgstr "退料" msgid "Debug Info" msgstr "调试信息" +msgid "No SD Card" +msgstr "无SD卡" + +msgid "SD Card Abnormal" +msgstr "SD卡异常" + msgid "Printing List" msgstr "项目切片" @@ -2798,9 +3076,42 @@ msgstr "取消打印" msgid "Are you sure you want to cancel this print?" msgstr "你确定要取消这次打印吗?" +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode disabled.Please reconnect the " +"printer by logging in with your user account." +msgstr "" +"由于LAN模式被禁用,已与打印机[%s]断开连接。请使用您的用户帐户登录以重新连接打" +"印机。" + +#, c-format, boost-format +msgid "" +"Disconnected from printer [%s] due to LAN mode enabled.Please reconnect the " +"printer by inputting Access Code which can be gotten from printer screen." +msgstr "" +"由于启用了LAN模式,已与打印机[%s]断开连接。请通过输入访问码重新连接打印机,访" +"问码可从打印机屏幕上获取。" + msgid "Downloading..." msgstr "下载中..." +msgid "Cloud Slicing..." +msgstr "云切片中..." + +msgid "Please heat the nozzle to above 170 degree before loading filament." +msgstr "请在进料前把喷嘴升温到170℃" + +msgid "Still unload" +msgstr "继续退料" + +msgid "Still load" +msgstr "继续进料" + +msgid "" +"Cannot read filament info: the filament is loaded to the tool head,please " +"unload the filament and try again." +msgstr "无法读取耗材丝信息:耗材丝已经加载到工具头,请退出耗材丝后再重试。" + msgid "This only takes effect during printing" msgstr "仅在打印过程中生效" @@ -2816,6 +3127,9 @@ msgstr "运动" msgid "Ludicrous" msgstr "狂暴" +msgid "Can't start this without SD card." +msgstr "没有SD卡无法开始任务" + msgid "Failed to connect to the server" msgstr "无法连接服务器" @@ -2834,11 +3148,8 @@ msgstr "" msgid "Failed to connect to the printer" msgstr "无法连接打印机" -msgid "Yes" -msgstr "是" - -msgid "No" -msgstr "否" +msgid "Don't show again" +msgstr "不再显示" #, c-format, boost-format msgid "%s error" @@ -2940,7 +3251,7 @@ msgstr "错误:" msgid "Warning:" msgstr "警告:" -msgid "Export ok." +msgid "Export successfully." msgstr "导出成功." msgid " (Repair)" @@ -2970,9 +3281,6 @@ msgstr "层" msgid "Range" msgstr "范围" -msgid "default" -msgstr "缺省" - msgid "" "The application cannot run normally because OpenGL version is lower than " "2.0.\n" @@ -3001,20 +3309,25 @@ msgctxt "Layers" msgid "Bottom" msgstr "底部" -msgid "Spaghetti and Excess Chute Pileup Detection" -msgstr "炒面与堆料检查" +msgid "Enable AI monitoring of printing" +msgstr "启用打印过程的AI监控" -msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" -msgstr "当发生炒面或废料口堆料时停止打印" +msgid "Sensitivity of pausing is" +msgstr "暂停的灵敏度为" + +msgid "Enable detection of build plate position" +msgstr "启用构建板位置检测" + +msgid "" +"The localization tag of build plate is detected, and printing is paused if " +"the tag is not in predefined range." +msgstr "检测构建板的定位标记,如果标记不在预定义范围内时暂停打印。" msgid "First Layer Inspection" msgstr "首层扫描" -msgid "Switch to per-object setting mode to edit modifier settings." -msgstr "切换到对象模式以编辑修改器的设置。" - -msgid "Don't show again" -msgstr "不再显示" +msgid "Auto-recovery from step loss" +msgstr "自动从丢步中恢复" msgid "Global" msgstr "全局" @@ -3069,7 +3382,7 @@ msgid "Click to edit preset" msgstr "点击编辑配置" msgid "Connection" -msgstr "连接打印机" +msgstr "连接" msgid "Bed type" msgstr "热床类型" @@ -3083,8 +3396,8 @@ msgstr "增加一个材料" msgid "Remove last filament" msgstr "删除最后一个材料" -msgid "Sync material list from AMS" -msgstr "同步到 AMS 的材料列表" +msgid "Synchronize filament list from AMS" +msgstr "从AMS同步材料列表" msgid "Set filaments to use" msgstr "配置可选择的材料" @@ -3104,6 +3417,14 @@ msgstr "同步到 AMS 的材料列表将丢弃所有当前配置的材料预设 msgid "There are no compatible filaments, and sync is not performed." msgstr "没有如任何兼容的材料,同步操作未执行。" +msgid "" +"There are some unknown filaments mapped to generic preset. Please update " +"Bambu Studio or restart Bambu Studio to check if there is an update to " +"system presets." +msgstr "" +"有一些未知型号的材料,映射到通用预设。请更新或者重启 Bambu Studio,以检查系统" +"预设有没有更新。" + msgid "Untitled" msgstr "未命名" @@ -3115,7 +3436,7 @@ msgstr "是否保存修改到“%1%”?" msgid "" "Successfully unmounted. The device %s(%s) can now be safely removed from the " "computer." -msgstr "卸载成功。设备%s(%s)现在可以安全地从电脑移除。" +msgstr "卸载成功。设备%s(%s)现在可能安全地从电脑移除。" #, c-format, boost-format msgid "Ejecting of device %s(%s) has failed." @@ -3132,6 +3453,14 @@ msgid "" "open the front door of printer before printing to avoid nozzle clog." msgstr "热床温度超过了材料的软化温度。请在打印前打开打印机前门以防堵头。" +msgid "" +"The nozzle hardness required by the filament is higher than the default " +"nozzle hardness of the printer. Please replace the hardened nozzle or " +"filament, otherwise, the nozzle will be attrited or damaged." +msgstr "" +"打印丝所要求的喷嘴硬度高于打印机默认的喷嘴硬度。请更换硬化的喷嘴或打印丝,否" +"则喷嘴可能被磨损或损坏。" + #, c-format, boost-format msgid "Loading file: %s" msgstr "加载文件:%s" @@ -3242,9 +3571,6 @@ msgstr "选中的模型不可分裂。" msgid "Another export job is running." msgstr "有其他导出任务正在进行中。" -msgid "Another export job is currently running." -msgstr "有其他导出任务正在进行中。" - msgid "Select a new file" msgstr "选择新文件" @@ -3269,6 +3595,9 @@ msgstr "警告" msgid "Invalid data" msgstr "无效数据" +msgid "Slicing Canceled" +msgstr "" + #, c-format, boost-format msgid "Slicing Plate %d" msgstr "正在切片盘%d" @@ -3296,6 +3625,28 @@ msgstr "创建新项目" msgid "Load project" msgstr "加载项目" +msgid "" +"Failed to save the project.\n" +"Please check whether the folder exists online or if other programs open the " +"project file." +msgstr "保存文件失败。请检查目录是否存在,以及是否有其他程序打开了该项目文件。" + +msgid "Save project" +msgstr "保存项目" + +msgid "Importing Model" +msgstr "正在导入模型" + +msgid "prepare 3mf file..." +msgstr "正在准备3mf文件..." + +msgid "downloading project ..." +msgstr "项目下载中..." + +#, c-format, boost-format +msgid "Project downloaded %d%%" +msgstr "项目已下载%d%%" + msgid "The selected file" msgstr "已选择的文件" @@ -3353,6 +3704,12 @@ msgstr "G-code文件另存为:" msgid "Save Sliced file as:" msgstr "切片文件另存为:" +#, c-format, boost-format +msgid "" +"The file %s has been sent to the printer's storage space and can be viewed " +"on the printer." +msgstr "文件%s已经发送到打印机的存储空间,可以在打印机上浏览。" + msgid "" "Print By Object: \n" "Suggest to use auto-arrange to avoid collisions when printing." @@ -3372,6 +3729,9 @@ msgstr "自定义的支撑和涂色在模型修复之前将被清除。" msgid "Invalid number" msgstr "无效数字" +msgid "Select Bed Type" +msgstr "选择热床类型" + #, boost-format msgid "Part name: %1%\n" msgstr "零件名字:%1%\n" @@ -3390,7 +3750,7 @@ msgstr "大小: %1% x %2% x %3% 毫米\n" #, boost-format msgid "Volume: %1% in³\n" -msgstr "" +msgstr "体积: %1% 英寸³\n" #, boost-format msgid "Volume: %1% mm³\n" @@ -3400,6 +3760,20 @@ msgstr "体积: %1% 毫米³\n" msgid "Triangles: %1%\n" msgstr "三角形:%1%\n" +msgid "Tips:" +msgstr "提示:" + +msgid "" +"\"Fix Model\" feature is currently only on Windows. Please repair the model " +"on Bambu Studio(windows) or CAD softwares." +msgstr "" +"\"修复模型\"功能目前仅适用于Windows。请在Bambu Studio(windows)或CAD软件上修复" +"模型。" + +#, c-format, boost-format +msgid "Plate %d: %s does not support filament %s (%s).\n" +msgstr "盘%d:%s不支持耗材丝%s (%s)。\n" + msgid "Switching the language requires application restart.\n" msgstr "切换语言要求重启应用程序。\n" @@ -3508,6 +3882,12 @@ msgstr "备份间隔时长" msgid "Downloads" msgstr "下载" +msgid "Dark Mode" +msgstr "深色模式" + +msgid "Enable Dark mode" +msgstr "启用深色模式" + msgid "Home page and daily tips" msgstr "首页和每日小贴士" @@ -3619,6 +3999,15 @@ msgstr "编辑预设" msgid "Project-inside presets" msgstr "项目预设" +msgid "Add/Remove filaments" +msgstr "添加/删除材料" + +msgid "Add/Remove materials" +msgstr "添加/删除材料" + +msgid "Add/Remove printers" +msgstr "添加/删除打印机" + msgid "Slice all plate to obtain time and filament estimation" msgstr "正在切片以获取切片信息和预估打印时间" @@ -3769,9 +4158,6 @@ msgstr "热床调平" msgid "Flow Calibration" msgstr "流量校准" -msgid "Send" -msgstr "发送" - msgid "send completed" msgstr "发送完成" @@ -3787,7 +4173,7 @@ msgstr "正在同步设备信息" msgid "Synchronizing device information time out" msgstr "同步设备信息超时" -msgid "Cannot send the print task when the upgrade is in progress" +msgid "Cannot send the print job when the printer is updating firmware" msgstr "设备升级中,无法发送打印任务" msgid "" @@ -3844,11 +4230,24 @@ msgstr "" msgid "An SD card needs to be inserted before printing." msgstr "请在发起打印前插入SD卡" -msgid "An SD card needs to be inserted to recording timelapse" +msgid "An SD card needs to be inserted to record timelapse." msgstr "开启延迟摄影功能需要插入SD卡" -msgid "Please check the following infomation:\n" -msgstr "请确认以下信息后发送打印:\n" +msgid "" +"Cannot send the print job to a printer whose firmware is required to get " +"updated." +msgstr "需要更新打印机固件后,才能将打印任务发送到打印机" + +msgid "Cannot send the print job for empty plate" +msgstr "无法为空盘发送打印任务" + +msgid "Errors" +msgstr "错误" + +msgid "" +"Please check the following infomation and click Confirm to continue sending " +"print:\n" +msgstr "请检查以下信息,点击确认后继续发送打印:\n" msgid "" "The printer type used to generate G-code is not the same type as the " @@ -3858,18 +4257,51 @@ msgstr "" "用于生成G-code的打印机类型与当前选定的物理打印机类型不同,建议选择相同的打印" "机类型重新切片。\n" +#, c-format, boost-format +msgid "The %s filament is too soft to be used with the 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 " +"start printing." +msgstr "" +"AMS映射中存在一些未知的耗材。请检查它们是否符合预期。如果符合,按“确定”以开始" +"打印任务。" + msgid "Preparing print job" msgstr "正在准备打印任务" msgid "Modifying the device name" msgstr "修改打印机名称" -msgid "Send to Printer" -msgstr "发送到打印机" +msgid "Send to Printer SD card" +msgstr "发送到打印机的SD卡" + +msgid "Cannot send the print task when the upgrade is in progress" +msgstr "设备升级中,无法发送打印任务" msgid "The printer is required to be in the same LAN as Bambu Studio." msgstr "打印机需要与Bambu Studio在同一个局域网内。" +msgid "The printer does not support sending to printer SD card." +msgstr "该打印机不支持发送到打印机SD卡。" + +msgid "Same as Global Bed Type" +msgstr "跟随全局热床类型" + +msgid "Cool Plate" +msgstr "低温打印热床" + +msgid "Engineering Plate" +msgstr "工程材料热床" + +msgid "High Temp Plate" +msgstr "高温打印热床" + +msgid "Textured PEI Plate" +msgstr "纹理PEI热床" + msgid "Log in printer" msgstr "登录打印机" @@ -3906,21 +4338,20 @@ msgid "Search in preset" msgstr "在预设中搜索" msgid "Click to reset all settings to the last saved preset." -msgstr "" +msgstr "点击以将所有设置还原到最后一次保存的版本。" msgid "" -"Prime tower is required by smooth timeplase. If whthout prime tower, there " -"will be flaws on the model. Are you sure you want to disable prime tower?" +"Prime tower is required for smooth timeplase. There may be flaws on the " +"model without prime tower. Are you sure you want to disable prime tower?" msgstr "" -"平滑模式的延时摄影需要擦料塔。如果没有,模型上就可能会有缺陷。你确定要禁用擦" -"料塔吗?" +"平滑模式的延时摄影需要擦料塔,否则打印件上可能会有瑕疵。您确定要关闭擦料塔" +"吗?" msgid "" -"Prime tower is required by smooth timelapse. If whthout prime tower, there " -"will be flaws on the model. Do you want to enable prime tower?" +"Prime tower is required for smooth timelapse. There may be flaws on the " +"model without prime tower. Do you want to enable prime tower?" msgstr "" -"平滑模式的延时摄影需要擦料塔。如果没有,模型上就可能会有缺陷。你想要启用擦料" -"塔吗?" +"平滑模式的延时摄影需要擦料塔,否则打印件上可能会有瑕疵。您想打开擦料塔吗?" msgid "" "When recording timelapse without toolhead, it is recommended to add a " @@ -3940,6 +4371,9 @@ msgstr "接缝" msgid "Precision" msgstr "精度" +msgid "Wall generator" +msgstr "墙生成器" + msgid "Walls" msgstr "墙" @@ -3969,15 +4403,15 @@ msgstr "空驶速度" msgid "Acceleration" msgstr "加速度" +msgid "Raft" +msgstr "筏层" + msgid "Support filament" msgstr "支撑耗材" msgid "Prime tower" msgstr "擦拭塔" -msgid "Flush options" -msgstr "换料冲刷选项" - msgid "Special mode" msgstr "特殊模式" @@ -4046,17 +4480,11 @@ msgid "" "filament does not support to print on the Engineering Plate" msgstr "安装工程材料热床时的热床温度。0值表示这个耗材丝不支持工程材料热床" -msgid "High Temp Plate" -msgstr "高温打印热床" - msgid "" "Bed temperature when high temperature plate is installed. Value 0 means the " "filament does not support to print on the High Temp Plate" msgstr "安装高温打印热床时的热床温度。0值表示这个耗材丝不支持高温打印热床" -msgid "Textured PEI Plate" -msgstr "纹理PEI热床" - msgid "" "Bed temperature when Textured PEI Plate is installed. Value 0 means the " "filament does not support to print on the Textured PEI Plate" @@ -4107,7 +4535,7 @@ msgid "Printable space" msgstr "可打印区域" msgid "Extruder Clearance" -msgstr "" +msgstr "挤出机避让空间" msgid "Accessory" msgstr "配件" @@ -4262,12 +4690,18 @@ msgid "" "contains the following unsaved changes:" msgstr "预设“%1%”和新的工艺预设不兼容,并且它包含以下未保存的修改:" +#, boost-format +msgid "" +"You have changed some settings of preset \"%1%\". \n" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "您已经更改了预设 \"%1%\",是否在切换后要保留这些更改的预设参数?" + msgid "" "You have changed some preset settings. \n" -"Would you like to keep these changed settings after switching preset?" -msgstr "" -"您有一些修改过的设置。\n" -"切换预设后,是否要保留这些更改过的设置?" +"Would you like to keep these changed settings (new value) after switching " +"preset?" +msgstr "您已经更改了预设参数,是否在切换后要保留这些更改的预设参数?" msgid "Extruders count" msgstr "挤出机数量" @@ -4278,6 +4712,11 @@ msgstr "常规" msgid "Capabilities" msgstr "能力" +msgid "" +"The P1P printer does not support smooth timelapse, use traditional timelapse " +"instead." +msgstr "P1P打印机不支持平滑模式的延时摄影,请改用传统模式。" + msgid "Show all presets (including incompatible)" msgstr "显示所有预设(包括不兼容的)" @@ -4361,17 +4800,28 @@ msgstr "没有可用的更新。" msgid "The configuration is up to date." msgstr "当前配置已经是最新版本。" -msgid "Auto-Calc" -msgstr "自动计算" - msgid "Flushing volumes for filament change" msgstr "耗材丝更换时的冲刷体积" +msgid "Auto-Calc" +msgstr "自动计算" + msgid "Flushing volume (mm³) for each filament pair." msgstr "在两个耗材丝间切换所需的冲刷量(mm³)" -msgid "Flush multiplier" -msgstr "冲刷量乘数" +msgid "Multiplier" +msgstr "乘数" + +msgid "Actual Volume = Flushing Volume * Multiplier" +msgstr "实际冲刷量 = 冲刷体积 * 乘数" + +#, c-format, boost-format +msgid "Suggestion: Actual Volume in range [%d, %d]" +msgstr "建议:实际冲刷量设置在[%d, %d]范围内" + +#, c-format, boost-format +msgid "The multiplier should be in range [%.2f, %.2f]." +msgstr "乘数的取值范围是[%.2f, %.2f]" msgid "unloaded" msgstr "卸载" @@ -4646,8 +5096,8 @@ msgstr "序列号:" msgid "Version:" msgstr "版本:" -msgid "Upgrade firmware" -msgstr "升级固件" +msgid "Update firmware" +msgstr "更新固件" msgid "Printing" msgstr "打印中" @@ -4658,14 +5108,14 @@ msgstr "空闲" msgid "Latest version" msgstr "最新版本" -msgid "Upgrading" -msgstr "升级中" +msgid "Updating" +msgstr "更新中" -msgid "Upgrading failed" -msgstr "升级失败" +msgid "Updating failed" +msgstr "更新失败" -msgid "Upgrading successful" -msgstr "升级成功" +msgid "Updating successful" +msgstr "更新成功" msgid "" "Are you sure you want to update? This will take about 10 minutes. Do not " @@ -4688,6 +5138,9 @@ msgstr "" "当前固件版本异常,需要进行修复升级,否则无法继续打印。你想现在就开始升级吗?" "你也可以稍后在打印机上升级,或者下一次启动studio再升级。" +msgid "Extension Board" +msgstr "扩展板" + msgid "Saving objects into the 3mf failed." msgstr "保存对象到3mf失败。" @@ -4932,12 +5385,6 @@ msgid "" "%1% is too close to exclusion area, there may be collisions when printing." msgstr "%1%离屏蔽区域太近,可能会发生碰撞。" -#, boost-format -msgid "" -"\n" -"%1% is too close to exclusion area, there may be collisions when printing." -msgstr "" - #, boost-format msgid "%1% is too close to others, and collisions may be caused." msgstr "%1%离其它对象太近,可能会发生碰撞。" @@ -4947,11 +5394,11 @@ msgid "%1% is too tall, and collisions will be caused." msgstr "%1%太高,会发生碰撞。" msgid " is too close to others, there may be collisions when printing.\n" -msgstr "" +msgstr "到其他对象的距离太近了,可能在打印过程中发生碰撞。\n" msgid "" " is too close to exclusion area, there may be collisions when printing.\n" -msgstr "" +msgstr "到屏蔽区域的距离太近了,可能在打印过程中发生碰撞。\n" msgid "Prime Tower" msgstr "擦拭塔" @@ -5011,6 +5458,11 @@ msgid "" "heights." msgstr "擦拭塔要求各个对象拥有同样的层高。" +msgid "" +"The prime tower is only supported if all objects have the same variable " +"layer height" +msgstr "各个对象的层高存在差异,无法启用擦料塔" + msgid "Too small line width" msgstr "线宽太小" @@ -5029,8 +5481,8 @@ msgid "Layer height cannot exceed nozzle diameter" msgstr "层高不能超过喷嘴直径" #, c-format, boost-format -msgid "Plate %d: %s does not support filament %s.\n" -msgstr "盘%d:%s不支持耗材丝%s\n" +msgid "Plate %d: %s does not support filament %s\n" +msgstr "盘%d: %s 不支持耗材丝 %s\n" msgid "Generating skirt & brim" msgstr "正在生成skirt和brim" @@ -5058,6 +5510,12 @@ msgstr "" "XY平面上的不可打印区域。例如,X1系列打印机在换料过程中,会使用左前角区域来切" "断耗材丝。这个多边形区域由以下格式的点表示:“XxY,XxY,…”" +msgid "Bed custom texture" +msgstr "自定义热床纹理" + +msgid "Bed custom model" +msgstr "自定义热床模型" + msgid "Elephant foot compensation" msgstr "象脚补偿" @@ -5100,7 +5558,7 @@ msgid "" msgstr "" msgid "Name of the printer" -msgstr "" +msgstr "打印机名称" msgid "HTTPS CA File" msgstr "" @@ -5217,12 +5675,6 @@ msgstr "首层热床温度。0值表示这个耗材丝不支持纹理PEI热床" msgid "Bed types supported by the printer" msgstr "打印机所支持的热床类型" -msgid "Cool Plate" -msgstr "低温打印热床" - -msgid "Engineering Plate" -msgstr "工程材料热床" - msgid "This G-code is inserted at every layer change before lifting z" msgstr "在每次换层抬升z高度之前插入这段G-code" @@ -5273,13 +5725,27 @@ msgstr "" msgid "Cooling overhang threshold" msgstr "冷却悬空阈值" +#, c-format msgid "" "Force cooling fan to be specific speed when overhang degree of printed part " "exceeds this value. Expressed as percentage which indicides how much width " -"of the line without support from lower layer" +"of the line without support from lower layer. 0% means forcing cooling for " +"all outer wall no matter how much overhang degree" msgstr "" -"当打印部分的悬垂程度超出设定值,强制冷却风扇为设置的速度。悬垂程度表示为未被" -"低层支撑的部分占线宽的百分比" +"当打印件的悬空程度超过此值时,强制冷却风扇达到特定速度。用百分比表示,表明没" +"有下层支撑的线的宽度是多少。0%%意味着无论悬垂程度如何,都要对所有外壁强制冷" +"却。" + +msgid "Bridge direction" +msgstr "桥接方向" + +msgid "" +"Bridging angle override. If left to zero, the bridging angle will be " +"calculated automatically. Otherwise the provided angle will be used for " +"external bridges. Use 180°for zero angle." +msgstr "" +"搭桥角度覆盖。如果设置为零,该角度将自动计算。否则外部的桥接将用提供的值。" +"180°表示0度。" msgid "Bridge flow" msgstr "桥接流量" @@ -5359,6 +5825,9 @@ msgstr "在brim和模型之间设置间隙,能够让brim更容易剥离" msgid "Compatible machine" msgstr "兼容的机器" +msgid "upward compatible machine" +msgstr "" + msgid "Compatible machine condition" msgstr "兼容的机器的条件" @@ -5441,9 +5910,6 @@ msgstr "" msgid "Thick bridges" msgstr "厚桥" -msgid "Layers and Perimeters" -msgstr "层和墙" - msgid "" "If enabled, bridges are more reliable, can bridge longer distances, but may " "look worse. If disabled, bridges look better but are reliable just for " @@ -5472,6 +5938,28 @@ msgstr "所有打印结束时的结尾G-code" msgid "End G-code when finish the printing of this filament" msgstr "结束使用该耗材打印时的结尾G-code" +msgid "Ensure vertical shell thickness" +msgstr "确保垂直外壳厚度" + +msgid "" +"Add solid infill near sloping surfaces to guarantee the vertical shell " +"thickness (top+bottom solid layers)" +msgstr "在斜面表面附近添加实心填充,以保证垂直外壳厚度(顶部+底部实心层)" + +msgid "Internal bridge support thickness" +msgstr "内部桥接支撑厚度" + +msgid "" +"If enabled, Studio will generate support loops under the contours of " +"internal bridges.These support loops could prevent internal bridges from " +"extruding over the air and improve the top surface quality, especially when " +"the sparse infill density is low.This value determines the thickness of the " +"support loops. 0 means disable this feature" +msgstr "" +"如果开启,Studio会沿着内部桥接的边沿在其下方生成支撑轮廓。这些支撑轮廓可以防" +"止悬空地打印内部桥接并提高顶面质量,特别是在填充密度较低的情况下。这个设置用" +"于调整支撑轮廓的厚度,0表示关闭此特性。" + msgid "Top surface pattern" msgstr "顶面图案" @@ -5496,6 +5984,12 @@ msgstr "直线排列" msgid "Hilbert Curve" msgstr "希尔伯特曲线" +msgid "Archimedean Chords" +msgstr "阿基米德和弦" + +msgid "Octagram Spiral" +msgstr "八角螺旋" + msgid "Bottom surface pattern" msgstr "底面图案" @@ -5537,7 +6031,7 @@ msgstr "到横杆高度" msgid "" "Distance of the nozzle tip to the lower rod. Used for collision avoidance in " "by-object printing." -msgstr "" +msgstr "喷嘴尖端到下方滑杆的距离。用于在逐件打印中避免碰撞。" msgid "Height to lid" msgstr "到顶盖高度" @@ -5545,23 +6039,20 @@ msgstr "到顶盖高度" msgid "" "Distance of the nozzle tip to the lid. Used for collision avoidance in by-" "object printing." -msgstr "" - -msgid "Radius" -msgstr "半径" +msgstr "喷嘴尖端到顶盖的距离。用于在逐件打印中避免碰撞。" msgid "" "Clearance radius around extruder. Used for collision avoidance in by-object " "printing." -msgstr "" +msgstr "挤出机四周的避让半径。用于在逐件打印中避免碰撞。" msgid "Max Radius" -msgstr "" +msgstr "最大半径" msgid "" "Max clearance radius around extruder. Used for collision avoidance in by-" "object printing." -msgstr "" +msgstr "挤出机四周的最大避让半径。用于在逐件打印中避免碰撞。" msgid "Extruder Color" msgstr "挤出机颜色" @@ -5613,19 +6104,33 @@ msgstr "" msgid "s" msgstr "秒" +msgid "Default color" +msgstr "缺省颜色" + +msgid "Default filament color" +msgstr "缺省材料颜色" + msgid "Color" msgstr "颜色" +msgid "Required nozzle HRC" +msgstr "喷嘴硬度要求" + +msgid "" +"Minimum HRC of nozzle required to print the filament. Zero means no checking " +"of nozzle's HRC." +msgstr "打印此材料的所需的最小喷嘴硬度。零值表示不检查喷嘴硬度。" + msgid "Max volumetric speed" msgstr "最大体积速度" msgid "" "This setting stands for how much volume of filament can be melted and " "extruded per second. Printing speed is limited by max volumetric speed, in " -"case of too high and unreasonable speed setting. Zero means no limit" +"case of too high and unreasonable speed setting. Can't be zero" msgstr "" "这个设置表示在1秒内能够融化和挤出的耗材丝体积。打印速度会受到最大体积速度的限" -"制,防止设置过高和不合理的速度。0表示没有限制。" +"制,防止设置过高和不合理的速度。不允许设置为0。" msgid "mm³/s" msgstr "mm³/s" @@ -5747,6 +6252,12 @@ msgstr "蜂窝" msgid "Adaptive Cubic" msgstr "自适应立方体" +msgid "3D Honeycomb" +msgstr "3D 蜂窝" + +msgid "Support Cubic" +msgstr "支撑立方体" + msgid "Lightning" msgstr "闪电" @@ -5755,6 +6266,9 @@ msgid "" "surface quality" msgstr "顶面填充的加速度。使用较低值可能会改善顶面质量" +msgid "Acceleration of outer wall. Using a lower value can improve quality" +msgstr "外墙加速度。使用较小的值可以提高质量。" + msgid "" "Acceleration of initial layer. Using a lower value can improve build plate " "adhensive" @@ -5810,20 +6324,6 @@ msgid "" "can improve build plate adhension" msgstr "首层层高" -msgid "Adaptive layer height" -msgstr "自适应层高" - -msgid "" -"Enabling this option means the height of every layer except the first will " -"be automatically calculated during slicing according to the slope of the " -"model’s surface.\n" -"Note that this option only takes effect if no prime tower is generated in " -"current plate." -msgstr "" -"开启这个选项,程序会在切片的过程中根据模型表面的倾斜度自动计算每层的层高,首" -"层除外。\n" -"注意这个选项仅在当前盘不存在擦拭塔的情况下生效。" - msgid "Speed of initial layer except the solid infill part" msgstr "首层除实心填充之外的其他部分的打印速度" @@ -5906,7 +6406,7 @@ msgid "" msgstr "喷嘴的金属材料。这将决定喷嘴的耐磨性,以及可打印材料的种类" msgid "Undefine" -msgstr "" +msgstr "未定义" msgid "Hardened steel" msgstr "硬化钢" @@ -5917,6 +6417,17 @@ msgstr "不锈钢" msgid "Brass" msgstr "黄铜" +msgid "Nozzle HRC" +msgstr "喷嘴洛氏硬度" + +msgid "" +"The nozzle's hardness. Zero means no checking for nozzle's hardness during " +"slicing." +msgstr "喷嘴硬度。零值表示在切片时不检查喷嘴硬度。" + +msgid "HRC" +msgstr "洛氏硬度" + msgid "Enable this option if machine has auxiliary part cooling fan" msgstr "如果机器有辅助部件冷却风扇,勾选该选项" @@ -5945,7 +6456,7 @@ msgid "Line width of internal sparse infill" msgstr "内部稀疏填充的线宽" msgid "Infill/Wall overlap" -msgstr "填充/外墙 重叠" +msgstr "填充/墙 重叠" msgid "" "Infill area is enlarged slightly to overlap with wall for better bonding. " @@ -6013,10 +6524,10 @@ msgstr "机器是否支持使用低加速度打印的静音模式。" msgid "" "This G-code will be used as a code for the pause print. User can insert " "pause G-code in gcode viewer" -msgstr "" +msgstr "该G-code用于暂停打印。您可以在gcode预览中插入暂停G-code" msgid "This G-code will be used as a custom code" -msgstr "" +msgstr "该G-code是定制化指令" msgid "Maximum speed X" msgstr "X最大速度" @@ -6257,9 +6768,6 @@ msgid "" msgstr "" "模型会在相应层数的支撑上抬高进行打印。使用该功能通常用于打印ABS时翘曲。" -msgid "Resolution" -msgstr "分辨率" - msgid "" "G-code path is genereated after simplifing the contour of model to avoid too " "much points and gcode lines in gcode file. Smaller value means higher " @@ -6415,9 +6923,6 @@ msgstr "" "平滑模式,打印完每层后,工具头将移动到吐料槽,然后拍摄快照。由于平滑模式在拍" "摄快照的过程中熔丝可能会从喷嘴中泄漏,因此需要使用擦拭塔进行喷嘴擦拭。" -msgid "Smooth" -msgstr "平滑模式" - msgid "Traditional" msgstr "传统模式" @@ -6444,6 +6949,24 @@ msgstr "" "在三角形网格切片过程中,小于2倍间隙闭合半径的裂纹将被填充。间隙闭合操作可能会" "降低最终打印分辨率,因此建议降值保持在合理的较低水平" +msgid "Slicing Mode" +msgstr "切片模式" + +msgid "" +"Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to " +"close all holes in the model." +msgstr "" +"对3DLabPrint的飞机模型使用 \"奇偶\"。使用 \"闭孔 \"来关闭模型上的所有孔。" + +msgid "Regular" +msgstr "常规" + +msgid "Even-odd" +msgstr "奇偶" + +msgid "Close holes" +msgstr "闭孔" + msgid "Enable support" msgstr "开启支撑" @@ -6466,11 +6989,11 @@ msgstr "树状(自动)" msgid "hybrid(auto)" msgstr "混合(自动)" -msgid "normal" -msgstr "普通" +msgid "normal(manual)" +msgstr "普通(手动)" -msgid "tree" -msgstr "树状" +msgid "tree(manual)" +msgstr "树状(手动)" msgid "Support/object xy distance" msgstr "支撑/模型xy间距" @@ -6504,10 +7027,16 @@ msgstr "顶部Z距离" msgid "The z gap between the top support interface and object" msgstr "支撑顶部和模型之间的z间隙" +msgid "Bottom Z distance" +msgstr "底部Z距离" + +msgid "The z gap between the bottom support interface and object" +msgstr "支撑生成于模型表面时,支撑面底部和模型之间的z间隙" + msgid "" -"Filament to print support and skirt. 0 means no specific filament for " -"support and current filament is used" -msgstr "打印支撑和skirt的耗材丝。0代表不指定特定的耗材丝,并使用当前耗材" +"Filament to print support and raft. \"Default\" means no specific filament " +"for support and current filament is used" +msgstr "打印支撑和筏层的耗材丝。“默认”代表不指定特定的耗材丝,并使用当前耗材" msgid "Line width of support" msgstr "支撑的线宽" @@ -6520,9 +7049,9 @@ msgid "" msgstr "使用圈形走线覆盖顶部接触面。默认关闭。" msgid "" -"Filament to print support interface. 0 means no specific filament for " -"support interface and current filament is used" -msgstr "打印支撑接触面的耗材丝。0代表不指定特定的耗材丝,并使用当前耗材" +"Filament to print support interface. \"Default\" means no specific filament " +"for support interface and current filament is used" +msgstr "打印支撑接触面的耗材丝。“默认”代表不指定特定的耗材丝,并使用当前耗材" msgid "Top interface layers" msgstr "顶部接触面层数" @@ -6574,6 +7103,12 @@ msgstr "主体图案线距" msgid "Spacing between support lines" msgstr "支撑线距" +msgid "Normal Support expansion" +msgstr "普通支撑拓展" + +msgid "Expand (+) or shrink (-) the horizontal span of normal support" +msgstr "在水平方向对普通支撑进行拓展(+)或收缩(-)" + msgid "Speed of support" msgstr "支撑打印速度" @@ -6581,7 +7116,7 @@ msgid "Style" msgstr "样式" msgid "Snug" -msgstr "" +msgstr "紧贴" msgid "Independent support layer height" msgstr "支撑独立层高" @@ -6589,7 +7124,7 @@ msgstr "支撑独立层高" msgid "" "Support layer uses layer height independent with object layer. This is to " "support customizing z-gap and save print time." -msgstr "" +msgstr "支撑使用不同于对象的层高。这样可以支持自定义Z方向间隙并节省打印时间。" msgid "Threshold angle" msgstr "阈值角度" @@ -6629,14 +7164,6 @@ msgstr "树状支撑外墙层数" msgid "This setting specify the count of walls around tree support" msgstr "树状支撑外墙层数" -msgid "Tree support with infill" -msgstr "树状支撑生成填充" - -msgid "" -"This setting specifies whether to add infill inside large hollows of tree " -"support" -msgstr "这个设置决定是否为树状支撑内部的空腔生成填充。" - msgid "Nozzle temperature for layers after the initial one" msgstr "除首层外的其它层的喷嘴温度" @@ -6733,6 +7260,14 @@ msgstr "切换耗材丝时,打印擦拭塔来让准配好喷嘴里材料。" msgid "Purging volumes" msgstr "冲刷体积" +msgid "Flush multiplier" +msgstr "冲刷量乘数" + +msgid "" +"The actual flushing volumes is equal to the flush multiplier multiplied by " +"the flushing volumes in the table." +msgstr "实际冲刷量等于冲刷量乘数乘以表格单元中的冲刷量" + msgid "Prime volume" msgstr "清理量" @@ -6745,38 +7280,31 @@ msgstr "宽度" msgid "Width of prime tower" msgstr "擦拭塔宽度" -msgid "Flush into objects' infill" -msgstr "冲刷到对象的填充" - msgid "" "Purging after filament change will be done inside objects' infills. This may " "lower the amount of waste and decrease the print time. If the walls are " "printed with transparent filament, the mixed color infill will be seen " -"outside" +"outside. It will not take effect, unless the prime tower is enabled." msgstr "" "换料后的过渡料会被用来打印对象的填充。这样可以减少材料浪费和缩短打印时间,但" "是如果对象的内外墙是采用透明材料打印的,则可以从模型外观上看到内部的混色过渡" -"料" - -msgid "Flush into objects' support" -msgstr "冲刷到对象的支撑" +"料。该功能只有在启用料塔的时候才生效。" msgid "" "Purging after filament change will be done inside objects' support. This may " -"lower the amount of waste and decrease the print time" +"lower the amount of waste and decrease the print time. It will not take " +"effect, unless the prime tower is enabled." msgstr "" -"换料后的过渡料会被用来打印对象的支撑。这样可以减少材料浪费以及缩短打印时间" - -msgid "Flush into this object" -msgstr "冲刷到这个对象" +"换料后的过渡料会被用来打印对象的支撑。这样可以减少材料浪费以及缩短打印时间。" +"该功能只有在启用料塔的时候才生效。" msgid "" "This object will be used to purge the nozzle after a filament change to save " "filament and decrease the print time. Colours of the objects will be mixed " -"as a result" +"as a result. It will not take effect, unless the prime tower is enabled." msgstr "" "换料后的过渡料会被用来打印这个对象。这样可以减少材料浪费和缩短打印时间,但是" -"这个对象的外观会是混色的" +"这个对象的外观会是混色的。该功能只有在启用料塔的时候才生效。" msgid "X-Y hole compensation" msgstr "X-Y 孔洞尺寸补偿" @@ -6801,6 +7329,96 @@ msgstr "" "模型外轮廓的尺寸将在X-Y方向收缩或拓展特定值。正值代表扩大。负值代表缩小。这个" "功能通常在模型有装配问题时微调尺寸" +msgid "" +"Classic wall generator produces walls with constant extrusion width and for " +"very thin areas is used gap-fill. Arachne engine produces walls with " +"variable extrusion width" +msgstr "" +"经典墙生成器产生的墙走线具有一致的挤出宽度,对狭窄区域使用填缝。Arachne引擎则" +"产生变线宽的墙走线" + +msgid "Classic" +msgstr "经典" + +msgid "Arachne" +msgstr "Arachne" + +msgid "Wall transition length" +msgstr "墙过渡长度" + +msgid "" +"When transitioning between different numbers of walls as the part becomes " +"thinner, a certain amount of space is allotted to split or join the wall " +"segments. It's expressed as a percentage over nozzle diameter" +msgstr "" +"当零件逐渐变薄导致墙的层数发生变化时,需要在过渡段分配一定的空间来分割和连接" +"墙走线。参数值表示为相对于喷嘴直径的百分比" + +msgid "Wall transitioning filter margin" +msgstr "墙过渡过滤间距" + +msgid "" +"Prevent transitioning back and forth between one extra wall and one less. " +"This margin extends the range of extrusion widths which follow to [Minimum " +"wall width - margin, 2 * Minimum wall width + margin]. Increasing this " +"margin reduces the number of transitions, which reduces the number of " +"extrusion starts/stops and travel time. However, large extrusion width " +"variation can lead to under- or overextrusion problems. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" +"防止特定厚度变化规律的局部在多一层墙和少一层墙之间来回转换。这个参数将挤压宽" +"度的范围扩大到[墙最小宽度-参数值, 2*墙最小宽度+参数值]。增大参数可以减少转换" +"的次数,从而减少挤出开始/停止和空驶的时间。然而,大的挤出宽度变化会导致过挤出" +"或欠挤出的问题。参数值表示为相对于喷嘴直径的百分比" + +msgid "Wall transitioning threshold angle" +msgstr "墙过渡阈值角度" + +msgid "" +"When to create transitions between even and odd numbers of walls. A wedge " +"shape with an angle greater than this setting will not have transitions and " +"no walls will be printed in the center to fill the remaining space. Reducing " +"this setting reduces the number and length of these center walls, but may " +"leave gaps or overextrude" +msgstr "" +"何时在偶数和奇数墙层数之间创建过渡段。角度大于这个阈值的楔形将不创建过渡段," +"并且不会在楔形中心打印墙走线以填补剩余空间。减小这个数值能减少中心墙走线的数" +"量和长度,但可能会导致间隙或者过挤出" + +msgid "Wall distribution count" +msgstr "墙分布计数" + +msgid "" +"The number of walls, counted from the center, over which the variation needs " +"to be spread. Lower values mean that the outer walls don't change in width" +msgstr "" +"从中心开始计算的墙层数,线宽变化需要分布在这些墙走线上。较低的数值意味着外墙" +"宽度更不易被改变" + +msgid "Minimum feature size" +msgstr "最小特征尺寸" + +msgid "" +"Minimum thickness of thin features. Model features that are thinner than " +"this value will not be printed, while features thicker than the Minimum " +"feature size will be widened to the Minimum wall width. It's expressed as a " +"percentage over nozzle diameter" +msgstr "" +"薄壁特征的最小厚度。比这个数值还薄的特征将不被打印,而比最小特征厚度还厚的特" +"征将被加宽到墙最小宽度。参数值表示为相对喷嘴直径的百分比" + +msgid "Minimum wall width" +msgstr "墙最小线宽" + +msgid "" +"Width of the wall that will replace thin features (according to the Minimum " +"feature size) of the model. If the Minimum wall width is thinner than the " +"thickness of the feature, the wall will become as thick as the feature " +"itself. It's expressed as a percentage over nozzle diameter" +msgstr "" +"用于替换模型细小特征(根据最小特征尺寸)的墙线宽。如果墙最小线宽小于最小特征" +"的厚度,则墙将变得和特征本身一样厚。参数值表示为相对喷嘴直径的百分比" + msgid "Detect narrow internal solid infill" msgstr "识别狭窄内部实心填充" @@ -6818,12 +7436,30 @@ 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 the plates: 0-all plates, i-plate i, others-invalid" msgstr "" msgid "Show command help." msgstr "显示命令行帮助。" +msgid "UpToDate" +msgstr "" + +msgid "Update the configs values of 3mf to latest." +msgstr "" + msgid "Output Model Info" msgstr "输出模型信息" @@ -6836,6 +7472,12 @@ msgstr "导出配置" msgid "Export settings to a file." msgstr "导出配置到文件。" +msgid "Send progress to pipe" +msgstr "" + +msgid "Send progress to pipe." +msgstr "" + msgid "Arrange Options" msgstr "摆放选项" @@ -6851,12 +7493,6 @@ msgstr "转换模型的单位" msgid "Orient the model" msgstr "旋转模型" -msgid "Repair" -msgstr "修复" - -msgid "Repair the model's meshes if it is non-manifold mesh" -msgstr "修复模型网格" - msgid "Scale the model by a float factor" msgstr "根据因子缩放模型" @@ -6929,9 +7565,6 @@ msgstr "模型有太多空层。" msgid "Slicing mesh" msgstr "正在切片网格" -msgid " Object:" -msgstr " 对象:" - #, c-format, boost-format msgid "Support: generate toolpath at layer %d" msgstr "支撑:正在生成层%d的走线路径" @@ -7013,7 +7646,7 @@ msgid "" "printing by a simple click?" msgstr "" "自动朝向\n" -"您知道吗?您只需单击鼠标,即可将对象旋转到适合的打印方向?" +"您知道吗,您只需单击鼠标,即可将对象旋转到适合的打印方向。" #: resources/data/hints.ini: [hint:Lay on Face] msgid "" @@ -7023,7 +7656,7 @@ msgid "" "F key." msgstr "" "放置在面部\n" -"您知道吗?您可以快速指定模型的底面,使其位于打印床上。选择“放置在面部”功能或" +"您知道吗,您可以快速指定模型的底面,使其位于打印床上。选择“放置在面部”功能或" "按F键。" #: resources/data/hints.ini: [hint:Object List] @@ -7044,7 +7677,7 @@ msgid "" "more in the documentation." msgstr "" "简化模型\n" -"您知道吗?您可以使用“简化模型”功能减少模型的三角形数。在模型上单击鼠标右键," +"您知道吗,您可以使用“简化模型”功能减少模型的三角形数。在模型上单击鼠标右键," "然后选择“简化模型”。" #: resources/data/hints.ini: [hint:Slicing Parameter Table] @@ -7063,7 +7696,7 @@ msgid "" "colorizing or printing?" msgstr "" "分割成对象/零件\n" -"您知道吗?您可以把一个大对象分割成多个小对象/零件以便着色或打印吗?" +"您知道吗,您可以把一个大对象分割成多个小对象/零件以便着色或打印。" #: resources/data/hints.ini: [hint:Subtract a Part] msgid "" @@ -7073,8 +7706,8 @@ msgid "" "directly in Bambu Studio. Read more in the documentation." msgstr "" "减去部分几何体\n" -"您知道吗?您可以使用负零件从另一个几何体中减去另一个几何体。例如,这样可以直" -"接在Bambu Studio中创建可轻松调整大小的孔。" +"您知道吗,您可以使用负零件从另一个几何体中减去另一个几何体。例如,可以直接在" +"Bambu Studio中创建可轻松调整大小的孔。" #: resources/data/hints.ini: [hint:STEP] msgid "" @@ -7085,7 +7718,7 @@ msgid "" "lower resolution STL. Give it a try!" msgstr "" "STEP文件\n" -"您知道吗?通过切片STEP文件而不是STL文件可以提高打印质量?\n" +"您知道吗,通过切片STEP文件而不是STL文件可以提高打印质量。\n" "Bambu Studio支持切片STEP文件,提供比低分辨率STL更平滑的结果。试试看!" #: resources/data/hints.ini: [hint:Z seam location] @@ -7096,8 +7729,8 @@ msgid "" "the overall look of your model. Check it out!" msgstr "" "Z接缝位置\n" -"您知道吗?您可以自定义Z接缝的位置,甚至可以将其绘制在打印上,使其位于不太可见" -"的位置?这样可以改善模型的整体外观。试试看!" +"您知道吗,您可以自定义Z接缝的位置,甚至可以将其绘制在打印上,使其位于不太可见" +"的位置。这样可以改善模型的整体外观。试试看!" #: resources/data/hints.ini: [hint:Fine-tuning for flow rate] msgid "" @@ -7107,8 +7740,8 @@ msgid "" "printed model by doing some fine-tuning." msgstr "" "流量微调\n" -"你知道吗?您可以微调流量,以获得更好看的打印效果吗?根据材料的不同,可以通过" -"进行一些微调来提高打印模型的整体光洁度。" +"你知道吗,您可以微调流量,以获得更好看的打印效果。根据材料的不同,可以通过进" +"行一些微调来提高打印模型的整体光洁度。" #: resources/data/hints.ini: [hint:Split your prints into plates] msgid "" @@ -7118,7 +7751,7 @@ msgid "" "track of all the parts." msgstr "" "分盘打印\n" -"您知道吗?您可以把一个有很多零件的模型安排到多个独立的分盘,然后打印出来,这" +"您知道吗,您可以把一个有很多零件的模型安排到多个独立的分盘,然后打印出来,这" "将简化对所有零件的管理。" #: resources/data/hints.ini: [hint:Speed up your print with Adaptive Layer @@ -7129,7 +7762,7 @@ msgid "" "Layer Height option? Check it out!" msgstr "" "自适应层高度加速打印\n" -"您知道吗?您可以使用“自适应层高度”选项可以更快地打印模型。试试看!" +"您知道吗,您可以使用“自适应层高度”选项可以更快地打印模型。试试看!" #: resources/data/hints.ini: [hint:Support painting] msgid "" @@ -7139,7 +7772,7 @@ msgid "" "model that actually need it." msgstr "" "绘制支撑\n" -"您知道吗?您可以手动绘制添加/屏蔽支撑的位置,此功能使仅将支撑材料放置在实际需" +"您知道吗,您可以手动绘制添加/屏蔽支撑的位置,此功能使仅将支撑材料放置在实际需" "要的模型截面上变得容易。" #: resources/data/hints.ini: [hint:Different types of supports] @@ -7150,7 +7783,7 @@ msgid "" "print speed. Check them out!" msgstr "" "支撑类型\n" -"您知道吗?有多种可选的支撑类型,树状支撑非常适合人物/动物模型,同时可以节耗材" +"您知道吗,有多种可选的支撑类型,树状支撑非常适合人物/动物模型,同时可以节耗材" "并提高打印速度。试试看!" #: resources/data/hints.ini: [hint:Printing Silk Filament] @@ -7161,8 +7794,8 @@ msgid "" "the best results." msgstr "" "打印丝绸耗材\n" -"你知道丝绸耗材需要特别考虑才能成功打印吗?为了获得最佳效果,通常建议使用较高" -"的温度和较低的速度。" +"你知道吗,丝绸耗材需要特别考虑才能成功打印。为了获得最佳效果,通常建议使用较" +"高的温度和较低的速度。" #: resources/data/hints.ini: [hint:Brim for better adhesion] msgid "" @@ -7180,20 +7813,285 @@ msgid "" "one time?" msgstr "" "为多个对象设置参数\n" -"您知道可以同时为所有选定对象设置切片参数吗?" +"您知道吗,可以同时为所有选定对象设置切片参数。" -#~ msgid "Print By Object" -#~ msgstr "逐件打印" +#: resources/data/hints.ini: [hint:Stack objects] +msgid "" +"Stack objects\n" +"Did you know that you can stack objects as a whole one?" +msgstr "" +"组合物体\n" +"你知道吗?你可以把多个对象组合为一个整体。" -#~ msgid "Suggest to use auto-arrange to avoid collisions when printing." -#~ msgstr "建议您使用自动摆盘避免打印时发生碰撞。" +#: resources/data/hints.ini: [hint:Flush into support/objects/infill] +msgid "" +"Flush into support/objects/infill\n" +"Did you know that you can save the wasted filament by flushing them into " +"support/objects/infill during filament change?" +msgstr "" +"冲刷到支持/对象/填充中\n" +"你知道吗?你可以在换料时将它们冲入支撑/对象/填充,以节省浪费的料丝。" + +#: resources/data/hints.ini: [hint:Improve strength] +msgid "" +"Improve strength\n" +"Did you know that you can use more wall loops and higher sparse infill " +"density to improve the strength of the model?" +msgstr "" +"提高强度\n" +"你知道吗?你可以使用更多的墙层数和更高的疏散填充密度来提高模型的强度。" #~ msgid "" -#~ "Print By Object\n" -#~ "Suggest to use auto-arrange to avoid collisions when printing." +#~ "When sparse infill density is low, the internal solid infill or internal " +#~ "bridge may have no archor at the end of line. This cause falling and bad " +#~ "quality when printing internal solid infill. When enable this feature, " +#~ "loop paths will be added to the sparse fill of the lower layers for " +#~ "specific thickness, so that better archor can be provided for internal " +#~ "bridge. 0 means disable this feature" #~ msgstr "" -#~ "逐件打印:\n" -#~ "建议使用自动摆盘避免打印时发生碰撞。" +#~ "当稀疏填充密度很低时,内部实心填充或内部桥接可能在走线转角处没有铆接。这导" +#~ "致内部实心填充打印失败或者打印质量差。开启这个设置时,将会在低层的稀疏填充" +#~ "中打印指定厚度的环形走线,为内部桥接提供更好的铆接。0值代表关闭该功能。" + +#~ msgid "" +#~ "If enabled, Studio will generate support loops under the contours of " +#~ "internal bridges.These support loops could prevent internal bridges from " +#~ "extruding over the air and improve the top surface quality, expecially " +#~ "with a low infill density.This value determins the thickness of the " +#~ "support loops." +#~ msgstr "" +#~ "如果开启,Studio沿着内部桥接的边缘在其下方生成支撑轮廓。这些支撑轮廓可以防" +#~ "止悬空打印内部桥接并提高顶面质量,特别是在填充密度较低的情况下。这个设置用" +#~ "于调整支撑轮廓的厚度。" + +#~ msgid "Choose one or more files (3mf/step/stl/obj/amf):" +#~ msgstr "选择一个或多个文件(3mf/step/stl/obj/amf):" + +#~ msgid "Finish" +#~ msgstr "完成" + +#~ msgid "Import 3MF/STL/STEP/OBJ/AMF" +#~ msgstr "导入 3MF/STL/STEP/OBJ/AMF" + +#~ msgid "Virtual Camera" +#~ msgstr "虚拟摄像头" + +#~ msgid "Part Cooling" +#~ msgstr "部件冷却" + +#~ msgid "Aux Cooling" +#~ msgstr "辅助冷却" + +#~ msgid "Same as global bed type" +#~ msgstr "跟随全局热床类型设置" + +#~ msgid "" +#~ "Filament to print support and skirt. 0 means no specific filament for " +#~ "support and current filament is used" +#~ msgstr "打印支撑和skirt的耗材丝。0代表不指定特定的耗材丝,并使用当前耗材" + +#~ msgid "" +#~ "Filament to print support interface. 0 means no specific filament for " +#~ "support interface and current filament is used" +#~ msgstr "打印支撑接触面的耗材丝。0代表不指定特定的耗材丝,并使用当前耗材" + +#~ msgid "Repair" +#~ msgstr "修复" + +#~ msgid "Repair the model's meshes if it is non-manifold mesh" +#~ msgstr "修复模型网格" + +#~ msgid "Heat the nozzle to target temperature" +#~ msgstr "加热喷嘴" + +#~ msgid "Show 'Streaming Video' guide page." +#~ msgstr "展示 'Streaming Video' 引导页" + +#~ msgid "" +#~ "Successfully sent. Will automatically jump to the device page in %s s" +#~ msgstr "已发送完成,即将自动跳转到设备页面(%s秒)" + +#~ msgid "" +#~ "AMS switches to the same type of filament automatically when the current " +#~ "filament runs out." +#~ msgstr "AMS料材耗尽后将自动切换相同类型的料材。" + +#~ msgid "Tower" +#~ msgstr "擦料塔" + +#~ msgid "Monitoring Recording" +#~ msgstr "监控录像" + +#~ msgid "" +#~ "Failed to save the project.\n" +#~ "Please check whether the project file is opened by other programs." +#~ msgstr "" +#~ "保存项目失败。\n" +#~ "请检查项目文件是否被其他程序打开。" + +#~ msgid "Go to layer" +#~ msgstr "跳转到层" + +#~ msgid "Layer number" +#~ msgstr "层数" + +#~ msgid "Edit Object Process" +#~ msgstr "编辑对象工艺" + +#~ msgid "Switch to per-object setting mode to edit object process." +#~ msgstr "切换到对象模式以编辑对象的工艺。" + +#~ msgid "" +#~ "The flush volume is less than the minimum value and will be automatically " +#~ "set to the minimum value." +#~ msgstr "冲刷体积小于最小值,将被自动设置为最小值" + +#~ msgid "Perimeter transitioning threshold angle" +#~ msgstr "墙过渡阈值角度" + +#~ msgid "Perimeter distribution count" +#~ msgstr "墙分布计数" + +#~ msgid "Layers and Perimeters" +#~ msgstr "层和墙" + +#~ msgid "Send to Printer" +#~ msgstr "发送到打印机" + +#~ msgid "" +#~ "Virtual camera is started.\n" +#~ "Press 'OK' to navigate the guide page of 'Streaming video of Bambu " +#~ "Printer'." +#~ msgstr "" +#~ "虚拟摄像头已经启动。点击“确认”打开相关帮助页面:'Streaming video of Bambu " +#~ "Printer'。" + +#~ msgid "Tree support with infill" +#~ msgstr "树状支撑生成填充" + +#~ msgid "" +#~ "This setting specifies whether to add infill inside large hollows of tree " +#~ "support" +#~ msgstr "这个设置决定是否为树状支撑内部的空腔生成填充。" + +#~ msgid "Entering Seam painting" +#~ msgstr "进入Z缝绘制" + +#~ msgid "Leaving Seam painting" +#~ msgstr "退出Z缝绘制" + +#~ msgid "Paint-on seam editing" +#~ msgstr "编辑手绘填缝" + +#~ msgid "Export ok." +#~ msgstr "导出成功." + +#~ msgid "Plate %d: %s does not support filament %s.\n" +#~ msgstr "盘%d:%s不支持耗材丝%s\n" + +#~ msgid "Not supported." +#~ msgstr "不支持" + +#~ msgid "Spaghetti and Excess Chute Pileup Detection" +#~ msgstr "炒面与堆料检查" + +#~ msgid "Stop printing when Spaghetti or Excess Chute Pileup is detected" +#~ msgstr "当发生炒面或废料口堆料时停止打印" + +#~ msgid "Sync material list from AMS" +#~ msgstr "同步到 AMS 的材料列表" + +#~ msgid "Filament N XX" +#~ msgstr "打印丝 N XX" + +#~ msgid "Color Print" +#~ msgstr "彩色打印" + +#~ msgid "Comsumption" +#~ msgstr "消耗" + +#~ msgid "Filament 1" +#~ msgstr "耗材丝 1" + +#~ msgid "Flushed filament" +#~ msgstr "换料冲刷消耗" + +#~ msgid "Initialize failed (Not supported without remote video tunnel)!" +#~ msgstr "初始化失败(不支持远程视频连接)" + +#~ msgid "Adaptive layer height" +#~ msgstr "自适应层高" + +#~ msgid "" +#~ "Enabling this option means the height of every layer except the first " +#~ "will be automatically calculated during slicing according to the slope of " +#~ "the model’s surface.\n" +#~ "Note that this option only takes effect if no prime tower is generated in " +#~ "current plate." +#~ msgstr "" +#~ "开启这个选项,程序会在切片的过程中根据模型表面的倾斜度自动计算每层的层高," +#~ "首层除外。\n" +#~ "注意这个选项仅在当前盘不存在擦拭塔的情况下生效。" + +#~ msgid "normal" +#~ msgstr "普通" + +#~ msgid "tree" +#~ msgstr "树状" + +#~ msgid " Object:" +#~ msgstr " 对象:" + +#~ msgid "Please check the following infomation:\n" +#~ msgstr "请确认以下信息后发送打印:\n" + +#~ msgid "" +#~ "You have changed some preset settings. \n" +#~ "Would you like to keep these changed settings after switching preset?" +#~ msgstr "" +#~ "您有一些修改过的设置。\n" +#~ "切换预设后,是否要保留这些更改过的设置?" + +#~ msgid "Export sliced file" +#~ msgstr "导出切片文件" + +#~ msgid "Export Sliced File" +#~ msgstr "导出切片文件" + +#~ msgid "Add Custom Printer" +#~ msgstr "添加自定义打印机" + +#~ msgid "Show Log" +#~ msgstr "显示日志" + +#~ msgid "Export current Sliced file" +#~ msgstr "导出当前已切片的文件" + +#~ msgid "Publish Project" +#~ msgstr "发布项目" + +#~ msgid "" +#~ "Force cooling fan to be specific speed when overhang degree of printed " +#~ "part exceeds this value. Expressed as percentage which indicides how much " +#~ "width of the line without support from lower layer" +#~ msgstr "" +#~ "当打印部分的悬垂程度超出设定值,强制冷却风扇为设置的速度。悬垂程度表示为未" +#~ "被低层支撑的部分占线宽的百分比" + +#~ msgid "" +#~ "Distance of the nozzle tip to the lower rod. Used as input of auto-" +#~ "arranging to avoid collision when printing by object" +#~ msgstr "挤出头尖端到下方滑杆的距离。用于逐件打印的自动摆盘" + +#~ msgid "" +#~ "Distance of the nozzle tip to the lid. Used as input of auto-arranging to " +#~ "avoid collision when printing by object" +#~ msgstr "挤出头尖端到顶盖的距离。用于逐件打印的自动摆盘。" + +#~ msgid "" +#~ "Clearance radius around extruder. Used as input of auto-arranging to " +#~ "avoid collision when printing by object" +#~ msgstr "挤出机的避让半径。用于逐件打印的自动摆盘" #~ msgid "Send and Print" #~ msgstr "发送并打印" @@ -7201,6 +8099,18 @@ msgstr "" #~ msgid "Can't connect to the printer" #~ msgstr "无法连接打印机" +#~ msgid "Upgrade firmware" +#~ msgstr "升级固件" + +#~ msgid "Upgrading" +#~ msgstr "升级中" + +#~ msgid "Upgrading failed" +#~ msgstr "升级失败" + +#~ msgid "Upgrading successful" +#~ msgstr "升级成功" + #~ msgid "Show &Wireframe" #~ msgstr "显示线框" @@ -7897,21 +8807,9 @@ msgstr "" #~ msgid "Object %s has zero size and can't be arranged." #~ msgstr "对象%s的尺寸为0,无法被自动摆放。" -#~ msgid "Importing Model" -#~ msgstr "正在导入模型" - -#~ msgid "prepare 3mf file..." -#~ msgstr "正在准备3mf文件..." - #~ msgid "Import project failed, Please try again!" #~ msgstr "加载项目失败,请重试!" -#~ msgid "downloading project ..." -#~ msgstr "项目下载中..." - -#~ msgid "Project downloaded %d%%" -#~ msgstr "项目已下载%d%%" - #~ msgid "Failed to publish your project. Please try agian!" #~ msgstr "项目发布失败。请重试!" @@ -8180,9 +9078,6 @@ msgstr "" #~ msgid "No objects to export." #~ msgstr "没有可导出的对象。" -#~ msgid "Save project" -#~ msgstr "保存项目" - #~ msgid "Event" #~ msgstr "事件" @@ -8760,9 +9655,6 @@ msgstr "" #~ msgid "New Version of BambuStudio" #~ msgstr "新版本的BambuStudio" -#~ msgid "Print plate" -#~ msgstr "打印单盘" - #~ msgid "Switching Presets: Unsaved Changes" #~ msgstr "切换预设:未保存的更改" @@ -8916,12 +9808,6 @@ msgstr "" #~ msgid "mm/s or %" #~ msgstr "mm/s 或 %" -#~ msgid "Bottom Z distance" -#~ msgstr "底部Z距离" - -#~ msgid "The z gap between the bottom support interface and object" -#~ msgstr "支撑生成于模型表面时,支撑面底部和模型之间的z间隙" - #~ msgid "Wall around the support" #~ msgstr "支撑外壁" @@ -8953,9 +9839,6 @@ msgstr "" #~ msgid "Value is out of range, continue?" #~ msgstr "值越界,是否继续?" -#~ msgid "Default color" -#~ msgstr "缺省颜色" - #~ msgid "Tool Rotate" #~ msgstr "工具 旋转" @@ -9007,9 +9890,6 @@ msgstr "" #~ msgid "Switch Language" #~ msgstr "切换语言" -#~ msgid "Add/Remove printers" -#~ msgstr "添加/删除打印机" - #~ msgid "" #~ "Speed of outer wall which is outermost and visible. It's relative to " #~ "inner wall speed if expressed as percentage" @@ -9092,12 +9972,6 @@ msgstr "" #~ msgid "Exporting finished." #~ msgstr "导出完成。" -#~ msgid "Add/Remove filaments" -#~ msgstr "添加/删除材料" - -#~ msgid "Add/Remove materials" -#~ msgstr "添加/删除材料" - #~ msgid "System Information" #~ msgstr "系统信息" @@ -9693,9 +10567,6 @@ msgstr "" #~ msgid "Use single nozzle to print multi filament" #~ msgstr "使用单喷嘴打印多耗材" -#~ msgid "Slicing Mode" -#~ msgstr "切片模式" - #~ msgid "Bottom contact Z distance" #~ msgstr "底部Z距离" @@ -9902,9 +10773,6 @@ msgstr "" #~ msgid "Enforce" #~ msgstr "添加" -#~ msgid "On overhangs only" -#~ msgstr "仅对悬空区生效" - #~ msgid "Overhang Threshold Angle" #~ msgstr "悬空角度阈值" @@ -9916,9 +10784,6 @@ msgstr "" #~ "angle." #~ msgstr "绘制一组连续面片,满足相邻面片之间的相对角度小于等于设定的阈值。" -#~ msgid "Allows painting only on facets selected by: \"%1%\"" -#~ msgstr "绘制仅对由%1%选中的面片生效" - #~ msgid "Paints only one facet." #~ msgstr "仅绘制单个面片。" @@ -10084,9 +10949,6 @@ msgstr "" #~ msgid "Physical Printer" #~ msgstr "物理打印机" -#~ msgid "Information" -#~ msgstr "信息" - #~ msgid "Please check your object list before preset changing." #~ msgstr "请在预设更改之前检查对象列表。" @@ -10909,51 +11771,9 @@ msgstr "" #~ msgid "Set Unprintable Instance" #~ msgstr "设置不可打印的实例" -#~ msgid "Variable layer height" -#~ msgstr "可变层高" - -#~ msgid "Left mouse button:" -#~ msgstr "鼠标左键:" - -#~ msgid "Add detail" -#~ msgstr "减小层高" - -#~ msgid "Right mouse button:" -#~ msgstr "鼠标右键:" - -#~ msgid "Remove detail" -#~ msgstr "增大层高" - -#~ msgid "Shift + Left mouse button:" -#~ msgstr "Shift + 鼠标左键:" - -#~ msgid "Reset to base" -#~ msgstr "设置到基础层高" - -#~ msgid "Shift + Right mouse button:" -#~ msgstr "Shift + 鼠标右键:" - -#~ msgid "Smoothing" -#~ msgstr "平滑" - -#~ msgid "Mouse wheel:" -#~ msgstr "鼠标滚轮:" - -#~ msgid "Increase/decrease edit area" -#~ msgstr "增加/减小编辑区域" - -#~ msgid "Adaptive" -#~ msgstr "自适应" - -#~ msgid "Quality / Speed" -#~ msgstr "细节/速度" - #~ msgid "Higher print quality versus higher print speed." #~ msgstr "高精度 vs 高速度。" -#~ msgid "Keep min" -#~ msgstr "保留最小" - #~ msgid "Variable layer height - Manual edit" #~ msgstr "可变层高 - 手动编辑" diff --git a/bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp b/bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp index 34af7964e2..aad8a1a576 100644 --- a/bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp +++ b/bbs_test_tools/bbs_gcode_checker/GCodeChecker.cpp @@ -2,12 +2,12 @@ #include #include #include - +#include namespace BambuStudio { //BBS: only check wodth when dE is longer than this value const double CHECK_WIDTH_E_THRESHOLD = 0.0025; -const double WIDTH_THRESHOLD = 0.012; +const double WIDTH_THRESHOLD = 0.02; const double RADIUS_THRESHOLD = 0.005; const double filament_diameter = 1.75; @@ -19,6 +19,11 @@ const std::string Wipe_Start_Tag = " WIPE_START"; const std::string Wipe_End_Tag = " WIPE_END"; const std::string Layer_Change_Tag = " CHANGE_LAYER"; const std::string Height_Tag = " LAYER_HEIGHT: "; +const std::string filament_flow_ratio_tag = " filament_flow_ratio"; +const std::string nozzle_temperature_Tag = " nozzle_temperature ="; +const std::string nozzle_temperature_initial_layer_Tag = " nozzle_temperature_initial_layer"; +const std::string Z_HEIGHT_TAG = " Z_HEIGHT: "; +const std::string Initial_Layer_Ptint_Height_Tag = " initial_layer_print_height ="; GCodeCheckResult GCodeChecker::parse_file(const std::string& path) { @@ -105,6 +110,19 @@ GCodeCheckResult GCodeChecker::parse_comment(GCodeLine& line) // extrusion role tag if (starts_with(comment, Extrusion_Role_Tag)) { m_role = string_to_role(comment.substr(Extrusion_Role_Tag.length())); + if (m_role == erExternalPerimeter) { + + if (z_height == initial_layer_height && nozzle_temp != nozzle_temperature_initial_layer[filament_id]) { + std::cout << "invalid filament nozzle initial layer temperature comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + + if (z_height != initial_layer_height && nozzle_temp != nozzle_temperature[filament_id]) { + std::cout << "invalid filament nozzle temperature comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + } + } else if (starts_with(comment, Wipe_Start_Tag)) { m_wiping = true; } else if (starts_with(comment, Wipe_End_Tag)) { @@ -123,7 +141,41 @@ GCodeCheckResult GCodeChecker::parse_comment(GCodeLine& line) } } else if (starts_with(comment, Layer_Change_Tag)) { m_layer_num++; + } else if (starts_with(comment, filament_flow_ratio_tag)) + { + std::string str = comment.substr(filament_flow_ratio_tag.size()+3); + if (!parse_double_from_str(str, filament_flow_ratio)) + { + std::cout << "invalid filament flow ratio comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } } + else if (starts_with(comment, nozzle_temperature_Tag)) { + std::string str = comment.substr(nozzle_temperature_Tag.size() + 1); + if (!parse_double_from_str(str, nozzle_temperature)) { + std::cout << "invalid nozzle temperature comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + } + else if (starts_with(comment, nozzle_temperature_initial_layer_Tag)) { + std::string str = comment.substr(nozzle_temperature_initial_layer_Tag.size() + 3); + if (!parse_double_from_str(str, nozzle_temperature_initial_layer)) { + std::cout << "invalid nozzle temperature initial layer comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + } else if (starts_with(comment, Z_HEIGHT_TAG)) { + std::string str = comment.substr(Z_HEIGHT_TAG.size()); + if (!parse_double_from_str(str, z_height)) { + std::cout << "invalid z height comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + } else if (starts_with(comment, Initial_Layer_Ptint_Height_Tag)) { + std::string str = comment.substr(Initial_Layer_Ptint_Height_Tag.size()); + if (!parse_double_from_str(str, initial_layer_height)) { + std::cout << "invalid initial layer height comment with invalid value!" << std::endl; + return GCodeCheckResult::ParseFailed; + } + } return GCodeCheckResult::Success; } @@ -153,11 +205,32 @@ GCodeCheckResult GCodeChecker::parse_command(GCodeLine& gcode_line) { case 82: { ret = parse_M82(gcode_line); break; } // Set to Absolute extrusion case 83: { ret = parse_M83(gcode_line); break; } // Set to Relative extrusion + case 104: { + ret = parse_M104_M109(gcode_line); + break; + } // Set to nozzle temperature + case 109: { + ret = parse_M104_M109(gcode_line); + break; + } // Set to nozzle temperature default: { break; } } break; } case 'T':{ + + int pt = ::atoi(&cmd[1]); + if (pt == 1000 || pt == 1100 || pt == 255) { + break; + } + + if (pt < 0 || pt > 254 || pt >= filament_flow_ratio.size()) { + std::cout << "Invalid T command"<& source, const std::array& target, double e, double height, bool is_bridge) const { - double volume = e * Pi * (filament_diameter/2.0f) * (filament_diameter/2.0f); + double volume = (e / flow_ratio) * Pi * (filament_diameter / 2.0f) * (filament_diameter / 2.0f); std::array delta = { target[0] - source[0], target[1] - source[1], target[2] - source[2] }; @@ -389,8 +481,9 @@ double GCodeChecker::calculate_G2_G3_width(const std::array& source, (radian < 0 ? -radian : 2 * Pi - radian); double radius = sqrt(v1[0] * v1[0] + v1[1] * v1[1]); double length = radius * radian; - double volume = e * Pi * (filament_diameter/2) * (filament_diameter/2); + double volume = (e / flow_ratio) * Pi * (filament_diameter / 2) * (filament_diameter / 2); double mm3_per_mm = volume / length; + return is_bridge? 2 * sqrt(mm3_per_mm/Pi) : (mm3_per_mm / height) + height * (1 - 0.25 * Pi); } @@ -481,12 +574,15 @@ GCodeCheckResult GCodeChecker::check_G0_G1_width(const GCodeLine& line) std::array target = { m_end_position[X], m_end_position[Y], m_end_position[Z] }; bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill; - double width_real = calculate_G1_width(source, target, delta_pos[E], m_height, is_bridge); - if (fabs(width_real - m_width) > WIDTH_THRESHOLD) { - std::cout << "Invalid G0_G1 because has abnormal line width." << std::endl; - std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl; - return GCodeCheckResult::CheckFailed; + if (!is_bridge) { + double width_real = calculate_G1_width(source, target, delta_pos[E], m_height, is_bridge); + if (fabs(width_real - m_width) > WIDTH_THRESHOLD) { + std::cout << "Invalid G0_G1 because has abnormal line width." << std::endl; + std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl; + return GCodeCheckResult::CheckFailed; + } } + } return GCodeCheckResult::Success; @@ -556,12 +652,16 @@ GCodeCheckResult GCodeChecker::check_G2_G3_width(const GCodeLine& line) m_role != erGapFill && delta_e > CHECK_WIDTH_E_THRESHOLD) { bool is_bridge = m_role == erOverhangPerimeter || m_role == erBridgeInfill; - double width_real = calculate_G2_G3_width(source, target, center, is_ccw, delta_e, m_height, is_bridge); - if (fabs(width_real - m_width) > WIDTH_THRESHOLD) { - std::cout << "Invalid G2_G3 because has abnormal line width." << std::endl; - std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl; - return GCodeCheckResult::CheckFailed; + + if (!is_bridge) { + double width_real = calculate_G2_G3_width(source, target, center, is_ccw, delta_e, m_height, is_bridge); + if (fabs(width_real - m_width) > WIDTH_THRESHOLD) { + std::cout << "Invalid G2_G3 because has abnormal line width." << std::endl; + std::cout << "Width: " << m_width << " Width_real: " << width_real << std::endl; + return GCodeCheckResult::CheckFailed; + } } + } return GCodeCheckResult::Success; diff --git a/bbs_test_tools/bbs_gcode_checker/GCodeChecker.h b/bbs_test_tools/bbs_gcode_checker/GCodeChecker.h index 74fb859b92..f908ebfb89 100644 --- a/bbs_test_tools/bbs_gcode_checker/GCodeChecker.h +++ b/bbs_test_tools/bbs_gcode_checker/GCodeChecker.h @@ -108,6 +108,7 @@ private: GCodeCheckResult parse_G92(GCodeLine& gcode_line); GCodeCheckResult parse_M82(const GCodeLine& gcode_line); GCodeCheckResult parse_M83(const GCodeLine& gcode_line); + GCodeCheckResult parse_M104_M109(const GCodeLine &gcode_line); GCodeCheckResult parse_comment(GCodeLine& gcode_line); @@ -160,6 +161,38 @@ public: } } + static bool parse_double_from_str(const std::string &input, std::vector &out) + { + + std::string cmd=input; + size_t read = 0; + + while (cmd.size() >= 5) + { + int pt = 0; + for (pt = 0; pt < cmd.size(); pt++) { + char temp = cmd[pt]; + if (temp == ',') + { + try { + double num = std::stod(cmd.substr(0, pt), &read); + + out.push_back(num); + cmd = cmd.substr(pt+1); + break; + } catch (...) { + return false; + } + } + } + } + + double num = std::stod(cmd, &read); + out.push_back(num); + + return true; + } + private: EPositioningType m_global_positioning_type = EPositioningType::Absolute; EPositioningType m_e_local_positioning_type = EPositioningType::Absolute; @@ -174,6 +207,14 @@ private: int m_layer_num = 0; double m_height = 0.0; double m_width = 0.0; + double z_height=0.0f; + double initial_layer_height=0.0f; + int filament_id; + double flow_ratio = 0; + double nozzle_temp = 0.0f; + std::vector filament_flow_ratio; + std::vector nozzle_temperature; + std::vector nozzle_temperature_initial_layer; }; } diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in index ac2b87880b..d513c387a3 100644 --- a/cmake/modules/MacOSXBundleInfo.plist.in +++ b/cmake/modules/MacOSXBundleInfo.plist.in @@ -116,8 +116,6 @@ CSResourcesFileMapped - NSRequiresAquaSystemAppearance - NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} diff --git a/deps/CURL/CURL.cmake b/deps/CURL/CURL.cmake index f5fd6988fc..b369caed21 100644 --- a/deps/CURL/CURL.cmake +++ b/deps/CURL/CURL.cmake @@ -31,8 +31,8 @@ elseif (APPLE) ${_curl_platform_flags} - -DCMAKE_USE_SECTRANSP:BOOL=ON - -DCMAKE_USE_OPENSSL:BOOL=OFF + #-DCMAKE_USE_SECTRANSP:BOOL=ON + -DCMAKE_USE_OPENSSL:BOOL=ON -DCURL_CA_PATH:STRING=none ) diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index bdc6b6dfc2..2bdffba590 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -7,6 +7,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(_gtk_ver 3) endif () set(_wx_toolkit "-DwxBUILD_TOOLKIT=gtk${_gtk_ver}") + set(_wx_private_font "-DwxUSE_PRIVATE_FONTS=1") +else () + set(_wx_private_font "-DwxUSE_PRIVATE_FONTS=0") endif() if (MSVC) @@ -30,6 +33,7 @@ bambustudio_add_cmake_project(wxWidgets -DwxUSE_MEDIACTRL=ON -DwxUSE_DETECT_SM=OFF -DwxUSE_UNICODE=ON + ${_wx_private_font} -DwxUSE_OPENGL=ON -DwxUSE_WEBVIEW=ON ${_wx_edge} diff --git a/localazy.json b/localazy.json index 5e83bab32f..42403bb53f 100644 --- a/localazy.json +++ b/localazy.json @@ -43,6 +43,7 @@ }, "download": { "folder": "bbl/i18n", + "includeSourceLang" : "true", "files": { "output": "${lang}/BambuStudio_${lang}.po" } diff --git a/resources/config.json b/resources/config.json index 73890dcfff..2eea04ed92 100644 --- a/resources/config.json +++ b/resources/config.json @@ -1,12 +1,40 @@ { "printers": [ + { + "display_name": "Bambu Lab P1P", + "func": { + "FUNC_CHAMBER_TEMP": false, + "FUNC_FIRSTLAYER_INSPECT": false, + "FUNC_AI_MONITORING": false, + "FUNC_BUILDPLATE_MARKER_DETECT": false, + "FUNC_FLOW_CALIBRATION": false, + "FUNC_MONITORING": false, + "FUNC_TIMELAPSE": false, + "FUNC_MEDIA_FILE": false, + "FUNC_REMOTE_TUNNEL": false, + "FUNC_LOCAL_TUNNEL": true, + "FUNC_VIRTUAL_CAMERA" : false, + "FUNC_PRINT_WITHOUT_SD": false, + "FUNC_ALTER_RESOLUTION": false, + "FUNC_AUTO_SWITCH_FILAMENT": false, + "FUNC_CHAMBER_FAN" : false, + "FUNC_SEND_TO_SDCARD": false + }, + "camera_resolution":["720p"], + "bed_temperature_limit": 100, + "model_id": "C11", + "printer_type": "C11", + "printer_thumbnail_image": "printer_thumbnail_p1p" + }, { "display_name": "Bambu Lab X1", "func": { "FUNC_LOCAL_TUNNEL": false }, + "camera_resolution":["720p","1080p"], "model_id": "BL-P002", - "printer_type": "3DPrinter-X1" + "printer_type": "3DPrinter-X1", + "printer_thumbnail_image": "printer_thumbnail" }, { "display_name": "Bambu Lab X1 Carbon", @@ -14,7 +42,9 @@ "FUNC_LOCAL_TUNNEL": false }, "model_id": "BL-P001", - "printer_type": "3DPrinter-X1-Carbon" + "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 12a3cf2df8..c3542fa7a1 100644 --- a/resources/data/hints.ini +++ b/resources/data/hints.ini @@ -153,6 +153,17 @@ documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/auto-brim 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/e/en/software/bambu-studio/stacking-objects + +[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:] #text = #hypertext = diff --git a/resources/i18n/de/BambuStudio.mo b/resources/i18n/de/BambuStudio.mo index ce7c4c641a..5d65f784f5 100644 Binary files a/resources/i18n/de/BambuStudio.mo and b/resources/i18n/de/BambuStudio.mo differ diff --git a/resources/i18n/en/BambuStudio.mo b/resources/i18n/en/BambuStudio.mo index 2b7b76200c..f5952f13f2 100644 Binary files a/resources/i18n/en/BambuStudio.mo and b/resources/i18n/en/BambuStudio.mo differ diff --git a/resources/i18n/es/BambuStudio.mo b/resources/i18n/es/BambuStudio.mo index 29a7fee7a0..741ca77c63 100644 Binary files a/resources/i18n/es/BambuStudio.mo and b/resources/i18n/es/BambuStudio.mo differ diff --git a/resources/i18n/fr/BambuStudio.mo b/resources/i18n/fr/BambuStudio.mo index 462d5311fd..5067d1175c 100644 Binary files a/resources/i18n/fr/BambuStudio.mo and b/resources/i18n/fr/BambuStudio.mo differ diff --git a/resources/i18n/hu/BambuStudio.mo b/resources/i18n/hu/BambuStudio.mo index 8a23489515..870b9b4f9f 100644 Binary files a/resources/i18n/hu/BambuStudio.mo and b/resources/i18n/hu/BambuStudio.mo differ diff --git a/resources/i18n/nl/BambuStudio.mo b/resources/i18n/nl/BambuStudio.mo index 3afa4fd1b2..386dd88b24 100644 Binary files a/resources/i18n/nl/BambuStudio.mo and b/resources/i18n/nl/BambuStudio.mo differ diff --git a/resources/i18n/sv/BambuStudio.mo b/resources/i18n/sv/BambuStudio.mo index dc4d2038b5..b419318549 100644 Binary files a/resources/i18n/sv/BambuStudio.mo and b/resources/i18n/sv/BambuStudio.mo differ diff --git a/resources/i18n/zh_cn/BambuStudio.mo b/resources/i18n/zh_cn/BambuStudio.mo index 841ec9074e..35f8831a6b 100644 Binary files a/resources/i18n/zh_cn/BambuStudio.mo and b/resources/i18n/zh_cn/BambuStudio.mo differ diff --git a/resources/images/ams_arrow.svg b/resources/images/ams_arrow.svg new file mode 100644 index 0000000000..2184cf7405 --- /dev/null +++ b/resources/images/ams_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/ams_fila_sync.svg b/resources/images/ams_fila_sync.svg index 0b2e0b75e8..407aa53197 100644 --- a/resources/images/ams_fila_sync.svg +++ b/resources/images/ams_fila_sync.svg @@ -1,12 +1,3 @@ - - - - - - - - - - + diff --git a/resources/images/ams_humidity_0.svg b/resources/images/ams_humidity_0.svg new file mode 100644 index 0000000000..e2fd6753df --- /dev/null +++ b/resources/images/ams_humidity_0.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/ams_humidity_1.svg b/resources/images/ams_humidity_1.svg new file mode 100644 index 0000000000..b5322212d3 --- /dev/null +++ b/resources/images/ams_humidity_1.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/ams_humidity_2.svg b/resources/images/ams_humidity_2.svg new file mode 100644 index 0000000000..ee14bbb224 --- /dev/null +++ b/resources/images/ams_humidity_2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/ams_humidity_3.svg b/resources/images/ams_humidity_3.svg new file mode 100644 index 0000000000..54f2f99da7 --- /dev/null +++ b/resources/images/ams_humidity_3.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/ams_humidity_4.svg b/resources/images/ams_humidity_4.svg new file mode 100644 index 0000000000..f552f06f04 --- /dev/null +++ b/resources/images/ams_humidity_4.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/ams_item_examples.svg b/resources/images/ams_item_examples.svg new file mode 100644 index 0000000000..588290c0d4 --- /dev/null +++ b/resources/images/ams_item_examples.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/ams_mapping_examples.svg b/resources/images/ams_mapping_examples.svg new file mode 100644 index 0000000000..e017313018 --- /dev/null +++ b/resources/images/ams_mapping_examples.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/ams_readonly.svg b/resources/images/ams_readonly.svg index 561c5382b6..fd67c7fb07 100644 --- a/resources/images/ams_readonly.svg +++ b/resources/images/ams_readonly.svg @@ -1,2 +1,2 @@ \ No newline at end of file + \ No newline at end of file diff --git a/resources/images/ams_setting_hover.svg b/resources/images/ams_setting_hover.svg index 25042562ee..36625b7e4d 100644 --- a/resources/images/ams_setting_hover.svg +++ b/resources/images/ams_setting_hover.svg @@ -1,6 +1,6 @@ - + diff --git a/resources/images/ams_setting_press.svg b/resources/images/ams_setting_press.svg index 9e1144b46e..123325ec39 100644 --- a/resources/images/ams_setting_press.svg +++ b/resources/images/ams_setting_press.svg @@ -1,6 +1,6 @@ - + diff --git a/resources/images/auxiliary_add_file.svg b/resources/images/auxiliary_add_file.svg index fdbd079c17..29c0e27b88 100644 --- a/resources/images/auxiliary_add_file.svg +++ b/resources/images/auxiliary_add_file.svg @@ -2,7 +2,7 @@ Layer 1 - - + + \ No newline at end of file diff --git a/resources/images/auxiliary_delete_file.svg b/resources/images/auxiliary_delete_file.svg index e4a0d6d8b3..83d56129b4 100644 --- a/resources/images/auxiliary_delete_file.svg +++ b/resources/images/auxiliary_delete_file.svg @@ -2,6 +2,6 @@ Layer 1 - + \ No newline at end of file diff --git a/resources/images/bbl-3dp-logo.svg b/resources/images/bbl-3dp-logo.svg new file mode 100644 index 0000000000..af0b6ef5e2 --- /dev/null +++ b/resources/images/bbl-3dp-logo.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_ep_bottom.svg b/resources/images/bbl_bed_ep_bottom.svg new file mode 100644 index 0000000000..8c33731392 --- /dev/null +++ b/resources/images/bbl_bed_ep_bottom.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_ep_left.svg b/resources/images/bbl_bed_ep_left.svg new file mode 100644 index 0000000000..06d0b10917 --- /dev/null +++ b/resources/images/bbl_bed_ep_left.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pc_bottom.svg b/resources/images/bbl_bed_pc_bottom.svg new file mode 100644 index 0000000000..cccc20063b --- /dev/null +++ b/resources/images/bbl_bed_pc_bottom.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pc_left.svg b/resources/images/bbl_bed_pc_left.svg new file mode 100644 index 0000000000..d8acdd5b13 --- /dev/null +++ b/resources/images/bbl_bed_pc_left.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pei_bottom.svg b/resources/images/bbl_bed_pei_bottom.svg new file mode 100644 index 0000000000..8143d03a23 --- /dev/null +++ b/resources/images/bbl_bed_pei_bottom.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pei_left.svg b/resources/images/bbl_bed_pei_left.svg new file mode 100644 index 0000000000..11ca8892bd --- /dev/null +++ b/resources/images/bbl_bed_pei_left.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pte_bottom.svg b/resources/images/bbl_bed_pte_bottom.svg new file mode 100644 index 0000000000..cf00a644d9 --- /dev/null +++ b/resources/images/bbl_bed_pte_bottom.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bbl_bed_pte_left.svg b/resources/images/bbl_bed_pte_left.svg new file mode 100644 index 0000000000..ce812d76ba --- /dev/null +++ b/resources/images/bbl_bed_pte_left.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/bullet_black.png b/resources/images/bullet_black.png new file mode 100644 index 0000000000..0ad73727e8 Binary files /dev/null and b/resources/images/bullet_black.png differ diff --git a/resources/images/bullet_blue.png b/resources/images/bullet_blue.png new file mode 100644 index 0000000000..a7651ec8a0 Binary files /dev/null and b/resources/images/bullet_blue.png differ diff --git a/resources/images/bullet_white.png b/resources/images/bullet_white.png new file mode 100644 index 0000000000..2ff85a6fce Binary files /dev/null and b/resources/images/bullet_white.png differ diff --git a/resources/images/camera_setting.svg b/resources/images/camera_setting.svg new file mode 100644 index 0000000000..b2837a5b06 --- /dev/null +++ b/resources/images/camera_setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/camera_setting_hover.svg b/resources/images/camera_setting_hover.svg new file mode 100644 index 0000000000..cca2c1ba18 --- /dev/null +++ b/resources/images/camera_setting_hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/check_off_disabled.svg b/resources/images/check_off_disabled.svg index d911ee69b9..8653c1f7bb 100644 --- a/resources/images/check_off_disabled.svg +++ b/resources/images/check_off_disabled.svg @@ -1,3 +1,3 @@ - + diff --git a/resources/images/circle_paint_dark.svg b/resources/images/circle_paint_dark.svg new file mode 100644 index 0000000000..d96f4ed4be --- /dev/null +++ b/resources/images/circle_paint_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/cross.svg b/resources/images/cross.svg index 35896d3822..4d832a5887 100644 --- a/resources/images/cross.svg +++ b/resources/images/cross.svg @@ -4,5 +4,5 @@ Slice 41 - - \ No newline at end of file + + \ No newline at end of file diff --git a/resources/images/fan_control_add.svg b/resources/images/fan_control_add.svg new file mode 100644 index 0000000000..19d9e41cce --- /dev/null +++ b/resources/images/fan_control_add.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/fan_control_decrease.svg b/resources/images/fan_control_decrease.svg new file mode 100644 index 0000000000..7a68c36d11 --- /dev/null +++ b/resources/images/fan_control_decrease.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_dash_bk.svg b/resources/images/fan_dash_bk.svg new file mode 100644 index 0000000000..47d451080f --- /dev/null +++ b/resources/images/fan_dash_bk.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/fan_icon.svg b/resources/images/fan_icon.svg new file mode 100644 index 0000000000..67a6071952 --- /dev/null +++ b/resources/images/fan_icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/fan_scale_0.svg b/resources/images/fan_scale_0.svg new file mode 100644 index 0000000000..c8ea0d6097 --- /dev/null +++ b/resources/images/fan_scale_0.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_1.svg b/resources/images/fan_scale_1.svg new file mode 100644 index 0000000000..42fd9700e6 --- /dev/null +++ b/resources/images/fan_scale_1.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_10.svg b/resources/images/fan_scale_10.svg new file mode 100644 index 0000000000..4fd2052588 --- /dev/null +++ b/resources/images/fan_scale_10.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_2.svg b/resources/images/fan_scale_2.svg new file mode 100644 index 0000000000..558b253ae1 --- /dev/null +++ b/resources/images/fan_scale_2.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_3.svg b/resources/images/fan_scale_3.svg new file mode 100644 index 0000000000..df944e6fe8 --- /dev/null +++ b/resources/images/fan_scale_3.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_4.svg b/resources/images/fan_scale_4.svg new file mode 100644 index 0000000000..21cdc9d47f --- /dev/null +++ b/resources/images/fan_scale_4.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_5.svg b/resources/images/fan_scale_5.svg new file mode 100644 index 0000000000..2aa01a20a9 --- /dev/null +++ b/resources/images/fan_scale_5.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_6.svg b/resources/images/fan_scale_6.svg new file mode 100644 index 0000000000..2ec6641f45 --- /dev/null +++ b/resources/images/fan_scale_6.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_7.svg b/resources/images/fan_scale_7.svg new file mode 100644 index 0000000000..8a0d2a147d --- /dev/null +++ b/resources/images/fan_scale_7.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_8.svg b/resources/images/fan_scale_8.svg new file mode 100644 index 0000000000..9bc4ffe1ab --- /dev/null +++ b/resources/images/fan_scale_8.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fan_scale_9.svg b/resources/images/fan_scale_9.svg new file mode 100644 index 0000000000..9430f66bb3 --- /dev/null +++ b/resources/images/fan_scale_9.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/fill_paint_dark.svg b/resources/images/fill_paint_dark.svg new file mode 100644 index 0000000000..6e8e76f6c4 --- /dev/null +++ b/resources/images/fill_paint_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/gap_fill_dark.svg b/resources/images/gap_fill_dark.svg new file mode 100644 index 0000000000..09e898ce8b --- /dev/null +++ b/resources/images/gap_fill_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/height_range_dark.svg b/resources/images/height_range_dark.svg new file mode 100644 index 0000000000..5b352af377 --- /dev/null +++ b/resources/images/height_range_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/mall_control_back.svg b/resources/images/mall_control_back.svg new file mode 100644 index 0000000000..6975727777 --- /dev/null +++ b/resources/images/mall_control_back.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/mall_control_forward.svg b/resources/images/mall_control_forward.svg new file mode 100644 index 0000000000..60dbc2cf2a --- /dev/null +++ b/resources/images/mall_control_forward.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/mall_control_refresh.svg b/resources/images/mall_control_refresh.svg new file mode 100644 index 0000000000..8459de3fb3 --- /dev/null +++ b/resources/images/mall_control_refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/mmu_segmentation_dark.svg b/resources/images/mmu_segmentation_dark.svg new file mode 100644 index 0000000000..aba5bf386f --- /dev/null +++ b/resources/images/mmu_segmentation_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/monitor_ams_extruder.svg b/resources/images/monitor_ams_extruder.svg index 2d383f7c27..e81a5fde9b 100644 --- a/resources/images/monitor_ams_extruder.svg +++ b/resources/images/monitor_ams_extruder.svg @@ -1,57 +1,56 @@ - - - - Layer 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/monitor_brokenimg.png b/resources/images/monitor_brokenimg.png new file mode 100644 index 0000000000..6c2e180ebb Binary files /dev/null and b/resources/images/monitor_brokenimg.png differ diff --git a/resources/images/monitor_extruder.png b/resources/images/monitor_extruder.png deleted file mode 100644 index 9376c3d827..0000000000 Binary files a/resources/images/monitor_extruder.png and /dev/null differ diff --git a/resources/images/monitor_extruder.svg b/resources/images/monitor_extruder.svg deleted file mode 100644 index a0c52687c1..0000000000 --- a/resources/images/monitor_extruder.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/monitor_extruder_empty_load.png b/resources/images/monitor_extruder_empty_load.png new file mode 100644 index 0000000000..3428f33dc3 Binary files /dev/null and b/resources/images/monitor_extruder_empty_load.png differ diff --git a/resources/images/monitor_extruder_empty_unload.png b/resources/images/monitor_extruder_empty_unload.png new file mode 100644 index 0000000000..c65c49e28f Binary files /dev/null and b/resources/images/monitor_extruder_empty_unload.png differ diff --git a/resources/images/monitor_extruder_filled_load.png b/resources/images/monitor_extruder_filled_load.png new file mode 100644 index 0000000000..afac9053ce Binary files /dev/null and b/resources/images/monitor_extruder_filled_load.png differ diff --git a/resources/images/monitor_extruder_filled_unload.png b/resources/images/monitor_extruder_filled_unload.png new file mode 100644 index 0000000000..51f83a0ee0 Binary files /dev/null and b/resources/images/monitor_extruder_filled_unload.png differ diff --git a/resources/images/monitor_extruder_load.png b/resources/images/monitor_extruder_load.png deleted file mode 100644 index 27f4f3c610..0000000000 Binary files a/resources/images/monitor_extruder_load.png and /dev/null differ diff --git a/resources/images/monitor_extruder_load.svg b/resources/images/monitor_extruder_load.svg deleted file mode 100644 index 789ddc36c1..0000000000 --- a/resources/images/monitor_extruder_load.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/monitor_recording_off.svg b/resources/images/monitor_recording_off.svg new file mode 100644 index 0000000000..0ec26d4691 --- /dev/null +++ b/resources/images/monitor_recording_off.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/monitor_recording_on.svg b/resources/images/monitor_recording_on.svg new file mode 100644 index 0000000000..ed153d1265 --- /dev/null +++ b/resources/images/monitor_recording_on.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/monitor_speed_active.svg b/resources/images/monitor_speed_active.svg index 03335cf42a..f8e7e68639 100644 --- a/resources/images/monitor_speed_active.svg +++ b/resources/images/monitor_speed_active.svg @@ -1,6 +1,6 @@ - - - - - + + + + + diff --git a/resources/images/monitor_timelapse_off.svg b/resources/images/monitor_timelapse_off.svg new file mode 100644 index 0000000000..bfe6407f0f --- /dev/null +++ b/resources/images/monitor_timelapse_off.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/monitor_timelapse_on.svg b/resources/images/monitor_timelapse_on.svg new file mode 100644 index 0000000000..5e1a44a7c7 --- /dev/null +++ b/resources/images/monitor_timelapse_on.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/monitor_upgrade_ext.svg b/resources/images/monitor_upgrade_ext.svg new file mode 100644 index 0000000000..2e3623bfa6 --- /dev/null +++ b/resources/images/monitor_upgrade_ext.svg @@ -0,0 +1,964 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/monitor_upgrade_printer.svg b/resources/images/monitor_upgrade_printer.svg deleted file mode 100644 index c320da4e9f..0000000000 --- a/resources/images/monitor_upgrade_printer.svg +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/monitor_vcamera_off.svg b/resources/images/monitor_vcamera_off.svg new file mode 100644 index 0000000000..1119224ef6 --- /dev/null +++ b/resources/images/monitor_vcamera_off.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/monitor_vcamera_on.svg b/resources/images/monitor_vcamera_on.svg new file mode 100644 index 0000000000..be03d52393 --- /dev/null +++ b/resources/images/monitor_vcamera_on.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/notification_close_dark.svg b/resources/images/notification_close_dark.svg new file mode 100644 index 0000000000..ab0dd789e5 --- /dev/null +++ b/resources/images/notification_close_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/resources/images/notification_close_hover_dark.svg b/resources/images/notification_close_hover_dark.svg new file mode 100644 index 0000000000..68c49e8a3a --- /dev/null +++ b/resources/images/notification_close_hover_dark.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/resources/images/notification_documentation_dark.svg b/resources/images/notification_documentation_dark.svg new file mode 100644 index 0000000000..8cfd77fa21 --- /dev/null +++ b/resources/images/notification_documentation_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/notification_documentation_hover_dark.svg b/resources/images/notification_documentation_hover_dark.svg new file mode 100644 index 0000000000..a51e95f5fa --- /dev/null +++ b/resources/images/notification_documentation_hover_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/notification_minimalize_dark.svg b/resources/images/notification_minimalize_dark.svg new file mode 100644 index 0000000000..1eb4bc2ea3 --- /dev/null +++ b/resources/images/notification_minimalize_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/notification_minimalize_hover_dark.svg b/resources/images/notification_minimalize_hover_dark.svg new file mode 100644 index 0000000000..85899b8ffc --- /dev/null +++ b/resources/images/notification_minimalize_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/notification_preferences_dark.svg b/resources/images/notification_preferences_dark.svg new file mode 100644 index 0000000000..04df804338 --- /dev/null +++ b/resources/images/notification_preferences_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/notification_preferences_hover_dark.svg b/resources/images/notification_preferences_hover_dark.svg new file mode 100644 index 0000000000..04edc99841 --- /dev/null +++ b/resources/images/notification_preferences_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/notification_right.svg b/resources/images/notification_right.svg index 8d40507a76..1dfa2c79d1 100644 --- a/resources/images/notification_right.svg +++ b/resources/images/notification_right.svg @@ -1,28 +1 @@ - - - - - - - - - - - - +1234214 \ No newline at end of file diff --git a/resources/images/notification_right_dark.svg b/resources/images/notification_right_dark.svg new file mode 100644 index 0000000000..3f22075e0d --- /dev/null +++ b/resources/images/notification_right_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/notification_right_hover.svg b/resources/images/notification_right_hover.svg index a436c95983..7f6305d419 100644 --- a/resources/images/notification_right_hover.svg +++ b/resources/images/notification_right_hover.svg @@ -1,27 +1 @@ - - - - - - - - - - - - +123124 \ No newline at end of file diff --git a/resources/images/notification_right_hover_dark.svg b/resources/images/notification_right_hover_dark.svg new file mode 100644 index 0000000000..fc6cf708ed --- /dev/null +++ b/resources/images/notification_right_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/one_layer_arrow.svg b/resources/images/one_layer_arrow.svg deleted file mode 100644 index 1e8e4e53ba..0000000000 --- a/resources/images/one_layer_arrow.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/resources/images/one_layer_off_dark.svg b/resources/images/one_layer_off_dark.svg new file mode 100644 index 0000000000..c5390625f2 --- /dev/null +++ b/resources/images/one_layer_off_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/one_layer_off_hover_dark.svg b/resources/images/one_layer_off_hover_dark.svg new file mode 100644 index 0000000000..d89bc32616 --- /dev/null +++ b/resources/images/one_layer_off_hover_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/resources/images/one_layer_on_dark.svg b/resources/images/one_layer_on_dark.svg new file mode 100644 index 0000000000..0ba3476fcd --- /dev/null +++ b/resources/images/one_layer_on_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/one_layer_on_hover_dark.svg b/resources/images/one_layer_on_hover_dark.svg new file mode 100644 index 0000000000..bece417f64 --- /dev/null +++ b/resources/images/one_layer_on_hover_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/param_3dhoneycomb.svg b/resources/images/param_3dhoneycomb.svg new file mode 100644 index 0000000000..9d2b94182b --- /dev/null +++ b/resources/images/param_3dhoneycomb.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/param_adaptivecubic.svg b/resources/images/param_adaptivecubic.svg new file mode 100644 index 0000000000..7490ca81bd --- /dev/null +++ b/resources/images/param_adaptivecubic.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_alignedrectilinear.svg b/resources/images/param_alignedrectilinear.svg new file mode 100644 index 0000000000..3e29d271a4 --- /dev/null +++ b/resources/images/param_alignedrectilinear.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/param_archimedeanchords.svg b/resources/images/param_archimedeanchords.svg new file mode 100644 index 0000000000..80d6539166 --- /dev/null +++ b/resources/images/param_archimedeanchords.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/param_concentric.svg b/resources/images/param_concentric.svg new file mode 100644 index 0000000000..47062df636 --- /dev/null +++ b/resources/images/param_concentric.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/param_cubic.svg b/resources/images/param_cubic.svg new file mode 100644 index 0000000000..344aeb1c89 --- /dev/null +++ b/resources/images/param_cubic.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_grid.svg b/resources/images/param_grid.svg new file mode 100644 index 0000000000..5ef8475734 --- /dev/null +++ b/resources/images/param_grid.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/param_gyroid.svg b/resources/images/param_gyroid.svg new file mode 100644 index 0000000000..fa42716efc --- /dev/null +++ b/resources/images/param_gyroid.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/resources/images/param_hilbertcurve.svg b/resources/images/param_hilbertcurve.svg new file mode 100644 index 0000000000..f76ff649ea --- /dev/null +++ b/resources/images/param_hilbertcurve.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/param_honeycomb.svg b/resources/images/param_honeycomb.svg new file mode 100644 index 0000000000..9d2b94182b --- /dev/null +++ b/resources/images/param_honeycomb.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/resources/images/param_lightning.svg b/resources/images/param_lightning.svg new file mode 100644 index 0000000000..0385be4126 --- /dev/null +++ b/resources/images/param_lightning.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/images/param_line.svg b/resources/images/param_line.svg new file mode 100644 index 0000000000..aed3393a87 --- /dev/null +++ b/resources/images/param_line.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_monotonic.svg b/resources/images/param_monotonic.svg new file mode 100644 index 0000000000..0c9245e28a --- /dev/null +++ b/resources/images/param_monotonic.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/param_monotonicline.svg b/resources/images/param_monotonicline.svg new file mode 100644 index 0000000000..b959242708 --- /dev/null +++ b/resources/images/param_monotonicline.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_octagramspiral.svg b/resources/images/param_octagramspiral.svg new file mode 100644 index 0000000000..d4848698ba --- /dev/null +++ b/resources/images/param_octagramspiral.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/param_raft.svg b/resources/images/param_raft.svg new file mode 100644 index 0000000000..d58506d2ca --- /dev/null +++ b/resources/images/param_raft.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/param_rectilinear-grid.svg b/resources/images/param_rectilinear-grid.svg new file mode 100644 index 0000000000..c47cb2c822 --- /dev/null +++ b/resources/images/param_rectilinear-grid.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_rectilinear.svg b/resources/images/param_rectilinear.svg new file mode 100644 index 0000000000..3e29d271a4 --- /dev/null +++ b/resources/images/param_rectilinear.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/resources/images/param_support_filament.svg b/resources/images/param_support_filament.svg index ab63b5934f..6abc4ff22e 100644 --- a/resources/images/param_support_filament.svg +++ b/resources/images/param_support_filament.svg @@ -1,17 +1,6 @@ - - - - - - - - - - - - - - - - + + + + + diff --git a/resources/images/param_supportcubic.svg b/resources/images/param_supportcubic.svg new file mode 100644 index 0000000000..344aeb1c89 --- /dev/null +++ b/resources/images/param_supportcubic.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_tri-hexagon.svg b/resources/images/param_tri-hexagon.svg new file mode 100644 index 0000000000..636925673d --- /dev/null +++ b/resources/images/param_tri-hexagon.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_triangles.svg b/resources/images/param_triangles.svg new file mode 100644 index 0000000000..8b7fd23a02 --- /dev/null +++ b/resources/images/param_triangles.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/param_zig-zag.svg b/resources/images/param_zig-zag.svg new file mode 100644 index 0000000000..58ddf0ea96 --- /dev/null +++ b/resources/images/param_zig-zag.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/plate_arrange_dark.svg b/resources/images/plate_arrange_dark.svg new file mode 100644 index 0000000000..04b66eaee4 --- /dev/null +++ b/resources/images/plate_arrange_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_arrange_hover_dark.svg b/resources/images/plate_arrange_hover_dark.svg new file mode 100644 index 0000000000..9b060b705e --- /dev/null +++ b/resources/images/plate_arrange_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_close_dark.svg b/resources/images/plate_close_dark.svg new file mode 100644 index 0000000000..8fb4bdd6a9 --- /dev/null +++ b/resources/images/plate_close_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_close_hover_dark.svg b/resources/images/plate_close_hover_dark.svg new file mode 100644 index 0000000000..47525ae39e --- /dev/null +++ b/resources/images/plate_close_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_locked_dark.svg b/resources/images/plate_locked_dark.svg new file mode 100644 index 0000000000..69d586faba --- /dev/null +++ b/resources/images/plate_locked_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_locked_hover_dark.svg b/resources/images/plate_locked_hover_dark.svg new file mode 100644 index 0000000000..1df119e75c --- /dev/null +++ b/resources/images/plate_locked_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_orient_dark.svg b/resources/images/plate_orient_dark.svg new file mode 100644 index 0000000000..a2e1cf7562 --- /dev/null +++ b/resources/images/plate_orient_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_orient_hover_dark.svg b/resources/images/plate_orient_hover_dark.svg new file mode 100644 index 0000000000..2f141d3323 --- /dev/null +++ b/resources/images/plate_orient_hover_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_set_bedtype.svg b/resources/images/plate_set_bedtype.svg new file mode 100644 index 0000000000..f4735d007a --- /dev/null +++ b/resources/images/plate_set_bedtype.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_changed.svg b/resources/images/plate_set_bedtype_changed.svg new file mode 100644 index 0000000000..c4aed904b2 --- /dev/null +++ b/resources/images/plate_set_bedtype_changed.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_changed_dark.svg b/resources/images/plate_set_bedtype_changed_dark.svg new file mode 100644 index 0000000000..0496fd615f --- /dev/null +++ b/resources/images/plate_set_bedtype_changed_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_changed_hover.svg b/resources/images/plate_set_bedtype_changed_hover.svg new file mode 100644 index 0000000000..303b4fbbe6 --- /dev/null +++ b/resources/images/plate_set_bedtype_changed_hover.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_changed_hover_dark.svg b/resources/images/plate_set_bedtype_changed_hover_dark.svg new file mode 100644 index 0000000000..fcea2f7c94 --- /dev/null +++ b/resources/images/plate_set_bedtype_changed_hover_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_dark.svg b/resources/images/plate_set_bedtype_dark.svg new file mode 100644 index 0000000000..74c19f4dd5 --- /dev/null +++ b/resources/images/plate_set_bedtype_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_hover.svg b/resources/images/plate_set_bedtype_hover.svg new file mode 100644 index 0000000000..db07509cd0 --- /dev/null +++ b/resources/images/plate_set_bedtype_hover.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/plate_set_bedtype_hover_dark.svg b/resources/images/plate_set_bedtype_hover_dark.svg new file mode 100644 index 0000000000..f90a67e4c2 --- /dev/null +++ b/resources/images/plate_set_bedtype_hover_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/plate_unlocked_dark.svg b/resources/images/plate_unlocked_dark.svg new file mode 100644 index 0000000000..13c562d552 --- /dev/null +++ b/resources/images/plate_unlocked_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/plate_unlocked_hover_dark.svg b/resources/images/plate_unlocked_hover_dark.svg new file mode 100644 index 0000000000..140fa1d7d6 --- /dev/null +++ b/resources/images/plate_unlocked_hover_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/printer_thumbnail.svg b/resources/images/printer_thumbnail.svg index 8f8b903e64..2a2c5e0a56 100644 --- a/resources/images/printer_thumbnail.svg +++ b/resources/images/printer_thumbnail.svg @@ -1,100 +1,274 @@ - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/printer_thumbnail_dark.svg b/resources/images/printer_thumbnail_dark.svg new file mode 100644 index 0000000000..03c280357e --- /dev/null +++ b/resources/images/printer_thumbnail_dark.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/images/printer_thumbnail_p1p.svg b/resources/images/printer_thumbnail_p1p.svg new file mode 100644 index 0000000000..4ba38749ca --- /dev/null +++ b/resources/images/printer_thumbnail_p1p.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/printer_thumbnail_p1p_dark.svg b/resources/images/printer_thumbnail_p1p_dark.svg new file mode 100644 index 0000000000..ce344e5004 --- /dev/null +++ b/resources/images/printer_thumbnail_p1p_dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/images/recording_off_hover.svg b/resources/images/recording_off_hover.svg deleted file mode 100644 index 0f59b4deee..0000000000 --- a/resources/images/recording_off_hover.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_off_normal.svg b/resources/images/recording_off_normal.svg deleted file mode 100644 index 3ba0450e8b..0000000000 --- a/resources/images/recording_off_normal.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_on_hover.svg b/resources/images/recording_on_hover.svg deleted file mode 100644 index 45a46c0fdf..0000000000 --- a/resources/images/recording_on_hover.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/recording_on_normal.svg b/resources/images/recording_on_normal.svg deleted file mode 100644 index b75b916e95..0000000000 --- a/resources/images/recording_on_normal.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/resources/images/reset_hover.svg b/resources/images/reset_hover.svg deleted file mode 100644 index e16408625f..0000000000 --- a/resources/images/reset_hover.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/reset_normal.svg b/resources/images/reset_normal.svg deleted file mode 100644 index 3d50733780..0000000000 --- a/resources/images/reset_normal.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/save.svg b/resources/images/save.svg index e53c72b49b..63029daf58 100644 --- a/resources/images/save.svg +++ b/resources/images/save.svg @@ -1,4 +1,3 @@ - - Slice 41 - - \ No newline at end of file + + + diff --git a/resources/images/sdcard_state_abnormal.svg b/resources/images/sdcard_state_abnormal.svg new file mode 100644 index 0000000000..5798a26343 --- /dev/null +++ b/resources/images/sdcard_state_abnormal.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/sdcard_state_no.svg b/resources/images/sdcard_state_no.svg new file mode 100644 index 0000000000..6b17701408 --- /dev/null +++ b/resources/images/sdcard_state_no.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/sdcard_state_normal.svg b/resources/images/sdcard_state_normal.svg new file mode 100644 index 0000000000..5bcaec8bb0 --- /dev/null +++ b/resources/images/sdcard_state_normal.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/sdcard_state_off.svg b/resources/images/sdcard_state_off.svg deleted file mode 100644 index 97b4866def..0000000000 --- a/resources/images/sdcard_state_off.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/resources/images/sdcard_state_on.svg b/resources/images/sdcard_state_on.svg deleted file mode 100644 index deef48a11b..0000000000 --- a/resources/images/sdcard_state_on.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/resources/images/search.svg b/resources/images/search.svg index cff2f50213..304562750b 100644 --- a/resources/images/search.svg +++ b/resources/images/search.svg @@ -1,6 +1,11 @@ - - - Slice 41 - - - \ No newline at end of file + + + + + + + + + + + diff --git a/resources/images/split_objects_dark.svg b/resources/images/split_objects_dark.svg new file mode 100644 index 0000000000..71acf8dff6 --- /dev/null +++ b/resources/images/split_objects_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/split_parts_dark.svg b/resources/images/split_parts_dark.svg new file mode 100644 index 0000000000..80ed055934 --- /dev/null +++ b/resources/images/split_parts_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/text_B_dark.svg b/resources/images/text_B_dark.svg new file mode 100644 index 0000000000..5fa0f1bbdc --- /dev/null +++ b/resources/images/text_B_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/text_B_hover.svg b/resources/images/text_B_hover.svg deleted file mode 100644 index 2242afa388..0000000000 --- a/resources/images/text_B_hover.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/text_B_press.svg b/resources/images/text_B_press.svg deleted file mode 100644 index 5333b0ef6f..0000000000 --- a/resources/images/text_B_press.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/resources/images/text_T_dark.svg b/resources/images/text_T_dark.svg new file mode 100644 index 0000000000..af85448dae --- /dev/null +++ b/resources/images/text_T_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/text_T_hover.svg b/resources/images/text_T_hover.svg deleted file mode 100644 index 2a7880cee0..0000000000 --- a/resources/images/text_T_hover.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/text_T_press.svg b/resources/images/text_T_press.svg deleted file mode 100644 index 9d1da57e2b..0000000000 --- a/resources/images/text_T_press.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/resources/images/timelapse_off_hover.svg b/resources/images/timelapse_off_hover.svg deleted file mode 100644 index d21e599c2e..0000000000 --- a/resources/images/timelapse_off_hover.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_off_normal.svg b/resources/images/timelapse_off_normal.svg deleted file mode 100644 index ec30c1b720..0000000000 --- a/resources/images/timelapse_off_normal.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_on_hover.svg b/resources/images/timelapse_on_hover.svg deleted file mode 100644 index 7ea45dc911..0000000000 --- a/resources/images/timelapse_on_hover.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/timelapse_on_normal.svg b/resources/images/timelapse_on_normal.svg deleted file mode 100644 index 09655e1349..0000000000 --- a/resources/images/timelapse_on_normal.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/resources/images/toolbar_add_plate_dark.svg b/resources/images/toolbar_add_plate_dark.svg new file mode 100644 index 0000000000..70b91e854f --- /dev/null +++ b/resources/images/toolbar_add_plate_dark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/resources/images/toolbar_arrange_dark.svg b/resources/images/toolbar_arrange_dark.svg new file mode 100644 index 0000000000..9654b5d9a8 --- /dev/null +++ b/resources/images/toolbar_arrange_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/toolbar_assemble_dark.svg b/resources/images/toolbar_assemble_dark.svg new file mode 100644 index 0000000000..f39b428d28 --- /dev/null +++ b/resources/images/toolbar_assemble_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/toolbar_background_dark.png b/resources/images/toolbar_background_dark.png new file mode 100644 index 0000000000..43d4a65f1a Binary files /dev/null and b/resources/images/toolbar_background_dark.png differ diff --git a/resources/images/toolbar_cut_dark.svg b/resources/images/toolbar_cut_dark.svg new file mode 100644 index 0000000000..ca963ca9fb --- /dev/null +++ b/resources/images/toolbar_cut_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/toolbar_flatten_dark.svg b/resources/images/toolbar_flatten_dark.svg new file mode 100644 index 0000000000..136d2a29d4 --- /dev/null +++ b/resources/images/toolbar_flatten_dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/resources/images/toolbar_modifier_sphere_dark.svg b/resources/images/toolbar_modifier_sphere_dark.svg new file mode 100644 index 0000000000..10f64738ae --- /dev/null +++ b/resources/images/toolbar_modifier_sphere_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/toolbar_move_dark.svg b/resources/images/toolbar_move_dark.svg new file mode 100644 index 0000000000..e19211eed7 --- /dev/null +++ b/resources/images/toolbar_move_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/toolbar_open_dark.svg b/resources/images/toolbar_open_dark.svg new file mode 100644 index 0000000000..116f4b4ffb --- /dev/null +++ b/resources/images/toolbar_open_dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/resources/images/toolbar_orient_dark.svg b/resources/images/toolbar_orient_dark.svg new file mode 100644 index 0000000000..96e642f159 --- /dev/null +++ b/resources/images/toolbar_orient_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/resources/images/toolbar_rotate_dark.svg b/resources/images/toolbar_rotate_dark.svg new file mode 100644 index 0000000000..952e4cb62d --- /dev/null +++ b/resources/images/toolbar_rotate_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/toolbar_scale_dark.svg b/resources/images/toolbar_scale_dark.svg new file mode 100644 index 0000000000..16bbd23f2f --- /dev/null +++ b/resources/images/toolbar_scale_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/toolbar_seam_dark.svg b/resources/images/toolbar_seam_dark.svg new file mode 100644 index 0000000000..4adf5a33e9 --- /dev/null +++ b/resources/images/toolbar_seam_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/toolbar_support_dark.svg b/resources/images/toolbar_support_dark.svg new file mode 100644 index 0000000000..a381f77160 --- /dev/null +++ b/resources/images/toolbar_support_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/resources/images/toolbar_text_dark.svg b/resources/images/toolbar_text_dark.svg new file mode 100644 index 0000000000..02fc94be93 --- /dev/null +++ b/resources/images/toolbar_text_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/toolbar_variable_layer_height.svg b/resources/images/toolbar_variable_layer_height.svg new file mode 100644 index 0000000000..5646841228 --- /dev/null +++ b/resources/images/toolbar_variable_layer_height.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/toolbar_variable_layer_height_dark.svg b/resources/images/toolbar_variable_layer_height_dark.svg new file mode 100644 index 0000000000..8cc6a36546 --- /dev/null +++ b/resources/images/toolbar_variable_layer_height_dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/topbar_publish_disable.svg b/resources/images/topbar_publish_disable.svg index df16faf1e1..4e2d6b20ec 100644 --- a/resources/images/topbar_publish_disable.svg +++ b/resources/images/topbar_publish_disable.svg @@ -1,5 +1,10 @@ - - - + + + + + + + + diff --git a/resources/images/triangle_paint_dark.svg b/resources/images/triangle_paint_dark.svg new file mode 100644 index 0000000000..0efbc898b6 --- /dev/null +++ b/resources/images/triangle_paint_dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/profiles/BBL.json b/resources/profiles/BBL.json index 237bc1713b..b55bac9753 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.03.00.13", + "version": "01.04.00.14", "force_update": "0", "description": "the initial version of BBL configurations", "machine_model_list": [ @@ -12,6 +12,10 @@ { "name": "Bambu Lab X1", "sub_path": "machine/Bambu Lab X1.json" + }, + { + "name": "Bambu Lab P1P", + "sub_path": "machine/Bambu Lab P1P.json" } ], "process_list": [ @@ -75,6 +79,10 @@ "name": "0.20mm Standard @BBL X1C", "sub_path": "process/0.20mm Standard @BBL X1C.json" }, + { + "name":"0.20mm Strength @BBL X1C", + "sub_path":"process/0.20mm Strength @BBL X1C.json" + }, { "name": "0.24mm Draft @BBL X1C", "sub_path": "process/0.24mm Draft @BBL X1C.json" @@ -102,6 +110,22 @@ { "name": "0.40mm Standard @BBL X1 0.8 nozzle", "sub_path": "process/0.40mm Standard @BBL X1 0.8 nozzle.json" + }, + { + "name":"0.10mm Standard @BBL P1P 0.2 nozzle", + "sub_path":"process/0.10mm Standard @BBL P1P 0.2 nozzle.json" + }, + { + "name":"0.20mm Standard @BBL P1P", + "sub_path":"process/0.20mm Standard @BBL P1P.json" + }, + { + "name":"0.30mm Standard @BBL P1P 0.6 nozzle", + "sub_path":"process/0.30mm Standard @BBL P1P 0.6 nozzle.json" + }, + { + "name":"0.40mm Standard @BBL P1P 0.8 nozzle", + "sub_path":"process/0.40mm Standard @BBL P1P 0.8 nozzle.json" } ], "filament_list": [ @@ -201,10 +225,18 @@ "name": "Generic PLA", "sub_path": "filament/Generic PLA.json" }, + { + "name": "Generic PLA Silk", + "sub_path": "filament/Generic PLA Silk.json" + }, { "name": "Generic PLA @0.2 nozzle", "sub_path": "filament/Generic PLA @0.2 nozzle.json" }, + { + "name": "Generic PLA-CF @base", + "sub_path": "filament/Generic PLA-CF @base.json" + }, { "name": "Generic PLA-CF", "sub_path": "filament/Generic PLA-CF.json" @@ -388,6 +420,142 @@ { "name": "PolyLite PLA @BBL X1C 0.2 nozzle", "sub_path": "filament/PolyLite PLA @BBL X1C 0.2 nozzle.json" + }, + { + "name":"Bambu Support G @BBL P1P", + "sub_path":"filament/P1P/Bambu Support G @BBL P1P.json" + }, + { + "name": "Bambu ABS @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Bambu ABS @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Bambu PLA Matte @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/Bambu PLA Matte @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Bambu PLA Matte @BBL P1P", + "sub_path":"filament/P1P/Bambu PLA Matte @BBL P1P.json" + }, + { + "name":"Bambu PLA Basic @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/Bambu PLA Basic @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Bambu PLA Basic @BBL P1P", + "sub_path":"filament/P1P/Bambu PLA Basic @BBL P1P.json" + }, + { + "name": "Bambu ABS @BBL P1P", + "sub_path": "filament/P1P/Bambu ABS @BBL P1P.json" + }, + { + "name": "Bambu PC @BBL P1P", + "sub_path": "filament/P1P/Bambu PC @BBL P1P.json" + }, + { + "name": "Bambu PC @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Bambu PC @BBL P1P 0.2 nozzle.json" + }, + { + "name": "Bambu Support W @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Bambu Support W @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Bambu TPU 95A @BBL P1P", + "sub_path":"filament/P1P/Bambu TPU 95A @BBL P1P.json" + }, + { + "name": "Bambu Support W @BBL P1P", + "sub_path": "filament/P1P/Bambu Support W @BBL P1P.json" + }, + { + "name":"Generic PLA @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/Generic PLA @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Generic PLA @BBL P1P", + "sub_path":"filament/P1P/Generic PLA @BBL P1P.json" + }, + { + "name": "Generic ABS @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Generic ABS @BBL P1P 0.2 nozzle.json" + }, + { + "name": "Generic ABS @BBL P1P", + "sub_path": "filament/P1P/Generic ABS @BBL P1P.json" + }, + { + "name": "Generic ASA @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Generic ASA @BBL P1P 0.2 nozzle.json" + }, + { + "name": "Generic ASA @BBL P1P", + "sub_path": "filament/P1P/Generic ASA @BBL P1P.json" + }, + { + "name": "Generic PC @BBL P1P 0.2 nozzle", + "sub_path": "filament/P1P/Generic PC @BBL P1P 0.2 nozzle.json" + }, + { + "name": "Generic PC @BBL P1P", + "sub_path": "filament/P1P/Generic PC @BBL P1P.json" + }, + { + "name":"Generic PETG @0.2 nozzle", + "sub_path":"filament/Generic PETG @0.2 nozzle.json" + }, + { + "name": "Generic PETG @BBL P1P", + "sub_path": "filament/P1P/Generic PETG @BBL P1P.json" + }, + { + "name":"Generic PVA @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/Generic PVA @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Generic PVA @BBL P1P", + "sub_path":"filament/P1P/Generic PVA @BBL P1P.json" + }, + { + "name":"Generic TPU @BBL P1P", + "sub_path":"filament/P1P/Generic TPU @BBL P1P.json" + }, + { + "name":"PolyLite PLA @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/PolyLite PLA @BBL P1P 0.2 nozzle.json" + }, + { + "name":"PolyLite PLA @BBL P1P", + "sub_path":"filament/P1P/PolyLite PLA @BBL P1P.json" + }, + { + "name":"PolyTerra PLA @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/PolyTerra PLA @BBL P1P 0.2 nozzle.json" + }, + { + "name":"PolyTerra PLA @BBL P1P", + "sub_path":"filament/P1P/PolyTerra PLA @BBL P1P.json" + }, + { + "name":"Bambu PA-CF @BBL P1P", + "sub_path":"filament/P1P/Bambu PA-CF @BBL P1P.json" + }, + { + "name":"Generic PA-CF @BBL P1P", + "sub_path":"filament/P1P/Generic PA-CF @BBL P1P.json" + }, + { + "name":"Generic PA @BBL P1P", + "sub_path":"filament/P1P/Generic PA @BBL P1P.json" + }, + { + "name":"Generic PETG @BBL P1P 0.2 nozzle", + "sub_path":"filament/P1P/Generic PETG @BBL P1P 0.2 nozzle.json" + }, + { + "name":"Generic PLA-CF @BBL P1P", + "sub_path":"filament/P1P/Generic PLA-CF @BBL P1P.json" } ], "machine_list": [ @@ -430,6 +598,22 @@ { "name": "Bambu Lab X1 Carbon 0.8 nozzle", "sub_path": "machine/Bambu Lab X1 Carbon 0.8 nozzle.json" + }, + { + "name": "Bambu Lab P1P 0.4 nozzle", + "sub_path": "machine/Bambu Lab P1P 0.4 nozzle.json" + }, + { + "name": "Bambu Lab P1P 0.2 nozzle", + "sub_path": "machine/Bambu Lab P1P 0.2 nozzle.json" + }, + { + "name": "Bambu Lab P1P 0.6 nozzle", + "sub_path": "machine/Bambu Lab P1P 0.6 nozzle.json" + }, + { + "name": "Bambu Lab P1P 0.8 nozzle", + "sub_path": "machine/Bambu Lab P1P 0.8 nozzle.json" } ] } diff --git a/resources/profiles/BBL/filament/Bambu PA-CF @BBL X1C.json b/resources/profiles/BBL/filament/Bambu PA-CF @BBL X1C.json index 944c053686..7c2f2e15dc 100644 --- a/resources/profiles/BBL/filament/Bambu PA-CF @BBL X1C.json +++ b/resources/profiles/BBL/filament/Bambu PA-CF @BBL X1C.json @@ -15,13 +15,13 @@ "290" ], "fan_max_speed": [ - "40" + "30" ], "fan_min_speed": [ "10" ], "fan_cooling_layer_time": [ - "6" + "5" ], "full_fan_speed_layer": [ "2" @@ -30,6 +30,7 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" ] diff --git a/resources/profiles/BBL/filament/Bambu PA-CF @base.json b/resources/profiles/BBL/filament/Bambu PA-CF @base.json index f4be03cdcd..6091597136 100644 --- a/resources/profiles/BBL/filament/Bambu PA-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu PA-CF @base.json @@ -5,6 +5,9 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_pa", + "required_nozzle_HRC": [ + "55" + ], "filament_vendor": [ "Bambu Lab" ], @@ -17,6 +20,12 @@ "nozzle_temperature_initial_layer": [ "280" ], + "overhang_fan_threshold": [ + "0%" + ], + "overhang_fan_speed": [ + "40" + ], "filament_type": [ "PA-CF" ], diff --git a/resources/profiles/BBL/filament/Bambu PET-CF @base.json b/resources/profiles/BBL/filament/Bambu PET-CF @base.json index 7fe02b6b25..459e2acbe9 100644 --- a/resources/profiles/BBL/filament/Bambu PET-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu PET-CF @base.json @@ -5,6 +5,9 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_pet", + "required_nozzle_HRC": [ + "40" + ], "filament_vendor": [ "Bambu Lab" ], diff --git a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL X1.json b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL X1.json index 0957d4dd0f..37cbb87b17 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Basic @BBL X1.json +++ b/resources/profiles/BBL/filament/Bambu PLA Basic @BBL X1.json @@ -15,5 +15,5 @@ "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" - ] + ] } diff --git a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL X1.json b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL X1.json index 83332e44ca..e775f0acf7 100644 --- a/resources/profiles/BBL/filament/Bambu PLA Matte @BBL X1.json +++ b/resources/profiles/BBL/filament/Bambu PLA Matte @BBL X1.json @@ -12,8 +12,8 @@ "8" ], "compatible_printers": [ - "Bambu Lab X1 0.4 nozzle", - "Bambu Lab X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" ] } diff --git a/resources/profiles/BBL/filament/Bambu Support G @BBL X1C.json b/resources/profiles/BBL/filament/Bambu Support G @BBL X1C.json index 3692f2dcc1..8733c225fa 100644 --- a/resources/profiles/BBL/filament/Bambu Support G @BBL X1C.json +++ b/resources/profiles/BBL/filament/Bambu Support G @BBL X1C.json @@ -9,6 +9,7 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" ] diff --git a/resources/profiles/BBL/filament/Bambu Support G @base.json b/resources/profiles/BBL/filament/Bambu Support G @base.json index 21d303dbac..d79ea893df 100644 --- a/resources/profiles/BBL/filament/Bambu Support G @base.json +++ b/resources/profiles/BBL/filament/Bambu Support G @base.json @@ -5,6 +5,9 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_pa", + "required_nozzle_HRC": [ + "3" + ], "filament_vendor": [ "Bambu Lab" ], diff --git a/resources/profiles/BBL/filament/Bambu Support W @BBL X1.json b/resources/profiles/BBL/filament/Bambu Support W @BBL X1.json index c5f6c4454f..530eae88ef 100644 --- a/resources/profiles/BBL/filament/Bambu Support W @BBL X1.json +++ b/resources/profiles/BBL/filament/Bambu Support W @BBL X1.json @@ -9,5 +9,5 @@ "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" - ] + ] } diff --git a/resources/profiles/BBL/filament/Bambu Support W @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/filament/Bambu Support W @BBL X1C 0.2 nozzle.json index 3c7f11f85d..603f193d28 100644 --- a/resources/profiles/BBL/filament/Bambu Support W @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/Bambu Support W @BBL X1C 0.2 nozzle.json @@ -15,7 +15,7 @@ "240" ], "compatible_printers": [ - "Bambu Lab X1 Carbon 0.2 nozzle", - "Bambu Lab X1 0.2 nozzle" + "Bambu Lab X1 Carbon 0.2 nozzle", + "Bambu Lab X1 0.2 nozzle" ] } \ No newline at end of file diff --git a/resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1.json b/resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1.json index 9c041fa4f9..db5b1d0580 100644 --- a/resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1.json +++ b/resources/profiles/BBL/filament/Bambu TPU 95A @BBL X1.json @@ -12,5 +12,5 @@ "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" - ] + ] } diff --git a/resources/profiles/BBL/filament/Generic PA-CF.json b/resources/profiles/BBL/filament/Generic PA-CF.json index 55b8285143..51ca84dff0 100644 --- a/resources/profiles/BBL/filament/Generic PA-CF.json +++ b/resources/profiles/BBL/filament/Generic PA-CF.json @@ -8,33 +8,40 @@ "inherits": "fdm_filament_pa", "filament_type": [ "PA-CF" - ], - "nozzle_temperature_initial_layer": [ + ], + "nozzle_temperature_initial_layer": [ "290" - ], - "nozzle_temperature": [ + ], + "nozzle_temperature": [ "290" - ], - "filament_max_volumetric_speed": [ + ], + "filament_max_volumetric_speed": [ "8" - ], - "fan_max_speed": [ - "40" + ], + "fan_max_speed": [ + "30" ], "fan_min_speed": [ "10" - ], + ], + "overhang_fan_threshold": [ + "0%" + ], + "overhang_fan_speed": [ + "40" + ], "fan_cooling_layer_time": [ - "6" - ], + "5" + ], "full_fan_speed_layer": [ "2" ], "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 X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" - ] + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] } diff --git a/resources/profiles/BBL/filament/Generic PA.json b/resources/profiles/BBL/filament/Generic PA.json index f6baca4474..f466c7d3cd 100644 --- a/resources/profiles/BBL/filament/Generic PA.json +++ b/resources/profiles/BBL/filament/Generic PA.json @@ -6,6 +6,9 @@ "from": "system", "instantiation": "true", "inherits": "fdm_filament_pa", + "required_nozzle_HRC": [ + "3" + ], "nozzle_temperature_initial_layer": [ "280" ], @@ -19,6 +22,7 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" ] diff --git a/resources/profiles/BBL/filament/Generic PC.json b/resources/profiles/BBL/filament/Generic PC.json index 6556f61cd5..1a322050c5 100644 --- a/resources/profiles/BBL/filament/Generic PC.json +++ b/resources/profiles/BBL/filament/Generic PC.json @@ -9,6 +9,7 @@ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" ] diff --git a/resources/profiles/BBL/filament/Generic PETG @0.2 nozzle.json b/resources/profiles/BBL/filament/Generic PETG @0.2 nozzle.json new file mode 100644 index 0000000000..0965504e40 --- /dev/null +++ b/resources/profiles/BBL/filament/Generic PETG @0.2 nozzle.json @@ -0,0 +1,15 @@ +{ + "type": "filament", + "setting_id": "GFSG99_01", + "name": "Generic PETG @0.2 nozzle.json", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG @base", + "filament_max_volumetric_speed": [ + "1" + ], + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.2 nozzle", + "Bambu Lab X1 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/Generic PETG @base.json b/resources/profiles/BBL/filament/Generic PETG @base.json index fd9ac2b834..98f25bdf71 100644 --- a/resources/profiles/BBL/filament/Generic PETG @base.json +++ b/resources/profiles/BBL/filament/Generic PETG @base.json @@ -41,6 +41,18 @@ "nozzle_temperature_range_high": [ "270" ], + "cool_plate_temp" : [ + "0" + ], + "eng_plate_temp" : [ + "70" + ], + "cool_plate_temp_initial_layer" : [ + "0" + ], + "eng_plate_temp_initial_layer" : [ + "70" + ], "hot_plate_temp" : [ "70" ], diff --git a/resources/profiles/BBL/filament/Generic PLA Silk.json b/resources/profiles/BBL/filament/Generic PLA Silk.json new file mode 100644 index 0000000000..16dc0cc49b --- /dev/null +++ b/resources/profiles/BBL/filament/Generic PLA Silk.json @@ -0,0 +1,22 @@ +{ + "type": "filament", + "setting_id": "GFSL99_01", + "name": "Generic PLA Silk", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA @base", + "filament_max_volumetric_speed": [ + "7.5" + ], + "filament_retraction_length": [ + "0.5" + ], + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/Generic PLA-CF @base.json b/resources/profiles/BBL/filament/Generic PLA-CF @base.json new file mode 100644 index 0000000000..df8db5d345 --- /dev/null +++ b/resources/profiles/BBL/filament/Generic PLA-CF @base.json @@ -0,0 +1,38 @@ +{ + "type": "filament", + "filament_id": "GFL98", + "name": "Generic PLA-CF @base", + "from": "system", + "instantiation": "false", + "inherits": "fdm_filament_pla", + "required_nozzle_HRC": [ + "40" + ], + "filament_flow_ratio": [ + "0.95" + ], + "filament_type": [ + "PLA-CF" + ], + "filament_max_volumetric_speed": [ + "12" + ], + "slow_down_layer_time": [ + "7" + ], + "additional_cooling_fan_speed": [ + "0" + ], + "temperature_vitrification": [ + "55" + ], + "nozzle_temperature_range_low": [ + "190" + ], + "nozzle_temperature_range_high": [ + "240" + ], + "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}" + ] +} diff --git a/resources/profiles/BBL/filament/Generic PLA-CF.json b/resources/profiles/BBL/filament/Generic PLA-CF.json index 3e28238475..4151ffcbc9 100644 --- a/resources/profiles/BBL/filament/Generic PLA-CF.json +++ b/resources/profiles/BBL/filament/Generic PLA-CF.json @@ -1,43 +1,16 @@ { "type": "filament", - "filament_id": "GFL98", "setting_id": "GFSL98", "name": "Generic PLA-CF", "from": "system", "instantiation": "true", - "inherits": "fdm_filament_pla", - "filament_flow_ratio": [ - "0.95" - ], - "filament_type": [ - "PLA-CF" - ], - "filament_max_volumetric_speed": [ - "12" - ], - "slow_down_layer_time": [ - "7" - ], - "additional_cooling_fan_speed": [ - "0" - ], - "temperature_vitrification": [ - "55" - ], - "nozzle_temperature_range_low": [ - "190" - ], - "nozzle_temperature_range_high": [ - "240" - ], - "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}" - ], + "inherits": "Generic PLA-CF @base", "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 X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" - ] + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle", + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] } diff --git a/resources/profiles/BBL/filament/Generic PVA.json b/resources/profiles/BBL/filament/Generic PVA.json index 8d47383d3d..961b77bf77 100644 --- a/resources/profiles/BBL/filament/Generic PVA.json +++ b/resources/profiles/BBL/filament/Generic PVA.json @@ -8,6 +8,7 @@ "compatible_printers": [ "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", "Bambu Lab X1 Carbon 0.8 nozzle", "Bambu Lab X1 0.6 nozzle", "Bambu Lab X1 0.8 nozzle" diff --git a/resources/profiles/BBL/filament/Generic TPU.json b/resources/profiles/BBL/filament/Generic TPU.json index a03c7a253a..5df255d936 100644 --- a/resources/profiles/BBL/filament/Generic TPU.json +++ b/resources/profiles/BBL/filament/Generic TPU.json @@ -13,11 +13,11 @@ "; 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}" ], "compatible_printers": [ - "Bambu Lab X1 Carbon 0.4 nozzle", "Bambu Lab X1 0.4 nozzle", - "Bambu Lab X1 Carbon 0.6 nozzle", - "Bambu Lab X1 Carbon 0.8 nozzle", "Bambu Lab X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" + "Bambu Lab X1 0.8 nozzle", + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle" ] } diff --git a/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..f7603eeea9 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSB00_02", + "name": "Bambu ABS @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS @base", + "filament_max_volumetric_speed": [ + "2" + ], + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 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 new file mode 100644 index 0000000000..9c585c9a6b --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu ABS @BBL P1P.json @@ -0,0 +1,34 @@ +{ + "type": "filament", + "setting_id": "GFSB00_03", + "name": "Bambu ABS @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu ABS @base", + "filament_max_volumetric_speed": [ + "22" + ], + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PA-CF @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu PA-CF @BBL P1P.json new file mode 100644 index 0000000000..1afbe432b6 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PA-CF @BBL P1P.json @@ -0,0 +1,34 @@ +{ + "type": "filament", + "setting_id": "GFSN00_10", + "name": "Bambu PA-CF @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PA-CF @base", + "filament_max_volumetric_speed": [ + "8" + ], + "nozzle_temperature_initial_layer": [ + "290" + ], + "nozzle_temperature": [ + "290" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "10" + ], + "fan_cooling_layer_time": [ + "5" + ], + "full_fan_speed_layer": [ + "2" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..9939eb446c --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P 0.2 nozzle.json @@ -0,0 +1,23 @@ +{ + "type": "filament", + "setting_id": "GFSC00_03", + "name": "Bambu PC @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PC @base", + "filament_max_volumetric_speed": [ + "1" + ], + "nozzle_temperature": [ + "260" + ], + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P.json new file mode 100644 index 0000000000..38d40953c0 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PC @BBL P1P.json @@ -0,0 +1,19 @@ +{ + "type": "filament", + "setting_id": "GFSC00_04", + "name": "Bambu PC @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PC @base", + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..afce920b5a --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSA00_10", + "name": "Bambu PLA Basic @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA Basic @base", + "filament_max_volumetric_speed": [ + "2" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P.json new file mode 100644 index 0000000000..11921d2b46 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PLA Basic @BBL P1P.json @@ -0,0 +1,37 @@ +{ + "type": "filament", + "setting_id": "GFSA04_10", + "name": "Bambu PLA Basic @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA Basic @base", + "filament_max_volumetric_speed": [ + "21" + ], + "slow_down_layer_time": [ + "8" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..0196d2a6a9 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSA01_10", + "name": "Bambu PLA Matte @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA Matte @base", + "filament_max_volumetric_speed": [ + "2" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P.json new file mode 100644 index 0000000000..aa3ac96dc4 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu PLA Matte @BBL P1P.json @@ -0,0 +1,37 @@ +{ + "type": "filament", + "setting_id": "GFSA05_10", + "name": "Bambu PLA Matte @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu PLA Matte @base", + "filament_max_volumetric_speed": [ + "22" + ], + "slow_down_layer_time": [ + "8" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu Support G @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu Support G @BBL P1P.json new file mode 100644 index 0000000000..ab03c12c37 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu Support G @BBL P1P.json @@ -0,0 +1,13 @@ +{ + "type": "filament", + "setting_id": "GFSS01_10", + "name": "Bambu Support G @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Support G @base", + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..820a7da2af --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P 0.2 nozzle.json @@ -0,0 +1,38 @@ +{ + "type": "filament", + "setting_id": "GFSS00_10", + "name": "Bambu Support W @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Support W @base", + "filament_max_volumetric_speed": [ + "0.5" + ], + "nozzle_temperature_initial_layer": [ + "240" + ], + "nozzle_temperature": [ + "240" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P.json new file mode 100644 index 0000000000..01700c8440 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu Support W @BBL P1P.json @@ -0,0 +1,31 @@ +{ + "type": "filament", + "setting_id": "GFSS02_10", + "name": "Bambu Support W @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Support W @base", + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} 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 new file mode 100644 index 0000000000..bf58213831 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Bambu TPU 95A @BBL P1P.json @@ -0,0 +1,28 @@ +{ + "type": "filament", + "setting_id": "GFSU01_10", + "name": "Bambu TPU 95A @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Bambu TPU 95A @base", + "filament_max_volumetric_speed": [ + "6.4" + ], + "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" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..ae2447b030 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSB99_02", + "name": "Generic ABS @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS @base", + "filament_max_volumetric_speed": [ + "2" + ], + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json new file mode 100644 index 0000000000..12c954002a --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic ABS @BBL P1P.json @@ -0,0 +1,31 @@ +{ + "type": "filament", + "setting_id": "GFSB99_01", + "name": "Generic ABS @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic ABS @base", + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..9b74c093d0 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P 0.2 nozzle.json @@ -0,0 +1,26 @@ +{ + "type": "filament", + "setting_id": "GFSB98_11", + "name": "Generic ASA @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic ASA @base", + "filament_max_volumetric_speed": [ + "2" + ], + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P.json new file mode 100644 index 0000000000..8802f7bdad --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic ASA @BBL P1P.json @@ -0,0 +1,25 @@ +{ + "type": "filament", + "setting_id": "GFSB98_10", + "name": "Generic ASA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic ASA @base", + "hot_plate_temp" : [ + "100" + ], + "hot_plate_temp_initial_layer" : [ + "100" + ], + "textured_plate_temp" : [ + "100" + ], + "textured_plate_temp_initial_layer" : [ + "100" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PA @BBL P1P.json new file mode 100644 index 0000000000..a8fc99a311 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PA @BBL P1P.json @@ -0,0 +1,26 @@ +{ + "type": "filament", + "filament_id": "GFN99", + "setting_id": "GFSN98_10", + "name": "Generic PA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pa", + "required_nozzle_HRC": [ + "3" + ], + "nozzle_temperature_initial_layer": [ + "280" + ], + "nozzle_temperature": [ + "280" + ], + "filament_max_volumetric_speed": [ + "16" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" +] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PA-CF @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PA-CF @BBL P1P.json new file mode 100644 index 0000000000..7d084b2c25 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PA-CF @BBL P1P.json @@ -0,0 +1,44 @@ +{ + "type": "filament", + "filament_id": "GFN98", + "setting_id": "GFSN99_10", + "name": "Generic PA-CF @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_pa", + "filament_type": [ + "PA-CF" + ], + "nozzle_temperature_initial_layer": [ + "290" + ], + "nozzle_temperature": [ + "290" + ], + "filament_max_volumetric_speed": [ + "8" + ], + "fan_max_speed": [ + "30" + ], + "fan_min_speed": [ + "10" + ], + "overhang_fan_threshold": [ + "0%" + ], + "overhang_fan_speed": [ + "40" + ], + "fan_cooling_layer_time": [ + "5" + ], + "full_fan_speed_layer": [ + "2" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..e5d8b1c39d --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P 0.2 nozzle.json @@ -0,0 +1,20 @@ +{ + "type": "filament", + "setting_id": "GFSC99_01", + "name": "Generic PC @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC @base", + "filament_max_volumetric_speed": [ + "1" + ], + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} \ No newline at end of file diff --git a/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P.json new file mode 100644 index 0000000000..413af620b8 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PC @BBL P1P.json @@ -0,0 +1,19 @@ +{ + "type": "filament", + "setting_id": "GFSC99_02", + "name": "Generic PC @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic PC @base", + "fan_max_speed": [ + "20" + ], + "reduce_fan_stop_start_freq": [ + "0" + ], + "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/P1P/Generic PETG @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic PETG @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..a45a05b9bb --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PETG @BBL P1P 0.2 nozzle.json @@ -0,0 +1,23 @@ +{ + "type": "filament", + "setting_id": "GFSG99_11", + "name": "Generic PETG @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG @base", + "hot_plate_temp" : [ + "80" + ], + "hot_plate_temp_initial_layer" : [ + "80" + ], + "textured_plate_temp" : [ + "80" + ], + "textured_plate_temp_initial_layer" : [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PETG @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PETG @BBL P1P.json new file mode 100644 index 0000000000..cbae651f8a --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PETG @BBL P1P.json @@ -0,0 +1,25 @@ +{ + "type": "filament", + "setting_id": "GFSG99_10", + "name": "Generic PETG @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic PETG @base", + "hot_plate_temp" : [ + "80" + ], + "hot_plate_temp_initial_layer" : [ + "80" + ], + "textured_plate_temp" : [ + "80" + ], + "textured_plate_temp_initial_layer" : [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..b6f3fef0a7 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P 0.2 nozzle.json @@ -0,0 +1,35 @@ +{ + "type": "filament", + "setting_id": "GFSL99_11", + "name": "Generic PLA @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA @base", + "filament_max_volumetric_speed": [ + "2" + ], + "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}" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P.json new file mode 100644 index 0000000000..8f5ecefc3f --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PLA @BBL P1P.json @@ -0,0 +1,31 @@ +{ + "type": "filament", + "setting_id": "GFSL99_10", + "name": "Generic PLA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA @base", + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PLA-CF @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PLA-CF @BBL P1P.json new file mode 100644 index 0000000000..7f8bffb761 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PLA-CF @BBL P1P.json @@ -0,0 +1,25 @@ +{ + "type": "filament", + "setting_id": "GFSL98_10", + "name": "Generic PLA-CF @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic PLA-CF @base", + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..dab75dd701 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P 0.2 nozzle.json @@ -0,0 +1,26 @@ +{ + "type": "filament", + "setting_id": "GFSS99_11", + "name": "Generic PVA @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Generic PVA @base", + "filament_max_volumetric_speed": [ + "0.5" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P.json new file mode 100644 index 0000000000..8bedcc72cb --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic PVA @BBL P1P.json @@ -0,0 +1,31 @@ +{ + "type": "filament", + "setting_id": "GFSS99_10", + "name": "Generic PVA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "Generic PVA @base", + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/Generic TPU @BBL P1P.json b/resources/profiles/BBL/filament/P1P/Generic TPU @BBL P1P.json new file mode 100644 index 0000000000..c085a57d57 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/Generic TPU @BBL P1P.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "filament_id": "GFU99", + "setting_id": "GFSR99_10", + "name": "Generic TPU @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "fdm_filament_tpu", + "filament_max_volumetric_speed": [ + "3.2" + ], + "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}" + ], + "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" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..0bc8d0e0c0 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSL25_10", + "name": "PolyLite PLA @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA @BBL X1C", + "filament_max_volumetric_speed": [ + "1" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P.json new file mode 100644 index 0000000000..ced0f6fa41 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/PolyLite PLA @BBL P1P.json @@ -0,0 +1,37 @@ +{ + "type": "filament", + "setting_id": "GFSL23_10", + "name": "PolyLite PLA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "PolyLite PLA @base", + "filament_max_volumetric_speed": [ + "15" + ], + "slow_down_layer_time": [ + "8" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..8c876821c4 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P 0.2 nozzle.json @@ -0,0 +1,32 @@ +{ + "type": "filament", + "setting_id": "GFSL24_10", + "name": "PolyTerra PLA @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "PolyTerra PLA @BBL X1C", + "filament_max_volumetric_speed": [ + "1" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P.json b/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P.json new file mode 100644 index 0000000000..8f5f4141a5 --- /dev/null +++ b/resources/profiles/BBL/filament/P1P/PolyTerra PLA @BBL P1P.json @@ -0,0 +1,37 @@ +{ + "type": "filament", + "setting_id": "GFSL22_10", + "name": "PolyTerra PLA @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "PolyTerra PLA @base", + "filament_max_volumetric_speed": [ + "22" + ], + "slow_down_layer_time": [ + "8" + ], + "hot_plate_temp" : [ + "65" + ], + "hot_plate_temp_initial_layer" : [ + "65" + ], + "textured_plate_temp" : [ + "65" + ], + "textured_plate_temp_initial_layer" : [ + "65" + ], + "fan_min_speed": [ + "50" + ], + "fan_cooling_layer_time": [ + "80" + ], + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle", + "Bambu Lab P1P 0.6 nozzle", + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/filament/PolyLite PLA @BBL X1.json b/resources/profiles/BBL/filament/PolyLite PLA @BBL X1.json index f92a2fda20..b1854271e6 100644 --- a/resources/profiles/BBL/filament/PolyLite PLA @BBL X1.json +++ b/resources/profiles/BBL/filament/PolyLite PLA @BBL X1.json @@ -12,8 +12,8 @@ "8" ], "compatible_printers": [ - "Bambu Lab X1 0.4 nozzle", - "Bambu Lab X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" - ] + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] } diff --git a/resources/profiles/BBL/filament/PolyLite PLA @BBL X1C 0.2 nozzle.json b/resources/profiles/BBL/filament/PolyLite PLA @BBL X1C 0.2 nozzle.json index 28283fa458..9e3a86c788 100644 --- a/resources/profiles/BBL/filament/PolyLite PLA @BBL X1C 0.2 nozzle.json +++ b/resources/profiles/BBL/filament/PolyLite PLA @BBL X1C 0.2 nozzle.json @@ -6,7 +6,7 @@ "instantiation": "true", "inherits": "PolyLite PLA @BBL X1C", "filament_max_volumetric_speed": [ - "15" + "1" ], "compatible_printers": [ "Bambu Lab X1 Carbon 0.2 nozzle", diff --git a/resources/profiles/BBL/filament/PolyTerra PLA @BBL X1.json b/resources/profiles/BBL/filament/PolyTerra PLA @BBL X1.json index 98a8e2d6dd..ff2b229b2f 100644 --- a/resources/profiles/BBL/filament/PolyTerra PLA @BBL X1.json +++ b/resources/profiles/BBL/filament/PolyTerra PLA @BBL X1.json @@ -12,8 +12,8 @@ "8" ], "compatible_printers": [ - "Bambu Lab X1 0.4 nozzle", - "Bambu Lab X1 0.6 nozzle", - "Bambu Lab X1 0.8 nozzle" - ] + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 0.8 nozzle" + ] } diff --git a/resources/profiles/BBL/filament/fdm_filament_abs.json b/resources/profiles/BBL/filament/fdm_filament_abs.json index c89c9bf55f..16497a718d 100644 --- a/resources/profiles/BBL/filament/fdm_filament_abs.json +++ b/resources/profiles/BBL/filament/fdm_filament_abs.json @@ -5,7 +5,7 @@ "instantiation": "false", "inherits": "fdm_filament_common", "cool_plate_temp" : [ - "90" + "0" ], "eng_plate_temp" : [ "90" @@ -17,7 +17,7 @@ "90" ], "cool_plate_temp_initial_layer" : [ - "90" + "0" ], "eng_plate_temp_initial_layer" : [ "90" diff --git a/resources/profiles/BBL/filament/fdm_filament_asa.json b/resources/profiles/BBL/filament/fdm_filament_asa.json index 7f05e2b3c2..3714e43235 100644 --- a/resources/profiles/BBL/filament/fdm_filament_asa.json +++ b/resources/profiles/BBL/filament/fdm_filament_asa.json @@ -5,7 +5,7 @@ "instantiation": "false", "inherits": "fdm_filament_common", "cool_plate_temp" : [ - "90" + "0" ], "eng_plate_temp" : [ "90" @@ -17,7 +17,7 @@ "90" ], "cool_plate_temp_initial_layer" : [ - "90" + "0" ], "eng_plate_temp_initial_layer" : [ "90" diff --git a/resources/profiles/BBL/filament/fdm_filament_common.json b/resources/profiles/BBL/filament/fdm_filament_common.json index 208d6ac175..17813e6170 100644 --- a/resources/profiles/BBL/filament/fdm_filament_common.json +++ b/resources/profiles/BBL/filament/fdm_filament_common.json @@ -3,6 +3,9 @@ "name": "fdm_filament_common", "from": "system", "instantiation": "false", + "required_nozzle_HRC": [ + "3" + ], "cool_plate_temp" : [ "60" ], @@ -40,7 +43,7 @@ "3" ], "filament_end_gcode": [ - "; filament end gcode \n;M106 P3 S0\n" + "; filament end gcode \nM106 P3 S0\n" ], "filament_flow_ratio": [ "1" diff --git a/resources/profiles/BBL/filament/fdm_filament_pa.json b/resources/profiles/BBL/filament/fdm_filament_pa.json index ce1b3d653c..0e8ceff002 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pa.json +++ b/resources/profiles/BBL/filament/fdm_filament_pa.json @@ -4,6 +4,9 @@ "from": "system", "instantiation": "false", "inherits": "fdm_filament_common", + "required_nozzle_HRC": [ + "40" + ], "cool_plate_temp" : [ "0" ], diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P 0.2 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1P 0.2 nozzle.json new file mode 100644 index 0000000000..5331500ad1 --- /dev/null +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.2 nozzle.json @@ -0,0 +1,34 @@ +{ + "type": "machine", + "setting_id": "GM010", + "name": "Bambu Lab P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Lab P1P 0.4 nozzle", + "printer_model": "Bambu Lab P1P", + "nozzle_diameter": [ + "0.2" + ], + "printer_variant": "0.2", + "default_filament_profile": [ + "Bambu PLA Basic @BBL X1C 0.2 nozzle" + ], + "default_print_profile": "0.10mm Standard @BBL P1P 0.2 nozzle", + "max_layer_height": [ + "0.14" + ], + "min_layer_height": [ + "0.04" + ], + "retraction_length": [ + "0.4" + ], + "retraction_minimum_travel": [ + "5" + ], + "machine_start_gcode": ";===== machine: P1P ========================\n;===== date: 202201114 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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", + "upward_compatible_machine":[ + "Bambu Lab X1 0.2 nozzle", + "Bambu Lab X1 Carbon 0.2 nozzle" + ] +} 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 new file mode 100644 index 0000000000..ca21332295 --- /dev/null +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.4 nozzle.json @@ -0,0 +1,38 @@ +{ + "type": "machine", + "setting_id": "GM013", + "name": "Bambu Lab P1P 0.4 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_bbl_3dp_001_common", + "printer_model": "Bambu Lab P1P", + "default_filament_profile": [ + "Bambu PLA Basic @BBL X1" + ], + "default_print_profile": "0.20mm Standard @BBL P1P", + "nozzle_diameter": [ + "0.4" + ], + "extruder_offset": [ + "0x2" + ], + "bed_exclude_area": [ + "0x0", + "18x0", + "18x28", + "0x28" + ], + "machine_pause_gcode": "M400 U1\n", + "machine_start_gcode": ";===== machine: P1P ========================\n;===== date: 202201114 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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_end_gcode": ";===== date: 20221202 =====================\n{if timelapse_type == 0}\nM991 S0 P-1 ;end traditional 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 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n{if timelapse_type == 1}\nM991 S0 P-1 ;end smooth timelapse at safe pos\n{endif}\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\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\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\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) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 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\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n", + "scan_first_layer": "0", + "machine_load_filament_time": "17", + "machine_unload_filament_time": "16", + "nozzle_type": "stainless_steel", + "nozzle_hrc": "20", + "auxiliary_fan": "0", + "upward_compatible_machine":[ + "Bambu Lab X1 0.4 nozzle", + "Bambu Lab X1 Carbon 0.4 nozzle" + ] + } diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P 0.6 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1P 0.6 nozzle.json new file mode 100644 index 0000000000..5ab6a52f20 --- /dev/null +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.6 nozzle.json @@ -0,0 +1,36 @@ +{ + "type": "machine", + "setting_id": "GM011", + "name": "Bambu Lab P1P 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Lab P1P 0.4 nozzle", + "printer_model": "Bambu Lab P1P", + "default_filament_profile": [ + "Bambu PLA Basic @BBL X1" + ], + "default_print_profile": "0.30mm Standard @BBL P1P 0.6 nozzle", + "nozzle_diameter": [ + "0.6" + ], + "printer_variant": "0.6", + "max_layer_height": [ + "0.42" + ], + "min_layer_height": [ + "0.12" + ], + "retraction_length": [ + "1.4" + ], + "retraction_minimum_travel": [ + "3" + ], + "machine_start_gcode": ";===== machine: P1P ========================\n;===== date: 202201114 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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", + "nozzle_type": "hardened_steel", + "nozzle_hrc": "55", + "upward_compatible_machine":[ + "Bambu Lab X1 0.6 nozzle", + "Bambu Lab X1 Carbon 0.6 nozzle" + ] +} diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P 0.8 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab P1P 0.8 nozzle.json new file mode 100644 index 0000000000..d60dc1e62a --- /dev/null +++ b/resources/profiles/BBL/machine/Bambu Lab P1P 0.8 nozzle.json @@ -0,0 +1,39 @@ +{ + "type": "machine", + "setting_id": "GM012", + "name": "Bambu Lab P1P 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "Bambu Lab P1P 0.4 nozzle", + "printer_model": "Bambu Lab P1P", + "default_filament_profile": [ + "Bambu PLA Basic @BBL X1" + ], + "nozzle_diameter": [ + "0.8" + ], + "printer_variant": "0.8", + "default_print_profile": "0.40mm Standard @BBL P1P 0.8 nozzle", + "max_layer_height": [ + "0.56" + ], + "min_layer_height": [ + "0.16" + ], + "retraction_length": [ + "3" + ], + "retraction_minimum_travel": [ + "1" + ], + "retract_length_toolchange": [ + "3" + ], + "machine_start_gcode": ";===== machine: P1P ========================\n;===== date: 202201114 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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", + "nozzle_type": "hardened_steel", + "nozzle_hrc": "55", + "upward_compatible_machine":[ + "Bambu Lab X1 0.8 nozzle", + "Bambu Lab X1 Carbon 0.8 nozzle" + ] + } diff --git a/resources/profiles/BBL/machine/Bambu Lab P1P.json b/resources/profiles/BBL/machine/Bambu Lab P1P.json new file mode 100644 index 0000000000..c08537f872 --- /dev/null +++ b/resources/profiles/BBL/machine/Bambu Lab P1P.json @@ -0,0 +1,13 @@ +{ + "type": "machine_model", + "name": "Bambu Lab P1P", + "model_id": "C11", + "url": "http://www.bambulab.com/Parameters/printer_model/Bambu Lab X1.json", + "nozzle_diameter": "0.4;0.2;0.6;0.8", + "machine_tech": "FFF", + "family": "BBL-3DP", + "bed_model": "bbl-3dp-X1.stl", + "bed_texture": "bbl-3dp-logo.svg", + "hotend_model": "bbl-3dp-hotend.stl", + "default_materials": "Generic PLA @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;" +} diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 0.2 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 0.2 nozzle.json index f38ac5f3ad..b555f9b12e 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 0.2 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 0.2 nozzle.json @@ -26,7 +26,9 @@ "retraction_minimum_travel": [ "5" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nG0 Y15 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E1\nG0 Y5.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F4800 \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.160 \n G0 X45.000 F30000 \n G0 Y20.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 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.080 \n G0 X45.000 F30000 \n G0 Y22.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 Y18.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 Y24.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 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.080 K0.160\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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.08 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.08}\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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", - "nozzle_type": "stainless_steel" + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83\n\t{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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F4800 \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.160 \n G0 X45.000 F30000 \n G0 Y20.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 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.080 \n G0 X45.000 F30000 \n G0 Y22.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 Y18.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 Y24.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 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.080 K0.160\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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.08 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.08}\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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", + "nozzle_type": "stainless_steel", + "upward_compatible_machine":[ + "Bambu Lab X1 Carbon 0.2 nozzle" + ] } - \ 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 d344917c46..2b561c72a8 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 @@ -22,12 +22,20 @@ "18x28", "0x28" ], + "machine_max_speed_z": [ + "20", + "20" + ], "machine_pause_gcode": "M400 U1\n", - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nG0 Y15 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E1\nG0 Y5.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n\n ;G0 X18 Y28 F20000\n ;G0 Y0\n ;G0 Z0.3\n ;G0 X250 E18 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n ;G0 Y0.5\n ;G0 X18 E18 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n G0 X35.000 Y18.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 Y20.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 Y18.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 Y22.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 Y18.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 Y24.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 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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_end_gcode": ";===== date: 202200913 =====================\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 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\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\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\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) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 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\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n\n", + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \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 Y18.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 Y20.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 Y18.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 Y22.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 Y18.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 Y24.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 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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_end_gcode": ";===== date: 20221202 =====================\n{if timelapse_type == 0}\nM991 S0 P-1 ;end traditional 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 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n{if timelapse_type == 1}\nM991 S0 P-1 ;end smooth timelapse at safe pos\n{endif}\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\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\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\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) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 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\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n", "scan_first_layer": "1", "machine_load_filament_time": "17", "machine_unload_filament_time": "16", "nozzle_type": "stainless_steel", - "auxiliary_fan": "0" + "nozzle_hrc": "20", + "auxiliary_fan": "0", + "upward_compatible_machine":[ + "Bambu Lab X1 Carbon 0.4 nozzle" + ] } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 0.6 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 0.6 nozzle.json index 197e59c340..54a1bf58cc 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 0.6 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 0.6 nozzle.json @@ -4,7 +4,7 @@ "name": "Bambu Lab X1 0.6 nozzle", "from": "system", "instantiation": "true", - "inherits": "Bambu Lab X1 0.4 nozzle", + "inherits": "Bambu Lab X1 0.4 nozzle", "printer_model": "Bambu Lab X1", "default_filament_profile": [ "Bambu PLA Basic @BBL X1" @@ -26,6 +26,10 @@ "retraction_minimum_travel": [ "3" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 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 E1.666\nG0 Y5.5 E1.166\nG0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.679 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.032 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.679 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.164 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.944 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.428 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.725 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.329 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.725 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.362 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.910 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.186 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.384 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.318 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.461 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.318 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n\n ;G0 X18 Y28 F20000\n ;G0 Y0\n ;G0 Z0.3\n ;G0 X250 E25 F{outer_wall_volumetric_speed/(0.3*0.9) * 60}\n ;G0 Y0.9\n ;G0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.9) * 60}\n\n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E16.9 F{outer_wall_volumetric_speed/(0.3*0.9) * 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.030 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.015 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.015 K0.030\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X135.000 E0.56250 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.015 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.015}\n M623 \n\n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X185.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X190.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X195.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X200.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X205.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X210.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X215.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X220.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X225.000 E0.56250 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", - "nozzle_type": "hardened_steel" -} \ No newline at end of file + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.679 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.032 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.679 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.164 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.944 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.428 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.725 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.329 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.725 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.362 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.910 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.186 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.384 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.318 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.461 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.318 \n G1 F1500.000 E-0.800 \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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E16.9 F{outer_wall_volumetric_speed/(0.3*0.9) * 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.030 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.015 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.015 K0.030\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X135.000 E0.56250 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.015 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.015}\n M623 \n\n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X185.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X190.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X195.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X200.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X205.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X210.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X215.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X220.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X225.000 E0.56250 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", + "nozzle_type": "hardened_steel", + "nozzle_hrc": "55", + "upward_compatible_machine":[ + "Bambu Lab X1 Carbon 0.6 nozzle" + ] +} diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 0.8 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 0.8 nozzle.json index e1863f8d35..da64994100 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 0.8 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 0.8 nozzle.json @@ -1,5 +1,5 @@ { - "type": "machine", + "type": "machine", "setting_id": "GM007", "name": "Bambu Lab X1 0.8 nozzle", "from": "system", @@ -29,6 +29,10 @@ "retract_length_toolchange": [ "3" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y4.5 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 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 E2\nG0 Y5.5 E1.500\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \nG0 X18 E15\nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.8660 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.0360 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.8660 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.1820 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E2.1600 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.4760 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.8060 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.3660 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.8060 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.4020 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E2.1220 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.3180 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.5380 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.4640 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.5120 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.4640 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X110.000 E9.35441 F4800 \n G0 X185.000 E9.35441 F4800 \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.020 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.010 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_layer[initial_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.010 K0.020\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature_initial_layer[initial_extruder]} \n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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.01 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14) *0.01}\n M623 \n\n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X185.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X190.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X195.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X200.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X205.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X210.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X215.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X220.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X225.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", - "nozzle_type": "hardened_steel" - } \ No newline at end of file + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\n{endif}\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.8660 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.0360 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.8660 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.1820 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E2.1600 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.4760 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.8060 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.3660 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.8060 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.4020 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E2.1220 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.3180 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.5380 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.4640 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.5120 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.4640 \n G1 F1500.000 E-0.800 \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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X110.000 E9.35441 F4800 \n G0 X185.000 E9.35441 F4800 \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.020 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.010 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_layer[initial_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.010 K0.020\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature_initial_layer[initial_extruder]} \n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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.01 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14) *0.01}\n M623 \n\n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X185.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X190.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X195.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X200.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X205.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X210.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X215.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X220.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X225.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", + "nozzle_type": "hardened_steel", + "nozzle_hrc": "55", + "upward_compatible_machine":[ + "Bambu Lab X1 Carbon 0.8 nozzle" + ] + } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.2 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.2 nozzle.json index d03e1f2275..85db85ce58 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.2 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.2 nozzle.json @@ -26,6 +26,7 @@ "retraction_minimum_travel": [ "5" ], -"machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nG0 Y15 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E1\nG0 Y5.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F4800 \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.160 \n G0 X45.000 F30000 \n G0 Y20.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 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.080 \n G0 X45.000 F30000 \n G0 Y22.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 Y18.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 Y24.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 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.080 K0.160\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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.08 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.08}\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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", - "nozzle_type": "stainless_steel" + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83\n\t{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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E9.35441 F4800 \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.160 \n G0 X45.000 F30000 \n G0 Y20.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 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.080 \n G0 X45.000 F30000 \n G0 Y22.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 Y18.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 Y24.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 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.080 K0.160\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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.08 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.08}\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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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", + "nozzle_type": "stainless_steel", + "nozzle_hrc": "20" } 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 3d9bc01fa8..eac1672e21 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 @@ -22,12 +22,17 @@ "18x28", "0x28" ], + "machine_max_speed_z": [ + "20", + "20" + ], "machine_pause_gcode": "M400 U1\n", - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 F300\nG0 X240 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nG0 Y15 E0.700 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\nG0 X239.5\nG0 E1\nG0 Y5.5 E0.700\nG0 X18 E15 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n\n ;G0 X18 Y28 F20000\n ;G0 Y0\n ;G0 Z0.3\n ;G0 X250 E18 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n ;G0 Y0.5\n ;G0 X18 E18 F{outer_wall_volumetric_speed/(0.3*0.5) * 60}\n\n G0 X35.000 Y18.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 Y20.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 Y18.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 Y22.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 Y18.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 Y24.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 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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_end_gcode": ";===== date: 202200913 =====================\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 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\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\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\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) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 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\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n\n", + "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E0.933 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.018 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E0.933 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.091 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.080 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.238 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.403 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.183 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.403 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.201 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.061 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E0.659 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E0.769 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E0.732 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.256 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E0.732 \n G1 F1500.000 E-0.800 \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 Y18.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 Y20.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 Y18.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 Y22.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 Y18.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 Y24.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 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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_end_gcode": ";===== date: 20221202 =====================\n{if timelapse_type == 0}\nM991 S0 P-1 ;end traditional 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 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n{if timelapse_type == 1}\nM991 S0 P-1 ;end smooth timelapse at safe pos\n{endif}\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\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\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\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) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 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\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n", "scan_first_layer": "1", "machine_load_filament_time": "17", "machine_unload_filament_time": "16", "nozzle_type": "hardened_steel", + "nozzle_hrc": "55", "auxiliary_fan": "1" } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.6 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.6 nozzle.json index 81e8152f78..d547f8b5b9 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.6 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.6 nozzle.json @@ -26,5 +26,5 @@ "retraction_minimum_travel": [ "3" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y5.0 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 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 E1.666\nG0 Y5.5 E1.166\nG0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.679 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.032 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.679 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.164 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.944 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.428 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.725 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.329 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.725 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.362 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.910 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.186 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.384 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.318 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.461 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.318 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n\n ;G0 X18 Y28 F20000\n ;G0 Y0\n ;G0 Z0.3\n ;G0 X250 E25 F{outer_wall_volumetric_speed/(0.3*0.9) * 60}\n ;G0 Y0.9\n ;G0 X18 E25 F{outer_wall_volumetric_speed/(0.3*0.9) * 60}\n\n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E16.9 F{outer_wall_volumetric_speed/(0.3*0.9) * 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.030 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.015 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.015 K0.030\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X135.000 E0.56250 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.015 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.015}\n M623 \n\n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X185.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X190.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X195.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X200.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X205.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X210.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X215.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X220.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X225.000 E0.56250 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.679 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.032 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.679 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.164 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E1.944 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.428 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.725 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.329 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.725 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.362 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E1.910 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.186 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.384 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.318 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.461 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.318 \n G1 F1500.000 E-0.800 \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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X185.000 E16.9 F{outer_wall_volumetric_speed/(0.3*0.9) * 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.030 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.015 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X135.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.9) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.015 K0.030\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature[initial_extruder]}\n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.25000 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60}\n G1 X70.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X75.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X80.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X85.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X90.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X95.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X100.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X105.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X110.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X115.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X120.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X125.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X130.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X135.000 E0.56250 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.015 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14)*0.015}\n M623 \n\n G1 X140.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X145.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X150.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X155.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X160.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X165.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X170.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X175.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X180.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X185.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X190.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X195.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X200.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X205.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X210.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X215.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5) * 60} \n G1 X220.000 E0.56250 F{outer_wall_volumetric_speed/(0.3*0.5)/ 4 * 60} \n G1 X225.000 E0.56250 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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" } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.8 nozzle.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.8 nozzle.json index 12e595ed26..28a7b8eacd 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.8 nozzle.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon 0.8 nozzle.json @@ -29,5 +29,5 @@ "retract_length_toolchange": [ "3" ], - "machine_start_gcode": ";===== machine: X1 =========================\n;===== date: 202200929 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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\n\n;===== heatbed preheat ====================\nM1002 gcode_claim_action : 2\n{if bbl_bed_temperature_gcode}\nM1002 set_heatbed_surface_temp:[bed_temperature_initial_layer_vector] ;config bed temps\nM140 A S[bed_temperature_initial_layer_single] ;set bed temp\nM190 A S[bed_temperature_initial_layer_single] ;wait for bed temp\n{else}\nM140 S[bed_temperature_initial_layer_single] ;set bed temp\nM190 S[bed_temperature_initial_layer_single] ;wait for bed temp\n{endif}\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0 \nM400 S1\n;===== check scanner clarity end =======================\n\n=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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{if scan_first_layer}\n;start heatbed scan====================================\nM976 S2 P1 \n{endif}\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 Y4.5 Z0.2 F18000;Move to start position\nM109 S{nozzle_temperature[initial_extruder]}\nG0 E3 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 E2\nG0 Y5.5 E1.500\nG0 X129 E15 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \nG0 X18 E15\nM400\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.8660 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.0360 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.8660 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.1820 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E2.1600 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.4760 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.8060 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.3660 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.8060 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.4020 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E2.1220 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.3180 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.5380 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.4640 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.5120 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.4640 \n G1 F1500.000 E-0.800 \n\n ;=========== extruder cali extrusion ================== \n T1000 \n M83 \n G0 X35.000 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X110.000 E9.35441 F4800 \n G0 X185.000 E9.35441 F4800 \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.020 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.010 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\nM104 S140\n\n\n;=========== laser and rgb calibration =========== \nM400\nM18 E\nM500 R\n\nM973 S3 P14\n\nG1 X120 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\nT1100\nG1 X143.0 Y5.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\nM960 S1 P1\nM400 P100\nM973 S6 P0; use auto exposure for horizontal laser by xcam\nM960 S0 P0\n\nG1 X240.0 Y10.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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_layer[initial_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.010 K0.020\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature_initial_layer[initial_extruder]} \n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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.01 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14) *0.01}\n M623 \n\n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X185.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X190.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X195.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X200.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X205.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X210.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X215.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X220.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X225.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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: 202201117 =====================\n;===== reset machine status =================\nG91\nM17 Z0.4 ; lower the z-motor current\nG0 Z12 F300 ; lower the hotbed , to prevent the nozzle is below the hotbed\nG0 Z-6;\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 Z0.0 ; clear z-trim value first\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_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_tool]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_tool]\n G1 X54 F12000\n G1 Y265\n M400\nM621 S[initial_tool]A\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;===== check scanner clarity ===========================\nM972 S5 P0\n;===== check scanner clarity end =======================\n\n;=============turn on fans to prevent PLA jamming=================\n{if filament_type[initial_tool]==\"PLA\"}\n {if (bed_temperature[current_extruder] >45)||(bed_temperature_initial_layer[current_extruder] >45)}\n M106 P3 S180\n {elsif (bed_temperature[current_extruder] >50)||(bed_temperature_initial_layer[current_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_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\n{endif}\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_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\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 G0 F3000 X28.000 Y19.500 Z0.200\n G1 F1200.0 X28.000 Y45.000 Z0.200 E1.8660 \n G1 F1200.0 X28.500 Y45.000 Z0.200 E0.0360 \n G1 F1200.0 X28.500 Y19.500 Z0.200 E1.8660 \n G1 F1200.0 X31.000 Y19.500 Z0.200 E0.1820 \n G1 F1200.0 X31.000 Y49.000 Z0.200 E2.1600 \n G1 F1200.0 X37.500 Y49.000 Z0.200 E0.4760 \n G1 F1200.0 X37.500 Y60.000 Z0.200 E0.8060 \n G1 F1200.0 X42.500 Y60.000 Z0.200 E0.3660 \n G1 F1200.0 X42.500 Y49.000 Z0.200 E0.8060 \n G1 F1200.0 X48.000 Y49.000 Z0.200 E0.4020 \n G1 F1200.0 X48.000 Y20.000 Z0.200 E2.1220 \n G1 F1200.0 X30.000 Y20.000 Z0.200 E1.3180 \n G1 F1200.0 X30.000 Y41.000 Z0.200 E1.5380 \n G1 F1200.0 X50.000 Y41.000 Z0.200 E1.4640 \n G1 F1200.0 X50.000 Y34.000 Z0.200 E0.5120 \n G1 F1200.0 X30.000 Y34.000 Z0.200 E1.4640 \n G1 F1500.000 E-0.800 \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 Y18.000 Z0.300 F30000 E0\n G1 F1500.000 E0.800 \n M106 S0 ; turn off fan\n G0 X110.000 E9.35441 F4800 \n G0 X185.000 E9.35441 F4800 \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.020 \n G0 X45.000 F30000 \n G0 Y20.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.000 F30000 ; move y to clear pos \n G1 Z0.3\n M400\n\n G0 X45.000 F30000 \n M900 K0.010 \n G0 X45.000 F30000 \n G0 Y22.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800 \n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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 Y24.000 F30000 \n G1 F1500.000 E0.800 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 F1500.000 E-0.800\n G1 X183 Z0.15 F30000\n G1 X185\n G1 Z1.0\n G0 Y18.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\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 X143.0 Y1.0 Z0.3 F18000.0;Move to first extrude line pos\n\nM400 P100\n\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 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \n M963 S1 \n M400 P1500 \n M964 \n T1100 \n G0 F6000 X40.000 Y54.500 Z0.000 \n M960 S0 P1\n M973 S1\n M400 P800\n M971 S6 P0\n M973 S2 P16000\n M400 P500 \n G0 Z0.000 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P1 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P200 \n M971 S5 P3 \n G0 Z0.500 F12000\n M960 S0 P0\n M960 S1 P1 \n G0 Y37.50 \n M400 P200\n M971 S5 P2 \n M960 S0 P0\n M960 S2 P1 \n G0 Y54.50 \n M400 P500 \n M971 S5 P4 \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_layer[initial_extruder]} ; rise nozzle temp now ,to reduce temp waiting time.\n\n T1100 \n M400 P400 \n M960 S0 P0\n G0 F30000.000 Y22.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.010 K0.020\n M400 P100 \n G0 F20000\n G0 Z1 ; rise nozzle up\n T1000 ; change to nozzle space\n G0 X45.000 Y16.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 Y16.000 F30000 E0\n M109 S{nozzle_temperature_initial_layer[initial_extruder]} \n G0 Z0.3\n G1 F1500.000 E3.600 \n G1 X65.000 E2.4945 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60}\n G1 X70.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X75.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X80.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X85.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X90.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X95.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X100.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X105.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X110.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X115.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X120.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X125.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X130.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X135.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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.01 M{outer_wall_volumetric_speed/(1.75*1.75/4*3.14) *0.01}\n M623 \n\n G1 X140.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X145.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X150.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X155.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X160.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X165.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X170.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X175.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X180.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X185.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X190.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X195.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X200.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X205.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X210.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X215.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 60} \n G1 X220.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) / 4 * 60} \n G1 X225.000 E0.6236 F{outer_wall_volumetric_speed/(0.3*1.0) * 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 X128.0 Y253.0 Z0.2 F6000.0;Move to start position\nM109 S{nozzle_temperature_initial_layer[initial_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" } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json index 3c83beb495..d07b2f8e63 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1 Carbon.json @@ -9,5 +9,5 @@ "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", "hotend_model": "bbl-3dp-hotend.stl", - "default_materials": "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;" + "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;" } diff --git a/resources/profiles/BBL/machine/Bambu Lab X1.json b/resources/profiles/BBL/machine/Bambu Lab X1.json index 8c8eadbc85..bb36dcb722 100644 --- a/resources/profiles/BBL/machine/Bambu Lab X1.json +++ b/resources/profiles/BBL/machine/Bambu Lab X1.json @@ -9,5 +9,5 @@ "bed_model": "bbl-3dp-X1.stl", "bed_texture": "bbl-3dp-logo.svg", "hotend_model": "bbl-3dp-hotend.stl", - "default_materials": "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;" + "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;" } diff --git a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json index 2ffd970079..e2723d163f 100644 --- a/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json +++ b/resources/profiles/BBL/machine/fdm_bbl_3dp_001_common.json @@ -93,8 +93,8 @@ "9" ], "machine_max_jerk_z": [ - "0.2", - "0.4" + "3", + "3" ], "machine_min_extruding_rate": [ "0", @@ -115,7 +115,7 @@ "extruder_clearance_max_radius": "68", "extruder_clearance_height_to_rod": "36", "extruder_clearance_height_to_lid": "90", - "nozzle_volume": "118", + "nozzle_volume": "107", "nozzle_diameter": [ "0.4" ], @@ -155,8 +155,8 @@ "nozzle_type": "hardened_steel", "silent_mode": "0", "single_extruder_multi_material": "1", - "change_filament_gcode": "M620 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\nG1 X70 F12000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\n{if old_filament_temp > 0 && next_extruder < 255}M109 S[old_filament_temp]{endif}\nG1 X90 F3000\nG1 Y250 F4000\nG1 X100 F5000\nG1 X120 F12000\n\nG1 X20 Y50 F12000\nG1 Y-3\n\nT[next_extruder]\n\n; always use highest temperature to flush\nM400\nM109 S[nozzle_temperature_range_high]\n\n{if next_extruder < 255}\nG1 X54 F12000\nG1 Y265\n\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\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\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\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\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\nM400\nM109 S[new_filament_temp]\n\nM400\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\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[z_after_toolchange] 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", - "layer_change_gcode": "{if timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG1 X65 Y245 F12000 ; move to safe pos\nG1 Y265 F3000\nM400 P100\nM971 S11 C10 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255\n{elsif timelapse_type == 2} ; timelapse without wipe tower\nM971 S11 C10 O0\n{endif}", + "change_filament_gcode": "M620 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\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}M104 S[old_filament_temp]{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\nM620.1 X F21000\nT[next_extruder]\nM620.1 E F{new_filament_e_feedrate}\n; always use highest temperature to flush\nM400\nM109 S[nozzle_temperature_range_high]\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\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\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\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\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[z_after_toolchange] 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", + "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 F10000 ; spiral lift a little\nG1 X65 Y245 F12000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F10000\nG1 Y265 F3000\nM400 P100\nM971 S11 C10 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255\n{endif}\nM623", "machine_pause_gcode": "M400 U1\n", "wipe": [ "1" diff --git a/resources/profiles/BBL/machine/fdm_machine_common.json b/resources/profiles/BBL/machine/fdm_machine_common.json index 37891fb1a5..31c0f357d8 100644 --- a/resources/profiles/BBL/machine/fdm_machine_common.json +++ b/resources/profiles/BBL/machine/fdm_machine_common.json @@ -55,7 +55,7 @@ "8" ], "machine_max_jerk_z": [ - "0.4" + "3" ], "machine_min_extruding_rate": [ "0" diff --git a/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json b/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json new file mode 100644 index 0000000000..2635ae9807 --- /dev/null +++ b/resources/profiles/BBL/process/0.10mm Standard @BBL P1P 0.2 nozzle.json @@ -0,0 +1,12 @@ +{ + "type": "process", + "setting_id": "GP014", + "name": "0.10mm Standard @BBL P1P 0.2 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_bbl_0.10_nozzle_0.2", + "elefant_foot_compensation": "0.15", + "compatible_printers": [ + "Bambu Lab P1P 0.2 nozzle" + ] +} diff --git a/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json b/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json new file mode 100644 index 0000000000..c6fdb3e920 --- /dev/null +++ b/resources/profiles/BBL/process/0.20mm Standard @BBL P1P.json @@ -0,0 +1,12 @@ +{ + "type": "process", + "setting_id": "GP015", + "name": "0.20mm Standard @BBL P1P", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_bbl_0.20", + "elefant_foot_compensation": "0.15", + "compatible_printers": [ + "Bambu Lab P1P 0.4 nozzle" + ] +} diff --git a/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json b/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json new file mode 100644 index 0000000000..c8fe887079 --- /dev/null +++ b/resources/profiles/BBL/process/0.20mm Strength @BBL X1C.json @@ -0,0 +1,15 @@ +{ + "type": "process", + "setting_id": "GP013", + "name": "0.20mm Strength @BBL X1C", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_bbl_0.20", + "outer_wall_speed": "60", + "wall_loops": "6", + "sparse_infill_density": "25%", + "compatible_printers": [ + "Bambu Lab X1 Carbon 0.4 nozzle", + "Bambu Lab X1 0.4 nozzle" + ] +} diff --git a/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json b/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json new file mode 100644 index 0000000000..0d2edb4f22 --- /dev/null +++ b/resources/profiles/BBL/process/0.30mm Standard @BBL P1P 0.6 nozzle.json @@ -0,0 +1,12 @@ +{ + "type": "process", + "setting_id": "GP016", + "name": "0.30mm Standard @BBL P1P 0.6 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_bbl_0.30_nozzle_0.6", + "elefant_foot_compensation": "0.15", + "compatible_printers": [ + "Bambu Lab P1P 0.6 nozzle" + ] +} diff --git a/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json b/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json new file mode 100644 index 0000000000..9f47ebfd53 --- /dev/null +++ b/resources/profiles/BBL/process/0.40mm Standard @BBL P1P 0.8 nozzle.json @@ -0,0 +1,12 @@ +{ + "type": "process", + "setting_id": "GP017", + "name": "0.40mm Standard @BBL P1P 0.8 nozzle", + "from": "system", + "instantiation": "true", + "inherits": "fdm_process_bbl_0.40_nozzle_0.8", + "elefant_foot_compensation": "0.15", + "compatible_printers": [ + "Bambu Lab P1P 0.8 nozzle" + ] +} diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.08.json b/resources/profiles/BBL/process/fdm_process_bbl_0.08.json index d6068a71d2..146295708c 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.08.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.08.json @@ -5,6 +5,7 @@ "instantiation": "false", "inherits": "fdm_process_bbl_common", "layer_height": "0.08", + "elefant_foot_compensation": "0.15", "bottom_shell_layers": "7", "top_shell_layers": "9", "bridge_flow": "1", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_0.12.json b/resources/profiles/BBL/process/fdm_process_bbl_0.12.json index c515f84758..453f58276c 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.12.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.12.json @@ -6,7 +6,9 @@ "inherits": "fdm_process_bbl_common", "layer_height": "0.12", "bottom_shell_layers": "5", - "top_shell_layers": "6", + "elefant_foot_compensation": "0.15", + "top_shell_layers": "5", + "top_shell_thickness": "0.6", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", 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 56c8afe843..08513bb82a 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.16.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.16.json @@ -5,8 +5,10 @@ "instantiation": "false", "inherits": "fdm_process_bbl_common", "layer_height": "0.16", + "elefant_foot_compensation": "0.15", "bottom_shell_layers": "4", - "top_shell_layers": "5", + "top_shell_layers": "4", + "top_shell_thickness": "0.6", "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 7b9336c4e5..66d7dc51af 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.20.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.20.json @@ -5,8 +5,10 @@ "instantiation": "false", "inherits": "fdm_process_bbl_common", "layer_height": "0.2", + "elefant_foot_compensation": "0.15", "bottom_shell_layers": "3", - "top_shell_layers": "4", + "top_shell_layers": "3", + "top_shell_thickness": "0.6", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", 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 87c7bf5a3c..159410e756 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.24.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.24.json @@ -5,9 +5,11 @@ "instantiation": "false", "inherits": "fdm_process_bbl_common", "layer_height": "0.24", + "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", "bottom_shell_layers": "3", - "top_shell_layers": "4", + "top_shell_layers": "3", + "top_shell_thickness": "0.6", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", 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 f773eaa4c6..22438e7098 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_0.28.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_0.28.json @@ -5,9 +5,11 @@ "instantiation": "false", "inherits": "fdm_process_bbl_common", "layer_height": "0.28", + "elefant_foot_compensation": "0.15", "top_surface_line_width": "0.45", "bottom_shell_layers": "3", - "top_shell_layers": "4", + "top_shell_layers": "3", + "top_shell_thickness": "0.6", "bridge_flow": "1", "initial_layer_speed": "50", "initial_layer_infill_speed": "105", diff --git a/resources/profiles/BBL/process/fdm_process_bbl_common.json b/resources/profiles/BBL/process/fdm_process_bbl_common.json index a14a39b4a4..091181418c 100644 --- a/resources/profiles/BBL/process/fdm_process_bbl_common.json +++ b/resources/profiles/BBL/process/fdm_process_bbl_common.json @@ -24,11 +24,13 @@ "enable_arc_fitting": "1", "outer_wall_line_width": "0.42", "outer_wall_speed": "120", + "outer_wall_acceleration": "5000", "wall_infill_order": "inner wall/outer wall/infill", "line_width": "0.42", "infill_direction": "45", "sparse_infill_density": "15%", "sparse_infill_pattern": "grid", + "internal_bridge_support_thickness": "0.8", "initial_layer_acceleration": "500", "initial_layer_line_width": "0.5", "initial_layer_print_height": "0.2", @@ -36,7 +38,7 @@ "gap_infill_speed": "50", "infill_combination": "0", "sparse_infill_line_width": "0.45", - "infill_wall_overlap": "25%", + "infill_wall_overlap": "15%", "sparse_infill_speed": "250", "interface_shells": "0", "ironing_flow": "10%", @@ -72,6 +74,7 @@ "support_type": "normal(auto)", "support_on_build_plate_only": "0", "support_top_z_distance": "0.2", + "support_bottom_z_distance": "0.2", "support_filament": "0", "support_line_width": "0.42", "support_interface_loop_pattern": "0", @@ -79,15 +82,16 @@ "support_interface_top_layers": "2", "support_interface_bottom_layers": "2", "support_interface_spacing": "0.5", + "support_expansion": "0", "support_interface_speed": "80", - "support_base_pattern": "rectilinear", + "support_base_pattern": "default", "support_base_pattern_spacing": "2.5", "support_speed": "150", "support_threshold_angle": "30", "support_object_xy_distance": "0.35", - "tree_support_branch_angle": "30", + "tree_support_branch_diameter": "2", + "tree_support_branch_angle": "45", "tree_support_wall_count": "0", - "tree_support_with_infill": "0", "detect_thin_wall": "0", "top_surface_pattern": "monotonicline", "top_surface_line_width": "0.42", diff --git a/resources/profiles/BBL/process/fdm_process_common.json b/resources/profiles/BBL/process/fdm_process_common.json index 0343476333..0177d23c6f 100644 --- a/resources/profiles/BBL/process/fdm_process_common.json +++ b/resources/profiles/BBL/process/fdm_process_common.json @@ -25,7 +25,7 @@ "gap_infill_speed": "30", "infill_combination": "0", "sparse_infill_line_width": "0.45", - "infill_wall_overlap": "25%", + "infill_wall_overlap": "15%", "sparse_infill_speed": "50", "interface_shells": "0", "detect_overhang_wall": "0", @@ -54,12 +54,12 @@ "support_interface_top_layers": "2", "support_interface_spacing": "0", "support_interface_speed": "80", - "support_base_pattern": "rectilinear", + "support_interface_pattern": "auto", + "support_base_pattern": "default", "support_base_pattern_spacing": "2", "support_speed": "40", "support_threshold_angle": "40", "support_object_xy_distance": "0.5", - "tree_support_with_infill": "1", "detect_thin_wall": "0", "top_surface_line_width": "0.42", "top_surface_speed": "30", diff --git a/resources/profiles/Creality.json b/resources/profiles/Creality.json index 23b372e27c..b85402ad38 100644 --- a/resources/profiles/Creality.json +++ b/resources/profiles/Creality.json @@ -1,6 +1,6 @@ { "name": "Creality", - "version": "01.02.01.04", + "version": "01.04.00.00", "force_update": "0", "description": "Creality configurations", "machine_model_list": [ diff --git a/resources/profiles/Creality/process/fdm_process_common.json b/resources/profiles/Creality/process/fdm_process_common.json index 2f46423f61..cb3d7351b1 100644 --- a/resources/profiles/Creality/process/fdm_process_common.json +++ b/resources/profiles/Creality/process/fdm_process_common.json @@ -59,7 +59,6 @@ "support_speed": "40", "support_threshold_angle": "40", "support_object_xy_distance": "0.5", - "tree_support_with_infill": "1", "detect_thin_wall": "0", "top_surface_line_width": "0.4", "top_surface_speed": "30", diff --git a/resources/profiles/Creality/process/fdm_process_creality_common.json b/resources/profiles/Creality/process/fdm_process_creality_common.json index e7bc58b7ee..5b900ab1bb 100644 --- a/resources/profiles/Creality/process/fdm_process_creality_common.json +++ b/resources/profiles/Creality/process/fdm_process_creality_common.json @@ -77,9 +77,8 @@ "support_speed": "150", "support_threshold_angle": "30", "support_object_xy_distance": "0.35", - "tree_support_branch_angle": "30", + "tree_support_branch_angle": "45", "tree_support_wall_count": "0", - "tree_support_with_infill": "0", "detect_thin_wall": "0", "top_surface_pattern": "monotonic", "top_surface_line_width": "0.4", diff --git a/resources/profiles/Voron.json b/resources/profiles/Voron.json index 9dfdf76794..dbf3d91518 100644 --- a/resources/profiles/Voron.json +++ b/resources/profiles/Voron.json @@ -1,6 +1,6 @@ { "name": "Voron", - "version": "01.02.01.06", + "version": "01.04.00.00", "force_update": "0", "description": "Voron configurations", "machine_model_list": [ diff --git a/resources/profiles/Voron/process/fdm_process_common.json b/resources/profiles/Voron/process/fdm_process_common.json index 2f46423f61..cb3d7351b1 100644 --- a/resources/profiles/Voron/process/fdm_process_common.json +++ b/resources/profiles/Voron/process/fdm_process_common.json @@ -59,7 +59,6 @@ "support_speed": "40", "support_threshold_angle": "40", "support_object_xy_distance": "0.5", - "tree_support_with_infill": "1", "detect_thin_wall": "0", "top_surface_line_width": "0.4", "top_surface_speed": "30", diff --git a/resources/profiles/Voron/process/fdm_process_voron_common.json b/resources/profiles/Voron/process/fdm_process_voron_common.json index d29395944a..1741223c02 100644 --- a/resources/profiles/Voron/process/fdm_process_voron_common.json +++ b/resources/profiles/Voron/process/fdm_process_voron_common.json @@ -80,9 +80,8 @@ "support_speed": "150", "support_threshold_angle": "30", "support_object_xy_distance": "0.35", - "tree_support_branch_angle": "30", + "tree_support_branch_angle": "45", "tree_support_wall_count": "0", - "tree_support_with_infill": "0", "detect_thin_wall": "0", "top_surface_pattern": "monotonicline", "top_surface_line_width": "0.4", diff --git a/resources/shaders/mm_gouraud_wireframe.fs b/resources/shaders/mm_gouraud_wireframe.fs new file mode 100644 index 0000000000..c10b0fd099 --- /dev/null +++ b/resources/shaders/mm_gouraud_wireframe.fs @@ -0,0 +1,107 @@ +#version 110 + +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const float EPSILON = 0.0001; +//BBS: add grey and orange +//const vec3 GREY = vec3(0.9, 0.9, 0.9); +const vec3 ORANGE = vec3(0.8, 0.4, 0.0); + +uniform vec4 uniform_color; + +varying vec3 clipping_planes_dots; +varying vec4 model_pos; + +uniform bool volume_mirrored; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; + +//BBS: add wireframe logic +varying vec3 barycentric_coordinates; +float edgeFactor(float lineWidth) { + vec3 d = fwidth(barycentric_coordinates); + vec3 a3 = smoothstep(vec3(0.0), d * lineWidth, barycentric_coordinates); + return min(min(a3.x, a3.y), a3.z); +} + +vec3 wireframe(vec3 fill, vec3 stroke, float lineWidth) { + return mix(stroke, fill, edgeFactor(lineWidth)); + //if (any(lessThan(barycentric_coordinates, vec3(0.005, 0.005, 0.005)))) + // return vec3(1.0, 0.0, 0.0); + //else + // return fill; +} + +vec3 getWireframeColor(vec3 fill) { + float brightness = 0.2126 * fill.r + 0.7152 * fill.g + 0.0722 * fill.b; + return (brightness > 0.75) ? vec3(0.11, 0.165, 0.208) : vec3(0.988, 0.988, 0.988); +} +uniform bool show_wireframe; + +void main() +{ + if (any(lessThan(clipping_planes_dots, ZERO))) + discard; + vec3 color = uniform_color.rgb; + float alpha = uniform_color.a; + + vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz))); +#ifdef FLIP_TRIANGLE_NORMALS + triangle_normal = -triangle_normal; +#endif + + vec3 transformed_normal = normalize(slope.volume_world_normal_matrix * triangle_normal); + if (slope.actived && transformed_normal.z < slope.normal_z - EPSILON) { + //color = vec3(0.7, 0.7, 1.0); + color = color * 0.5 + ORANGE * 0.5; + alpha = 1.0; + } + + if (volume_mirrored) + triangle_normal = -triangle_normal; + + // First transform the normal into camera space and normalize the result. + vec3 eye_normal = normalize(gl_NormalMatrix * triangle_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + + // x = diffuse, y = specular; + vec2 intensity = vec2(0.0, 0.0); + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * model_pos).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + + if (show_wireframe) { + vec3 wireframeColor = show_wireframe ? getWireframeColor(color) : color; + vec3 triangleColor = wireframe(color, wireframeColor, 1.0); + gl_FragColor = vec4(vec3(intensity.y) + triangleColor * intensity.x, alpha); + } + else { + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + } +} diff --git a/resources/shaders/mm_gouraud_wireframe.vs b/resources/shaders/mm_gouraud_wireframe.vs new file mode 100644 index 0000000000..f81da2f348 --- /dev/null +++ b/resources/shaders/mm_gouraud_wireframe.vs @@ -0,0 +1,43 @@ +#version 110 + +const vec3 ZERO = vec3(0.0, 0.0, 0.0); + +attribute vec3 v_position; +attribute vec3 v_barycentric; + +uniform mat4 volume_world_matrix; +// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. +uniform vec2 z_range; +// Clipping plane - general orientation. Used by the SLA gizmo. +uniform vec4 clipping_plane; + +varying vec3 clipping_planes_dots; +varying vec4 model_pos; + +varying vec3 barycentric_coordinates; + +struct SlopeDetection +{ + bool actived; + float normal_z; + mat3 volume_world_normal_matrix; +}; +uniform SlopeDetection slope; +void main() +{ + //model_pos = gl_Vertex; + model_pos = vec4(v_position, 1.0); + // Point in homogenous coordinates. + //vec4 world_pos = volume_world_matrix * gl_Vertex; + vec4 world_pos = volume_world_matrix * model_pos; + + //gl_Position = ftransform(); + gl_Position = gl_ModelViewProjectionMatrix * vec4(v_position.x, v_position.y, v_position.z, 1.0); + // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. + clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z); + + //compute the Barycentric Coordinates + //int vertexMod3 = gl_VertexID % 3; + //barycentric_coordinates = vec3(float(vertexMod3 == 0), float(vertexMod3 == 1), float(vertexMod3 == 2)); + barycentric_coordinates = v_barycentric; +} diff --git a/resources/web/data/text.js b/resources/web/data/text.js index 9dc76cb738..741b60eecd 100644 --- a/resources/web/data/text.js +++ b/resources/web/data/text.js @@ -30,9 +30,9 @@ var LangText={ "t28":"Recent", "t29":"Mall", "t30":"Manual", - "t31":"New project", + "t31":"New Project", "t32":"Create new project", - "t33":"Open project", + "t33":"Open Project", "t34":"hotspot", "t35":"Recently opened", "t36":"ok", @@ -81,7 +81,10 @@ var LangText={ "t86":"Close", "t87":"User Manual", "t88":"Remove", - "t89":"Open Containing Folder" + "t89":"Open Containing Folder", + "t90":"3D Model", + "t91":"Download 3D models", + "t92":"Bambu Christmas Cabin" }, "zh_CN":{ "t1":"欢迎使用Bambu Studio", @@ -166,6 +169,9 @@ var LangText={ "t87":"使用引导", "t88":"移除", "t89":"打开所在的文件夹", + "t90":"3D 模型", + "t91":"下载3D模型", + "t92":"Bambu圣诞小屋", "wk1":"快速入门指南", "wk2":"本文介绍了Bambu Studio的最基本用法。它指导用户配置软件,创建项目,并逐步完成第一个打印任务。", "wk3":"基于项目的工作流", diff --git a/resources/web/guide/1/index.html b/resources/web/guide/1/index.html index dea1d22991..8565bf7a8a 100644 --- a/resources/web/guide/1/index.html +++ b/resources/web/guide/1/index.html @@ -4,7 +4,8 @@ 引导_P1 - + + diff --git a/resources/web/guide/11/11.css b/resources/web/guide/11/11.css index caaeddf41e..8ad4bf61fd 100644 --- a/resources/web/guide/11/11.css +++ b/resources/web/guide/11/11.css @@ -5,17 +5,20 @@ flex-direction: column; justify-content:flex-start; align-items:center; + align-content: center; } #EarthIcon img { - width: 160px; + width: 40%; + min-width: 100px; } #EarthIcon { margin-bottom: 20px; + text-align: center; } #RegionList @@ -48,9 +51,10 @@ .RegionSelected:hover { background-color:#00AE42; - color: #fff; + color: #fff; } + #ChangeTip { margin-top: 15px; diff --git a/resources/web/guide/11/index.html b/resources/web/guide/11/index.html index 8581fea091..e503b475f0 100644 --- a/resources/web/guide/11/index.html +++ b/resources/web/guide/11/index.html @@ -4,8 +4,9 @@ 引导_P21 - + + @@ -20,7 +21,7 @@
-
Asia-Pacific
+
Asia-Pacific
China
Europe
North America
diff --git a/resources/web/guide/21/21.css b/resources/web/guide/21/21.css index b779a78cf4..47b09fcbec 100644 --- a/resources/web/guide/21/21.css +++ b/resources/web/guide/21/21.css @@ -4,26 +4,6 @@ overflow-y:auto; } -#Content::-webkit-scrollbar {/*滚动条整体样式*/ - width: 5px; /*高宽分别对应横竖滚动条的尺寸*/ - height: 1px; -} - -#Content::-webkit-scrollbar-thumb {/*滚动条里面小方块*/ - border-radius: 10px; - -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); - box-shadow: inset 0 0 5px rgba(0,0,0,0.2); - background-color: #AAAAAA; -} - -#Content::-webkit-scrollbar-track {/*滚动条里面轨道*/ - -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); - box-shadow: inset 0 0 5px rgba(0,0,0,0.2); - border-radius: 10px; - background: #EDEDED; -} - - .BlockBanner { padding: 0px; @@ -113,9 +93,10 @@ { display: none; width: 400px; - border: 1px solid #000; + border-width: 1px; + border-style: solid; border-radius: 4px; - background-color: #fff; + background-color: inherit; position: absolute; left: 50%; top: 200px; diff --git a/resources/web/guide/21/21.js b/resources/web/guide/21/21.js index fbc32ced38..fc7877892e 100644 --- a/resources/web/guide/21/21.js +++ b/resources/web/guide/21/21.js @@ -89,7 +89,7 @@ function HandleModelList( pVal ) for(let m=0;m'+nNozzel+'mm nozzle
'; + HtmlNozzel+='
'+nNozzel+'mm nozzle
'; } let CoverImage="../../image/printer/"+OneModel['model']+"_cover.png"; diff --git a/resources/web/guide/21/index.html b/resources/web/guide/21/index.html index ad3f685486..b6589ca79a 100644 --- a/resources/web/guide/21/index.html +++ b/resources/web/guide/21/index.html @@ -6,6 +6,7 @@ 引导_P21 + @@ -18,7 +19,7 @@
Printer Selection
-
+
@@ -68,78 +76,120 @@
+
+
+
Christmas Cabin
+
+
+ +
+
+
-
recent open
-
Clear all
+
recent open
+
Clear all
+
+
+ +
+
abcd12334abcd12334abcd12334.3mf
+
2021/12/27 09:22
+
+
+ +
+
abcd12334abcd12334abcd12334.3mf
+
2021/12/27 09:22
+
+
+ +
+
abcd12334abcd12334abcd12334.3mf
+
2021/12/27 09:22
+
-->
@@ -163,44 +213,44 @@
-
Quick Start
+
Quick Start
This article introduces the most basic usage of Bambu Studio. It guides users to configure software, create projects, and complete the first printing task step by step.
-
Project Based Workflow
+
Project Based Workflow
Bambu Studio has put forward a leading workflow to truly achieve an “all in one” project. Based on the mainstream 3MF project format, it provides a series of revolutionary new features, such as Multi-Plate Support, a Project Resource Manager, and Assembly/Part View. It greatly improves the efficiency of both creators and regular users.
-
High Speed Print at Quality
+
High Speed Print at Quality
It is challenging to print at high speed while maintaining high quality. Bambu Studio makes this happen. "Arch Move" makes the toolhead move smoothly and reduces the machine's vibration. The smart cooling is based on fine-tuned cooling parameters for each filament type. "Auto slow down" for overhang walls works to prevent deformation at high speeds.
-
Multi-Color Printing
+
Multi-Color Printing
Bambu Studio provides versatile colorizing tools to make a colorful model. You can freely add/remove filaments in a project and colorize your model with different brushes. Before printing, each filament will be auto-mapped to an AMS slot, not needing to manually change the spool placement in the AMS.
-
Setting Guide of Slicing Parameters
+
Setting Guide of Slicing Parameters
The parameter management features in Bambu Studio provide very flexible and powerful control over the slicing process. This article introduces the organization of parameters and provides some skills on taking full advantage of these capabilities.
-
Remote Control & Monitoring
+
Remote Control & Monitoring
Bambu Studio support sending print job to your printer over WAN/LAN network, controlling & monitoring every aspect of your 3D printer and printing jobs. If you have more than one printer, you can easily switch between them in the device list.
-
STEP Format
+
STEP Format
Compared with STL, STEP brings more effective information. Thanks to the high accuracy of STEP, a lot of extrusion paths can be generated as arcs. STEP also includes the assembly relationship of each part of a model, which can be used to restore the assembly view after a model is split.
-
3D Text
+
3D Text
With 3D Text tool, users can easily create various 3D text shapes in the project, making the model more personalized. Bambu Studio provides dozens of fonts and supports bold and italic styles to give text greater flexibility.
diff --git a/resources/web/homepage/js/globalapi.js b/resources/web/homepage/js/globalapi.js index 3d56015018..ab7d5e6a20 100644 --- a/resources/web/homepage/js/globalapi.js +++ b/resources/web/homepage/js/globalapi.js @@ -278,3 +278,63 @@ function SendWXMessage( strMsg ) } +/*------CSS Link Control----*/ +function RemoveCssLink( LinkPath ) +{ + let pNow=$("head link[href='"+LinkPath+"']"); + + let nTotal=pNow.length; + for( let n=0;n0) + RemoveCssLink(DarkCssPath); + } + else + { + if(nNow==0) + AddCssLink(DarkCssPath); + } +} + +SwitchDarkMode("css/dark.css"); \ No newline at end of file diff --git a/resources/web/homepage/js/home.js b/resources/web/homepage/js/home.js index d88c07d927..c96006fc0b 100644 --- a/resources/web/homepage/js/home.js +++ b/resources/web/homepage/js/home.js @@ -12,6 +12,9 @@ function OnInit() SendMsg_GetLoginInfo(); SendMsg_GetRecentFile(); + + //-----Christmas----- + ShowCabin(); } //------最佳打开文件的右键菜单功能---------- @@ -22,7 +25,7 @@ var MousePosY=0; function Set_RecentFile_MouseRightBtn_Event() { - $(".FileItem").mousedown( + $("#FileList .FileItem").mousedown( function(e) { //FilePath @@ -117,7 +120,7 @@ function HandleStudio( pVal ) { $("#NoPluginTip").hide(); } - } + } } function GotoMenu( strMenu ) @@ -188,7 +191,7 @@ function ShowRecentFileList( pList ) let TmpHtml='
'+ ''+ '
No Image
'+ - ''+sName+''+ + '
'+sName+'
'+ '
'+sTime+'
'+ '
'; @@ -203,6 +206,7 @@ function ShowRecentFileList( pList ) function ShowRecnetFileContextMenu() { + $("#recnet_context_menu").offset({top: 10000, left:-10000}); $('#recnet_context_menu').show(); let ContextMenuWidth=$('#recnet_context_menu').width(); @@ -214,10 +218,10 @@ function ShowRecnetFileContextMenu() let RealX=MousePosX; let RealY=MousePosY; - if( MousePosX + ContextMenuWidth >DocumentWidth ) - RealX=MousePosX-ContextMenuWidth; - if( MousePosY+ContextMenuHeight>DocumentHeight ) - RealY=MousePosY-ContextMenuHeight; + if( MousePosX + ContextMenuWidth + 24 >DocumentWidth ) + RealX=DocumentWidth-ContextMenuWidth-24; + if( MousePosY+ContextMenuHeight+24>DocumentHeight ) + RealY=DocumentHeight-ContextMenuHeight-24; $("#recnet_context_menu").offset({top: RealY, left:RealX}); } @@ -252,6 +256,14 @@ function OnLoginOrRegister() SendWXMessage( JSON.stringify(tSend) ); } +function OnClickModelDepot() +{ + var tSend={}; + tSend['sequence_id']=Math.round(new Date() / 1000); + tSend['command']="homepage_modeldepot"; + + SendWXMessage( JSON.stringify(tSend) ); +} function OnClickNewProject() { @@ -392,3 +404,61 @@ function OpenWikiUrl( strUrl ) //---------------Global----------------- window.postMessage = HandleStudio; + + +//---------------Christma cabin +var CCabin={ + "model":[ + { + "name":"Bambu Christmas Cabin", + "icon":"christmas_cabin.png", + "file":"Bambu Christmas Cabin.3mf" + } + ] +}; + +function ShowCabin() +{ + let nCabin=CCabin.model.length; + + if(nCabin==0) + { + $('#CabinList').html(''); + + $('#ChristmasArea').hide(); + return; + } + + let strHtml=''; + for(let m=0;m'+ + '
'+ + '
'+OneCabin.name+'
'+ + '
'; + + strHtml+=OneHtml; + } + + $('#CabinList').html(strHtml); + + $('#ChristmasArea').show(); + $('#ChristmasArea').css('display','flex'); +} + +function OnOpenCabin( cabinfile ) +{ + //alert(cabinfile); + + var tSend={}; + tSend['sequence_id']=Math.round(new Date() / 1000); + tSend['command']="homepage_open_ccabin"; + tSend['data']={}; + tSend['data']['file']=cabinfile; + + SendWXMessage( JSON.stringify(tSend) ); +} + + diff --git a/resources/web/homepage/model/Bambu Christmas Cabin.3mf b/resources/web/homepage/model/Bambu Christmas Cabin.3mf new file mode 100644 index 0000000000..aef4533f3c Binary files /dev/null and b/resources/web/homepage/model/Bambu Christmas Cabin.3mf differ diff --git a/resources/web/homepage/model/christmas_cabin.png b/resources/web/homepage/model/christmas_cabin.png new file mode 100644 index 0000000000..a95a462cd9 Binary files /dev/null and b/resources/web/homepage/model/christmas_cabin.png differ diff --git a/resources/web/image/printer/Bambu Lab P1P_cover.png b/resources/web/image/printer/Bambu Lab P1P_cover.png new file mode 100644 index 0000000000..566ce21456 Binary files /dev/null and b/resources/web/image/printer/Bambu Lab P1P_cover.png differ diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 368797dae2..d372346e29 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -22,6 +22,17 @@ #include #include #include + +#if defined(__linux__) || defined(__LINUX__) +#include +#include +#include +//add json logic +#include "nlohmann/json.hpp" + +using namespace nlohmann; +#endif + #include #include #include @@ -75,6 +86,217 @@ using namespace Slic3r; +/*typedef struct _error_message{ + int code; + std::string message; +}error_message;*/ + + +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"} +}; + +#if defined(__linux__) || defined(__LINUX__) +#define PIPE_BUFFER_SIZE 512 + +typedef struct _cli_callback_mgr { + int m_plate_count {0}; + int m_plate_index {0}; + int m_progress { 0 }; + int m_total_progress { 0 }; + std::string m_message; + int m_warning_step; + bool m_exit {false}; + bool m_data_ready {false}; + bool m_started {false}; + boost::thread m_thread; + // Mutex and condition variable to synchronize m_thread with the UI thread. + std::mutex m_mutex; + std::condition_variable m_condition; + int m_pipe_fd{-1}; + + bool is_started() + { + bool result; + std::unique_lock lck(m_mutex); + result = m_started; + lck.unlock(); + + return result; + } + + void set_plate_info(int index, int count) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": index="<= 0) + j["warning"] = m_message; + else + j["message"] = m_message; + + std::string notify_message = j.dump(); + //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()); + + int ret = write(m_pipe_fd, pipe_message, strlen(pipe_message)); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": write returns "< lck(m_mutex); + m_started = true; + m_data_ready = false; + lck.unlock(); + m_condition.notify_one(); + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc started."; + while(1) { + lck.lock(); + m_condition.wait(lck, [this](){ return m_data_ready || m_exit; }); + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": wakup."; + if (m_data_ready) { + notify(); + m_data_ready = false; + } + if (m_exit) { + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc will exit."; + break; + } + lck.unlock(); + m_condition.notify_one(); + } + lck.unlock(); + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::thread_proc exit."; + } + + void update(int percent, std::string message, int warning_step) + { + std::unique_lock lck(m_mutex); + if (!m_started) { + lck.unlock(); + return; + } + + if ((m_progress >= percent)&&(warning_step == -1)) { + //already update before + lck.unlock(); + return; + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": percent="< lck(m_mutex); + m_thread = create_thread([this]{ + this->thread_proc(); + }); + lck.unlock(); + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::start successfully."; + return true; + } + + void stop() + { + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop enter."; + std::unique_lock lck(m_mutex); + if (!m_started) { + lck.unlock(); + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop not started before, return directly."; + return; + } + m_exit = true; + lck.unlock(); + m_condition.notify_one(); + // Wait until the worker thread exits. + m_thread.join(); + if (m_pipe_fd > 0) { + close(m_pipe_fd); + m_pipe_fd = -1; + } + BOOST_LOG_TRIVIAL(info) << "cli_callback_mgr_t::stop successfully."; + } +}cli_callback_mgr_t; + +cli_callback_mgr_t g_cli_callback_mgr; + +void cli_status_callback(const PrintBase::SlicingStatus& slicing_status) +{ + g_cli_callback_mgr.update(slicing_status.percent, slicing_status.text, slicing_status.warning_step); + return; +} +#endif + static PrinterTechnology get_printer_technology(const DynamicConfig &config) { const ConfigOptionEnum *opt = config.option>("printer_technology"); @@ -82,10 +304,18 @@ static PrinterTechnology get_printer_technology(const DynamicConfig &config) } //BBS: add flush and exit +#if defined(__linux__) || defined(__LINUX__) +#define flush_and_exit(ret) { boost::nowide::cout << __FUNCTION__ << " found error, return "<setup(debug_argc, debug_argv))*/ if (!this->setup(argc, argv)) { boost::nowide::cerr << "setup params error" << std::endl; - return 1; + return CLI_INVALID_PARAMS; } BOOST_LOG_TRIVIAL(info) << "finished setup params, argc="<< argc << std::endl; std::string temp_path = wxFileName::GetTempDir().utf8_str().data(); @@ -222,211 +452,41 @@ int CLI::run(int argc, char **argv) #endif // SLIC3R_GUI } - BOOST_LOG_TRIVIAL(info) << "before load settings, file count="<< load_configs.size() << std::endl; - // load config files supplied via --load - for (auto const &file : load_configs) { - if (! boost::filesystem::exists(file)) { - boost::nowide::cerr << "can not find setting file: " << file << std::endl; - flush_and_exit(1); - } - DynamicPrintConfig config; - ConfigSubstitutions config_substitutions; - try { - BOOST_LOG_TRIVIAL(info) << "load setting file "<< file << ", with rule "<< config_substitution_rule << std::endl; - std::map key_values; - std::string reason; - - config_substitutions = config.load_from_json(file, config_substitution_rule, key_values, reason); - if (!reason.empty()) { - BOOST_LOG_TRIVIAL(error) << "Can not load config from file "<serialize() << std::endl; - } catch (std::exception &ex) { - boost::nowide::cerr << "Loading setting file \"" << file << "\" failed: " << ex.what() << std::endl; - flush_and_exit(1); - } - if (! config_substitutions.empty()) { - BOOST_LOG_TRIVIAL(info) << "Found legacy configuration values, substituted when loading " << file << ":\n"; - for (const ConfigSubstitution &subst : config_substitutions) - BOOST_LOG_TRIVIAL(info) << "\tkey = \"" << subst.opt_def->opt_key << "\"\t old_value = \"" << subst.old_value << "\tnew_value = \"" << subst.new_value->serialize() << "\"\n"; - } - else { - BOOST_LOG_TRIVIAL(info) << "no substitutions performed from file " << file << "\n"; - } - config.normalize_fdm(); - 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 " < key_values; - try { - BOOST_LOG_TRIVIAL(info) << "load filament file "<< file << ", with rule "<< config_substitution_rule << std::endl; - std::string reason; - config_substitutions = config.load_from_json(file, config_substitution_rule, key_values, reason); - if (!reason.empty()) { - BOOST_LOG_TRIVIAL(error) << "Can not load filament config from file "<serialize() << std::endl; - } catch (std::exception &ex) { - boost::nowide::cerr << "Loading filament file \"" << file << "\" failed: " << ex.what() << std::endl; - flush_and_exit(1); - } - if (! config_substitutions.empty()) { - BOOST_LOG_TRIVIAL(info) << "Found legacy configuration values, substituted when loading " << file << ":\n"; - for (const ConfigSubstitution &subst : config_substitutions) - BOOST_LOG_TRIVIAL(info) << "\tkey = \"" << subst.opt_def->opt_key << "\"\t old_value = \"" << subst.old_value << "\tnew_value = \"" << subst.new_value->serialize() << "\"\n"; - } - else { - BOOST_LOG_TRIVIAL(info) << "no substitutions performed from file " << file << "\n"; - } - config.normalize_fdm(); - 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 " < (m_print_config.option("filament_settings_id", true)); - ConfigOptionStrings *opt_filament_settings_src = static_cast(config.option("filament_settings_id", false)); - if (opt_filament_settings_src) - opt_filament_settings->set_at(opt_filament_settings_src, index, 0); - else { - std::string name = file; - name.erase(name.size() - 5); - ConfigOptionString option(name); - opt_filament_settings->set_at(&option, index, 0); - } - std::string filament_id; - ConfigOptionStrings *opt_filament_ids = static_cast (m_print_config.option("filament_ids", true)); - auto filament_id_iter = key_values.find(BBL_JSON_KEY_FILAMENT_ID); - if (filament_id_iter != key_values.end()) - filament_id = filament_id_iter->second; - ConfigOptionString* filament_id_setting = new ConfigOptionString(filament_id); - if (opt_filament_ids->size() < filament_count) - opt_filament_ids->resize(filament_count, filament_id_setting); - opt_filament_ids->set_at(filament_id_setting, index, 0); - //parse the filament value to index th - //loop through options and apply them - for (const t_config_option_key &opt_key : config.keys()) { - // 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, - // an exception is thrown if not ignore_nonexistent. - - const ConfigOption *source_opt = config.option(opt_key); - if (source_opt == nullptr) { - // The key was not found in the source config, therefore it will not be initialized! - boost::nowide::cerr << "can not found option " <is_scalar()) { - if (opt_key == "compatible_printers_condition") { - ConfigOption *opt = m_print_config.option("compatible_machine_expression_group", true); - ConfigOptionStrings* opt_vec_dst = static_cast(opt); - if (opt_vec_dst->size() == 0) - opt_vec_dst->resize(1, new ConfigOptionString()); - opt_vec_dst->set_at(source_opt, index+1, 0); - } - else if (opt_key == "compatible_prints_condition") { - ConfigOption *opt = m_print_config.option("compatible_process_expression_group", true); - ConfigOptionStrings* opt_vec_dst = static_cast(opt); - if (opt_vec_dst->size() == 0) - opt_vec_dst->resize(1, new ConfigOptionString()); - opt_vec_dst->set_at(source_opt, index, 0); - } - else { - //skip the scalar values - BOOST_LOG_TRIVIAL(info) << "skip scalar option " <def(). - // This is only possible if other is of DynamicConfig type. - boost::nowide::cerr << "can not create option " <(opt); - const ConfigOptionVectorBase* opt_vec_src = static_cast(source_opt); - if (opt_key == "bed_temperature" || opt_key == "bed_temperature_initial_layer") { - const ConfigOptionInts* bed_temp_opt = dynamic_cast(opt_vec_src); - for (size_t type = 0; type < (size_t)BedType::btCount; type++) { - if (type < bed_temp_opt->size()) - opt_vec_dst->set_at(bed_temp_opt, index * BedType::btCount + type, type); - else - // BBS FIXME: set bed temperature to 0 for new bed types - opt_vec_dst->set_at(new ConfigOptionInt(0), index * BedType::btCount + type, type); - } - } - else if (opt_key == "compatible_prints" || opt_key == "compatible_printers") - continue; - else { - opt_vec_dst->set_at(opt_vec_src, index, 0); - } - } - } - } - - // are we starting as gcodeviewer ? - /*for (auto it = m_actions.begin(); it != m_actions.end(); ++it) { - if (*it == "gcodeviewer") { - start_gui = true; - start_as_gcodeviewer = true; - m_actions.erase(it); - break; - } - }*/ - BOOST_LOG_TRIVIAL(info) << "start_gui="<< start_gui << std::endl; //BBS: add plate data related logic - PlateDataPtrs plate_data; + PlateDataPtrs plate_data_src; int arrange_option; - bool first_file = true, is_bbl_3mf = false, need_arrange = true; + 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; 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::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; // Read input file(s) if any. BOOST_LOG_TRIVIAL(info) << "Will start to read model file now, file count :" << m_input_files.size() << "\n"; + ConfigOptionInt* slice_option = m_config.option("slice"); + if (slice_option) + plate_to_slice = slice_option->value; + ConfigOptionBool* uptodate_option = m_config.option("uptodate"); + if (uptodate_option) + up_config_to_date = uptodate_option->value; /*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) << "plate_to_slice="<< plate_to_slice << std::endl; //if (!start_as_gcodeviewer) { for (const std::string& file : m_input_files) { if (!boost::filesystem::exists(file)) { boost::nowide::cerr << "No such file: " << file << std::endl; - flush_and_exit(1); + flush_and_exit(CLI_FILE_NOTFOUND); } Model model; //BBS: add plate related logic @@ -449,15 +509,15 @@ int CLI::run(int argc, char **argv) // BBS: adjust whebackup //LoadStrategy strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances; //if (load_aux) strategy = strategy | LoadStrategy::LoadAuxiliary; - model = Model::read_from_file(file, &config, &config_substitutions, strategy, &plate_data, &project_presets, &is_bbl_3mf, &file_version); + model = Model::read_from_file(file, &config, &config_substitutions, strategy, &plate_data_src, &project_presets, &is_bbl_3mf, &file_version, nullptr, nullptr, nullptr, nullptr, nullptr, plate_to_slice); if (is_bbl_3mf) { if (!first_file) { BOOST_LOG_TRIVIAL(info) << "The BBL 3mf file should be placed at the first position, filename=" << file << "\n"; - flush_and_exit(1); + flush_and_exit(CLI_FILELIST_INVALID_ORDER); } - BOOST_LOG_TRIVIAL(info) << "the first file is a 3mf, got plate count:" << plate_data.size() << "\n"; + BOOST_LOG_TRIVIAL(info) << "the first file is a 3mf, got plate count:" << plate_data_src.size() << "\n"; need_arrange = false; for (ModelObject* o : model.objects) { @@ -471,6 +531,40 @@ int CLI::run(int argc, char **argv) const Vec3d &instance_offset = model_instance->get_offset(); 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; }*/ + 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; + 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()) + current_printer_system_name = current_printer_name; + else + current_printer_system_name = current_inherits_group[size-1]; + + if (current_inherits_group[0].empty()) + current_process_system_name = current_process_name; + else + current_process_system_name = current_inherits_group[0]; + + current_filaments_system_name.resize(size - 2); + for (int index = 1; index < (size - 1); index++) { + if (current_inherits_group[index].empty()) + current_filaments_system_name[index-1] = current_filaments_name[index-1]; + 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; + } + 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; } else { @@ -490,7 +584,7 @@ int CLI::run(int argc, char **argv) } if ((printer_technology != other_printer_technology) && (other_printer_technology != ptUnknown)) { boost::nowide::cerr << "invalid printer_technology " < key_values; + std::string reason, config_from; + + config_substitutions = config.load_from_json(file, config_substitution_rule, key_values, reason); + if (!reason.empty()) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< ":Can not load config from file "<second; + } + if (config_from != "system") { + boost::nowide::cerr <<__FUNCTION__ << boost::format(":file %1%'s from %2% unsupported") % file % config_from; + return CLI_CONFIG_FILE_ERROR; + } + + auto type_iter = key_values.find(BBL_JSON_KEY_TYPE); + if (type_iter != key_values.end()) { + config_type = type_iter->second; + } + if (config_type == "machine") { + //config.set("printer_settings_id", config_name, true); + //printer_inherits = config.option("inherits", true)->value; + } + else if (config_type == "process") { + //config.set("print_settings_id", config_name, true); + //print_inherits = config.option("inherits", true)->value; + } + else if (config_type == "filament") { + auto filament_id_iter = key_values.find(BBL_JSON_KEY_FILAMENT_ID); + if (filament_id_iter != key_values.end()) + filament_id = filament_id_iter->second; + } + else { + boost::nowide::cerr <<__FUNCTION__ << boost::format(": unknown config type %1% of file %2% in load-settings") % config_type % file; + return CLI_CONFIG_FILE_ERROR; + } + config.normalize_fdm(); + + if (! config_substitutions.empty()) { + BOOST_LOG_TRIVIAL(info) << "Found legacy configuration values, substituted when loading " << file << ":\n"; + for (const ConfigSubstitution &subst : config_substitutions) + BOOST_LOG_TRIVIAL(info) << "\tkey = \"" << subst.opt_def->opt_key << "\"\t old_value = \"" << subst.old_value << "\tnew_value = \"" << subst.new_value->serialize() << "\"\n"; + } + else { + BOOST_LOG_TRIVIAL(info) << "no substitutions performed from file " << file << "\n"; + } + //config.erase("inherits"); + //config.erase("compatible_printers"); + //BOOST_LOG_TRIVIAL(info) << "got printable_area "<< config.option("printable_area")->serialize() << std::endl; + } catch (std::exception &ex) { + boost::nowide::cerr << __FUNCTION__<< ":Loading setting file \"" << file << "\" failed: " << ex.what() << std::endl; + return CLI_CONFIG_FILE_ERROR; + } + return 0; + }; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ":before load settings, file count="<< load_configs.size() << std::endl; + //std::vector filament_compatible_printers; + // 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); + if (ret) { + flush_and_exit(ret); + } + + if (config_type == "machine") { + if (!new_printer_name.empty()) { + boost::nowide::cerr << "duplicate machine config file: " << file << std::endl; + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + new_printer_name = config_name; + config.set("printer_settings_id", new_printer_name, true); + //printer_inherits = config.option("inherits", true)->value; + load_machine_config = std::move(config); + } + else if (config_type == "process") { + if (!new_process_name.empty()) { + boost::nowide::cerr << "duplicate process config file: " << file << std::endl; + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + new_process_name = config_name; + 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); + } + + 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 " < load_filaments_index; + std::vector load_filaments_config; + std::vector load_filaments_id; + std::vector load_filaments_name; + int current_index = 0; + 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); + if (ret) { + 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; + flush_and_exit(CLI_CONFIG_FILE_ERROR); + } + + 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 " <("upward_compatible_machine", true)->values; + config.set("printer_settings_id", config_name, true); + load_machine_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::nowide::cerr << __FUNCTION__<< ": can not find system preset file: " << system_process_path << std::endl; + //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) + 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; + + 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; + } + 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); + + 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); + } + } + } + else if (is_bbl_3mf){ + fetch_upward_values = true; + fetch_compatible_values = true; + } + + //fetch upward_compatible_machine + if (fetch_upward_values) { + if (!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; + //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) + flush_and_exit(ret); + upward_compatible_printers = config.option("upward_compatible_machine", true)->values; + } + } + } + + //fetch print_compatible_printers + if (fetch_compatible_values) { + if (!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 + } + 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; + } + } + } + + //upwards check + bool process_compatible = true, machine_upwards = false; + 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) { + 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; + } + else { + for (int index = 0; index < current_print_compatible_printers.size(); index++) { + if (current_print_compatible_printers[index] == new_printer_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; + } + } + 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) { + 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 && !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) { + 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; + 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."); + flush_and_exit(CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE); + } + } + + if (!process_compatible) { + boost::nowide::cout <<__FUNCTION__ << boost::format(": process not compatible with printer."); + flush_and_exit(CLI_PROCESS_NOT_COMPATIBLE); + } + + //create project embedded preset if needed + Preset *new_preset = NULL; + if (is_bbl_3mf && machine_upwards) { + Preset *current_preset = NULL; + size_t project_presets_count = project_presets.size(); + for (int index = 0; index < project_presets_count; index++) + { + if (project_presets[index]->name == current_process_name) { + current_preset = project_presets[index]; + break; + } + } + new_preset = new Preset(Preset::TYPE_PRINT, current_process_name); + if (current_preset) { + *new_preset = *current_preset; + 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) { + need_insert = false; + break; + } + } + if (need_insert) + compatible_printers.push_back(new_printer_name); + } + else { + //store a project-embedded preset + const std::vector& process_keys = Preset::print_options(); + 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); + if (current_process_system_name != current_process_name) { + std::string& inherits = new_preset->config.option("inherits", true)->value; + inherits = current_process_system_name; + } + new_preset->is_project_embedded = true; + new_preset->type = Preset::TYPE_PRINT; + //new_preset->name = current_process_name; + } + new_preset->name += "(auto)"; + new_preset->config.set("print_settings_id", new_preset->name, true); + m_print_config.set("print_settings_id", new_preset->name, true); + project_presets.push_back(new_preset); + } + + //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 + continue; + } + const ConfigOption *source_opt = config.option(opt_key); + if (source_opt == nullptr) { + // The key was not found in the source config, therefore it will not be initialized! + boost::nowide::cerr << __FUNCTION__<<": can not found option " <set(source_opt); + //*dest_opt = *source_opt; + } + } + return 0; + }; + + std::vector& different_settings = m_print_config.option("different_settings_to_system", true)->values; + std::vector& inherits_group = m_print_config.option("inherits_group", true)->values; + inherits_group.resize(filament_count + 2, std::string()); + different_settings.resize(filament_count + 2, std::string()); + //set the machine settings into print config + if (!new_printer_name.empty() || up_config_to_date) { + std::vector different_keys; + + if (new_printer_name.empty()) { + std::string diff_settings; + if (!different_settings.empty()) { + diff_settings = different_settings[filament_count+1]; + Slic3r::unescape_strings_cstyle(diff_settings, different_keys); + } + } + else { + different_settings[filament_count+1] = ""; + inherits_group[filament_count+1] = ""; + } + + std::set different_keys_set(different_keys.begin(), different_keys.end()); + int ret = update_full_config(m_print_config, load_machine_config, different_keys_set); + if (ret) + flush_and_exit(ret); + } + + //set the process settings into print config + std::vector& print_compatible_printers = m_print_config.option("print_compatible_printers", true)->values; + if (!new_process_name.empty() || up_config_to_date) { + std::vector different_keys; + + if (new_process_name.empty()) { + std::string diff_settings; + if (!different_settings.empty()) { + diff_settings = different_settings[0]; + Slic3r::unescape_strings_cstyle(diff_settings, different_keys); + int remove_index = -1; + for (int index = 0; index < different_keys.size(); index++) { + if (different_keys[index] == "compatible_printers") { + remove_index = index; + break; + } + } + if (remove_index != -1) { + different_keys[remove_index] = different_keys[different_keys.size() - 1]; + different_keys.erase(different_keys.begin() + different_keys.size() - 1); + different_settings[0] = Slic3r::escape_strings_cstyle(different_keys); + } + } + print_compatible_printers = std::move(current_print_compatible_printers); + } + else { + different_settings[0] = ""; + inherits_group[0] = ""; + print_compatible_printers = std::move(new_print_compatible_printers); + } + + std::set different_keys_set(different_keys.begin(), different_keys.end()); + int ret = update_full_config(m_print_config, load_machine_config, different_keys_set); + if (ret) + flush_and_exit(ret); + } + + if (machine_upwards) { + print_compatible_printers.push_back(new_printer_name); + + std::string old_setting = different_settings[0]; + if (old_setting.empty()) + different_settings[0] = "compatible_printers"; + else { + std::vector different_keys; + Slic3r::unescape_strings_cstyle(old_setting, different_keys); + bool need_insert = true; + for (int index = 0; index < different_keys.size(); index++) { + if (different_keys[index] == "compatible_printers") { + need_insert = false; + break; + } + } + if (need_insert) + different_settings[0] = old_setting + ";compatible_printers"; + } + } + + //set the filament settings into print config + if ((load_filament_count > 0) || (up_config_to_date)) + { + for (int index = 0; index < load_filaments_config.size(); index++) { + DynamicPrintConfig& config = load_filaments_config[index]; + int filament_index = load_filaments_index[index]; + std::vector different_keys; + + 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]; + ConfigOptionString* filament_name_setting = new ConfigOptionString(filament_name); + if (opt_filament_settings->size() < filament_count) + opt_filament_settings->resize(filament_count, filament_name_setting); + opt_filament_settings->set_at(filament_name_setting, filament_index-1, 0); + config.erase("filament_settings_id"); + + std::string& filament_id = load_filaments_id[index]; + ConfigOptionStrings *opt_filament_ids = static_cast (m_print_config.option("filament_ids", true)); + ConfigOptionString* filament_id_setting = new ConfigOptionString(filament_id); + if (opt_filament_ids->size() < filament_count) + opt_filament_ids->resize(filament_count, filament_id_setting); + opt_filament_ids->set_at(filament_id_setting, filament_index-1, 0); + + different_settings[filament_index] = ""; + inherits_group[filament_index] = ""; + } + else { + std::string diff_settings; + + if (!different_settings.empty()) { + diff_settings = different_settings[filament_index]; + Slic3r::unescape_strings_cstyle(diff_settings, different_keys); + } + } + + //parse the filament value to index th + //loop through options and apply them + std::set different_keys_set(different_keys.begin(), different_keys.end()); + 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 + 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, + // an exception is thrown if not ignore_nonexistent. + + const ConfigOption *source_opt = config.option(opt_key); + if (source_opt == nullptr) { + // The key was not found in the source config, therefore it will not be initialized! + boost::nowide::cerr << "can not found option " <is_scalar()) { + if (opt_key == "compatible_printers_condition") { + ConfigOption *opt = m_print_config.option("compatible_machine_expression_group", true); + ConfigOptionStrings* opt_vec_dst = static_cast(opt); + if (opt_vec_dst->size() == 0) + opt_vec_dst->resize(filament_count+2, new ConfigOptionString()); + opt_vec_dst->set_at(source_opt, filament_index, 0); + } + else if (opt_key == "compatible_prints_condition") { + ConfigOption *opt = m_print_config.option("compatible_process_expression_group", true); + ConfigOptionStrings* opt_vec_dst = static_cast(opt); + if (opt_vec_dst->size() == 0) + opt_vec_dst->resize(filament_count, new ConfigOptionString()); + opt_vec_dst->set_at(source_opt, filament_index-1, 0); + } + else { + //skip the scalar values + BOOST_LOG_TRIVIAL(warning) << "skip scalar option " <def(). + // This is only possible if other is of DynamicConfig type. + boost::nowide::cerr << "can not create option " <(opt); + const ConfigOptionVectorBase* opt_vec_src = static_cast(source_opt); + if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "model_id" || opt_key == "dev_model_name" || opt_key == "filament_settings_id") + continue; + else { + opt_vec_dst->set_at(opt_vec_src, filament_index-1, 0); + } + } + } + } + } + //BBS: set default to ptFFF if (printer_technology == ptUnknown) printer_technology = ptFFF; @@ -556,7 +1230,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; - flush_and_exit(1); + flush_and_exit(CLI_INVALID_PRINTER_TECH); /*assert(printer_technology == ptSLA); sla_print_config.filename_format.value = "[input_filename_base].sl1"; @@ -573,7 +1247,7 @@ int CLI::run(int argc, char **argv) std::string validity = m_print_config.validate(); if (!validity.empty()) { boost::nowide::cerr <<"Error: The composite configation is not valid: " << validity << std::endl; - flush_and_exit(1); + flush_and_exit(CLI_INVALID_PRINTER_TECH); } //BBS: partplate list @@ -594,10 +1268,9 @@ int CLI::run(int argc, char **argv) plate_stride = partplate_list.plate_stride_x(); BOOST_LOG_TRIVIAL(info) << "bed size, x="< 0) + if (plate_data_src.size() > 0) { - partplate_list.load_from_3mf_structure(plate_data); - release_PlateData_list(plate_data); + partplate_list.load_from_3mf_structure(plate_data_src); } /*for (ModelObject *model_object : m_models[0].objects) for (ModelInstance *model_instance : model_object->instances) @@ -677,7 +1350,7 @@ int CLI::run(int argc, char **argv) } } catch (std::exception &ex) { boost::nowide::cerr << "error: " << ex.what() << std::endl; - flush_and_exit(1); + flush_and_exit(CLI_COPY_OBJECTS_ERROR); } } } else if (opt_key == "center") { @@ -746,7 +1419,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; - flush_and_exit(1); + flush_and_exit(CLI_SCALE_TO_FIT_ERROR); } for (auto &model : m_models) for (auto &o : model.objects) @@ -836,11 +1509,12 @@ int CLI::run(int argc, char **argv) // model.repair(); } else { boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; - flush_and_exit(1); + flush_and_exit(CLI_UNSUPPORTED_OPERATION); } } 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) { @@ -850,6 +1524,7 @@ int CLI::run(int argc, char **argv) { BOOST_LOG_TRIVIAL(info) << "Before process command, Orient object, name=" << o->name <<",id="<id().id<ensure_on_bed(); // loop through action options - bool export_to_3mf = false; - int plate_to_slice = 0; - std::string export_3mf_file; + bool export_to_3mf = false, load_slicedata = false, export_slicedata = false, export_slicedata_error = 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; for (auto const &opt_key : m_actions) { @@ -1002,6 +1677,18 @@ int CLI::run(int argc, char **argv) this->print_help(true, ptFFF); } else if (opt_key == "help_sla") { this->print_help(true, ptSLA); + } else if (opt_key == "pipe") { +#if defined(__linux__) || defined(__LINUX__) + std::string pipe_name = m_config.option("pipe")->value; + g_cli_callback_mgr.start(pipe_name); +#endif + } else if (opt_key == "load_slicedata") { + load_slicedata = true; + 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; + 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 @@ -1013,16 +1700,18 @@ int CLI::run(int argc, char **argv) model.add_default_instances(); model.print_info(); } + } else if (opt_key == "uptodate") { + //already processed before } else if (opt_key == "export_stl") { for (auto &model : m_models) model.add_default_instances(); if (! this->export_models(IO::STL)) - flush_and_exit(1); + 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)) - flush_and_exit(1); + flush_and_exit(CLI_EXPORT_OBJ_ERROR); }/* else if (opt_key == "export_amf") { if (! this->export_models(IO::AMF)) return 1; @@ -1030,6 +1719,13 @@ int CLI::run(int argc, char **argv) export_to_3mf = true; export_3mf_file = m_config.opt_string(opt_key); //} else if (opt_key == "export_gcode" || opt_key == "export_sla" || opt_key == "slice") { + } else if (opt_key == "export_slicedata") { + export_slicedata = true; + 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; + 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; @@ -1099,6 +1795,20 @@ int CLI::run(int argc, char **argv) BuildVolume build_volume(part_plate->get_shape(), print_height); model.update_print_volume_state(build_volume); unsigned int count = model.update_print_volume_state(build_volume); + + 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; + flush_and_exit(CLI_NO_SUITABLE_OBJECTS); + } + else { + for (ModelObject* model_object : model.objects) + for (ModelInstance *i : model_object->instances) + 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; + flush_and_exit(CLI_OBJECTS_PARTLY_INSIDE); + } + } // BBS: TODO //BOOST_LOG_TRIVIAL(info) << boost::format("print_volume {%1%,%2%,%3%}->{%4%, %5%, %6%}, has %7% printables") % print_volume.min(0) % print_volume.min(1) // % print_volume.min(2) % print_volume.max(0) % print_volume.max(1) % print_volume.max(2) % count << std::endl; @@ -1122,7 +1832,9 @@ int CLI::run(int argc, char **argv) if (format == static_cast(m_print_config.def()->get("filename_format")->default_value.get())->value) format = "[input_filename_base].SL1"; }*/ - print->apply(model, m_print_config); + DynamicPrintConfig new_print_config = m_print_config; + new_print_config.apply(*part_plate->config()); + print->apply(model, new_print_config); StringObjectException warning; auto err = print->validate(&warning); if (!err.string.empty()) { @@ -1130,20 +1842,48 @@ int CLI::run(int argc, char **argv) boost::nowide::cerr << err.string << std::endl; //BBS: continue for other plates //continue; - flush_and_exit(1); + flush_and_exit(CLI_VALIDATE_ERROR); } else if (!warning.string.empty()) BOOST_LOG_TRIVIAL(info) << "got warnings: "<< warning.string << std::endl; if (print->empty()) { - BOOST_LOG_TRIVIAL(info) << "Nothing to print for " << outfile << " . Either the print is empty or no object is fully inside the print volume." << std::endl; - flush_and_exit(1); + 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; + flush_and_exit(CLI_NO_SUITABLE_OBJECTS); } else try { std::string outfile_final; - BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<process(); + BOOST_LOG_TRIVIAL(info) << "start Print::process for partplate "<set_status_callback(cli_status_callback); + g_cli_callback_mgr.set_plate_info(index+1, (plate_to_slice== 0)?partplate_list.get_plate_count():1); + if (!warning.string.empty()) { + PrintBase::SlicingStatus slicing_status{2, warning.string, 0, 0}; + cli_status_callback(slicing_status); + } + } +#endif + if (load_slicedata) { + std::string plate_dir = load_slice_data_dir+"/"+std::to_string(index+1); + int ret = print->load_cached_data(plate_dir); + if (ret) { + BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": load Slicing data error, ret=" << ret; + BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": switch normal slicing"; + print->process(); + } + else { + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": load cached data success, go on."; + print->process(true); + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": finished print::process."; + } + } + else { + print->process(); + } if (printer_technology == ptFFF) { // The outfile is processed by a PlaceholderParser. //outfile = part_plate->get_tmp_gcode_path(); @@ -1176,13 +1916,38 @@ int CLI::run(int argc, char **argv) //run_post_process_scripts(outfile, print->full_print_config()); BOOST_LOG_TRIVIAL(info) << "Slicing result exported to " << outfile << std::endl; part_plate->update_slice_result_valid_state(true); +#if defined(__linux__) || defined(__LINUX__) + if (g_cli_callback_mgr.is_started()) { + PrintBase::SlicingStatus slicing_status{100, "Slicing finished"}; + cli_status_callback(slicing_status); + } +#endif + if (export_slicedata) { + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ":will export Slicing data to " << export_slice_data_dir; + std::string plate_dir = export_slice_data_dir+"/"+std::to_string(index+1); + bool with_space = (get_logging_level() >= 4)?true:false; + int ret = print->export_cached_data(plate_dir, with_space); + if (ret) { + BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": export Slicing data error, ret=" << ret; + export_slicedata_error = true; + if (fs::exists(plate_dir)) + fs::remove_all(plate_dir); + } + } } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "< plate_bboxes; PlateDataPtrs plate_data_list; partplate_list.store_to_3mf_structure(plate_data_list); - std::vector project_presets; + if (!outfile_dir.empty()) { export_3mf_file = outfile_dir + "/"+export_3mf_file; } +#if defined(__linux__) || defined(__LINUX__) + if (g_cli_callback_mgr.is_started()) { + PrintBase::SlicingStatus slicing_status{91, "Generate thumbnails"}; + cli_status_callback(slicing_status); + } +#endif + + bool need_regenerate_thumbnail = oriented_or_arranged; // get type and color for platedata auto* filament_types = dynamic_cast(m_print_config.option("filament_type")); const ConfigOptionStrings* filament_color = dynamic_cast(m_print_config.option("filament_colour")); @@ -1244,202 +2017,274 @@ int CLI::run(int argc, char **argv) it->color = filament_color?filament_color->get_at(it->id):"#FFFFFF"; //it->filament_id = filament_id?filament_id->get_at(it->id):"unknown"; } + + if (!plate_data->plate_thumbnail.is_valid()) { + if (!oriented_or_arranged && plate_data_src.size() > i) + plate_data->thumbnail_file = plate_data_src[i]->thumbnail_file; + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail data is invalid, check the file %2% exist or not")%(i+1) %plate_data->thumbnail_file; + if (plate_data->thumbnail_file.empty() || (!boost::filesystem::exists(plate_data->thumbnail_file))) { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file also not there, need to regenerate")%(i+1); + need_regenerate_thumbnail = true; + } + else { + BOOST_LOG_TRIVIAL(info) << boost::format("thumbnails stage: plate %1%'s thumbnail file exists, no need to regenerate")%(i+1); + } + } } - std::vector colors; - if (filament_color) { - colors= filament_color->vserialize(); - } - else - colors.push_back("#FFFFFF"); + if (need_regenerate_thumbnail) { + std::vector colors; + if (filament_color) { + colors= filament_color->vserialize(); + } + else + colors.push_back("#FFFFFF"); - std::vector> colors_out(colors.size()); - unsigned char rgb_color[3] = {}; - for (const std::string& color : colors) { - Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); - size_t color_idx = &color - &colors.front(); - colors_out[color_idx] = { float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f }; - } + std::vector> colors_out(colors.size()); + unsigned char rgb_color[3] = {}; + for (const std::string& color : colors) { + Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); + size_t color_idx = &color - &colors.front(); + colors_out[color_idx] = { float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f }; + } - int gl_major, gl_minor, gl_verbos; - glfwGetVersion(&gl_major, &gl_minor, &gl_verbos); - BOOST_LOG_TRIVIAL(info) << boost::format("opengl version %1%.%2%.%3%")%gl_major %gl_minor %gl_verbos; + int gl_major, gl_minor, gl_verbos; + glfwGetVersion(&gl_major, &gl_minor, &gl_verbos); + BOOST_LOG_TRIVIAL(info) << boost::format("opengl version %1%.%2%.%3%")%gl_major %gl_minor %gl_verbos; - glfwSetErrorCallback(glfw_callback); - int ret = glfwInit(); - if (ret == GLFW_FALSE) { - int code = glfwGetError(NULL); - BOOST_LOG_TRIVIAL(error) << "glfwInit return error, code " <(option))->getInt(); - 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 (!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, "volume", true); - //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; - std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; - - unsigned char rgb_color[3] = {}; - Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); - glvolume_collection.volumes.back()->set_render_color( float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f); - } + GLFWwindow* window = glfwCreateWindow(640, 480, "base_window", NULL, NULL); + if (window == NULL) + { + BOOST_LOG_TRIVIAL(error) << "Failed to create GLFW window" << std::endl; } + else + glfwMakeContextCurrent(window); } - - ThumbnailsParams thumbnail_params; - GLShaderProgram* shader = opengl_mgr.get_shader("gouraud_light"); - if (!shader) { - BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail"); + bool opengl_valid = opengl_mgr.init_gl(); + if (!opengl_valid) { + BOOST_LOG_TRIVIAL(error) << "init opengl failed! skip thumbnail generating" << std::endl; } else { - for (int i = 0; i < partplate_list.get_plate_count(); i++) { - Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); - ThumbnailData * thumbnail_data = new ThumbnailData(); - unsigned int thumbnail_width = 256, thumbnail_height = 256; - const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; + BOOST_LOG_TRIVIAL(info) << "glewInit Sucess." << std::endl; + GLVolumeCollection glvolume_collection; + Model &model = m_models[0]; + int 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(); + 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 (!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, "volume", true); + //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; + std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) - { - case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: - { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); - Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, - thumbnail_width, thumbnail_height, thumbnail_params, - partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); + unsigned char rgb_color[3] = {}; + Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); + glvolume_collection.volumes.back()->set_render_color( float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f); + + std::array new_color; + new_color[0] = float(rgb_color[0]) / 255.f; + new_color[1] = float(rgb_color[1]) / 255.f; + new_color[2] = float(rgb_color[2]) / 255.f; + new_color[3] = 1.f; + glvolume_collection.volumes.back()->set_color(new_color); + } + } + } + + ThumbnailsParams thumbnail_params; + GLShaderProgram* shader = opengl_mgr.get_shader("gouraud_light"); + if (!shader) { + BOOST_LOG_TRIVIAL(error) << boost::format("can not get shader for rendering thumbnail"); + } + else { + for (int i = 0; i < partplate_list.get_plate_count(); i++) { + Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); + PlateData *plate_data = plate_data_list[i]; + if (plate_data->plate_thumbnail.is_valid()) { + thumbnails.push_back(&plate_data->plate_thumbnail); + 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; + continue; + } + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail, need to regenerate")%(i+1); + ThumbnailData * thumbnail_data = new ThumbnailData(); + unsigned int thumbnail_width = 256, thumbnail_height = 256; + const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; + + switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); + break; + } + case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: + { + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); + Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, + thumbnail_width, thumbnail_height, thumbnail_params, + partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); + break; + } + default: + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); break; - } - case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: - { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); - Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, - thumbnail_width, thumbnail_height, thumbnail_params, - partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); - break; - } - default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); - break; + } + thumbnails.push_back(thumbnail_data); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail,finished rendering")%(i+1); } - thumbnails.push_back(thumbnail_data); - - //render calibration thumbnail - if (!part_plate->get_slice_result() || !part_plate->is_slice_result_valid()) { - BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% doesn't have a valid sliced result, skip it")%(i+1); - calibration_thumbnails.push_back(new ThumbnailData()); - plate_bboxes.push_back(new PlateBBoxData()); - continue; - } - PrintBase *print_base=NULL; - Slic3r::GUI::GCodeResult *gcode_result = NULL; - int print_index; - part_plate->get_print(&print_base, &gcode_result, &print_index); - - BuildVolume build_volume(part_plate->get_shape(), print_height); - const std::vector& exclude_bounding_box = part_plate->get_exclude_areas(); - Print *print = dynamic_cast(print_base); - Slic3r::GUI::GCodeViewer gcode_viewer; - gcode_viewer.init(ConfigOptionMode::comAdvanced, nullptr); - gcode_viewer.load(*gcode_result, *print, build_volume, exclude_bounding_box, false, ConfigOptionMode::comAdvanced, false); - - std::vector colors; - if (filament_color) - colors = filament_color->values; - gcode_viewer.refresh(*gcode_result, colors); - - ThumbnailData* calibration_data = new ThumbnailData(); - const ThumbnailsParams calibration_params = { {}, false, true, true, true, i }; - //BBS fixed size - const int cali_thumbnail_width = 2560; - const int cali_thumbnail_height = 2560; - gcode_viewer.render_calibration_thumbnail(*calibration_data, cali_thumbnail_width, cali_thumbnail_height, - calibration_params, partplate_list, opengl_mgr); - //generate_calibration_thumbnail(*calibration_data, thumbnail_width, thumbnail_height, calibration_params); - //*plate_bboxes[index] = p->generate_first_layer_bbox(); - calibration_thumbnails.push_back(calibration_data); - - PlateBBoxData* plate_bbox = new PlateBBoxData(); - std::vector& id_bboxes = plate_bbox->bbox_objs; - BoundingBoxf bbox_all; - auto seq_print = m_print_config.option>("print_sequence"); - if ( seq_print && (seq_print->value == PrintSequence::ByObject)) - plate_bbox->is_seq_print = true; - - auto objects = print->objects(); - auto orig = part_plate->get_origin(); - Vec2d orig2d = { orig[0], orig[1] }; - - for (auto obj : objects) - { - 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; - data.bbox = { bb.min.x(),bb.min.y(),bb.max.x(),bb.max.y() }; - id_bboxes.emplace_back(std::move(data)); - } - plate_bbox->bbox_all = { bbox_all.min.x(),bbox_all.min.y(),bbox_all.max.x(),bbox_all.max.y() }; - plate_bboxes.push_back(plate_bbox); + } + } + //BBS: release glfw + glfwTerminate(); + } + else { + for (int i = 0; i < partplate_list.get_plate_count(); i++) { + PlateData *plate_data = plate_data_list[i]; + if (plate_data->plate_thumbnail.is_valid()) { + thumbnails.push_back(&plate_data->plate_thumbnail); + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail data, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height; } } } + //generate first layer bboxes + for (int i = 0; i < partplate_list.get_plate_count(); i++) { + Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i); + //render calibration thumbnail + if (!part_plate->get_slice_result() || !part_plate->is_slice_result_valid()) { + BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% doesn't have a valid sliced result, skip it")%(i+1); + //calibration_thumbnails.push_back(new ThumbnailData()); + plate_bboxes.push_back(new PlateBBoxData()); + continue; + } + PrintBase *print_base=NULL; + Slic3r::GUI::GCodeResult *gcode_result = NULL; + int print_index; + part_plate->get_print(&print_base, &gcode_result, &print_index); + + Print *print = dynamic_cast(print_base); + + //don't render calibration picture + /*BuildVolume build_volume(part_plate->get_shape(), print_height); + const std::vector& exclude_bounding_box = part_plate->get_exclude_areas(); + Slic3r::GUI::GCodeViewer gcode_viewer; + gcode_viewer.init(ConfigOptionMode::comAdvanced, nullptr); + gcode_viewer.load(*gcode_result, *print, build_volume, exclude_bounding_box, false, ConfigOptionMode::comAdvanced, false); + + std::vector colors; + if (filament_color) + colors = filament_color->values; + gcode_viewer.refresh(*gcode_result, colors); + + ThumbnailData* calibration_data = new ThumbnailData(); + const ThumbnailsParams calibration_params = { {}, false, true, true, true, i }; + //BBS fixed size + const int cali_thumbnail_width = 2560; + const int cali_thumbnail_height = 2560; + gcode_viewer.render_calibration_thumbnail(*calibration_data, cali_thumbnail_width, cali_thumbnail_height, + calibration_params, partplate_list, opengl_mgr); + //generate_calibration_thumbnail(*calibration_data, thumbnail_width, thumbnail_height, calibration_params); + //*plate_bboxes[index] = p->generate_first_layer_bbox(); + calibration_thumbnails.push_back(calibration_data);*/ + + PlateBBoxData* plate_bbox = new PlateBBoxData(); + std::vector& id_bboxes = plate_bbox->bbox_objs; + BoundingBoxf bbox_all; + auto seq_print = m_print_config.option>("print_sequence"); + if ( seq_print && (seq_print->value == PrintSequence::ByObject)) + plate_bbox->is_seq_print = true; + + auto objects = print->objects(); + auto orig = part_plate->get_origin(); + Vec2d orig2d = { orig[0], orig[1] }; + + for (auto obj : objects) + { + 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; + data.bbox = { bb.min.x(),bb.min.y(),bb.max.x(),bb.max.y() }; + id_bboxes.emplace_back(std::move(data)); + } + // add wipe tower bounding box + if (print->has_wipe_tower()) { + BBoxData data; + auto wt_corners = print->first_layer_wipe_tower_corners(); + // when loading gcode.3mf, wipe tower info may not be correct + if (!wt_corners.empty()) { + BoundingBox bb_scaled = {wt_corners[0], wt_corners[2]}; + auto bb = unscaled(bb_scaled); + bb.min -= orig2d; + bb.max -= orig2d; + bbox_all.merge(bb); + data.name = "wipe_tower"; + data.id = partplate_list.get_curr_plate()->get_index() + 1000; + data.bbox = {bb.min.x(), bb.min.y(), bb.max.x(), bb.max.y()}; + id_bboxes.emplace_back(std::move(data)); + } + } + plate_bbox->bbox_all = { bbox_all.min.x(),bbox_all.min.y(),bbox_all.max.x(),bbox_all.max.y() }; + plate_bboxes.push_back(plate_bbox); + } + + +#if defined(__linux__) || defined(__LINUX__) + if (g_cli_callback_mgr.is_started()) { + PrintBase::SlicingStatus slicing_status{95, "Exporting 3mf"}; + cli_status_callback(slicing_status); + } +#endif + 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, calibration_thumbnails, plate_bboxes, &m_print_config)) { release_PlateData_list(plate_data_list); - flush_and_exit(1); + flush_and_exit(CLI_EXPORT_3MF_ERROR); } release_PlateData_list(plate_data_list); for (unsigned int i = 0; i < thumbnails.size(); i++) @@ -1452,11 +2297,20 @@ int CLI::run(int argc, char **argv) delete plate_bboxes[i]; } - //BBS: release glfw - if (export_to_3mf) { - glfwTerminate(); + if (plate_data_src.size() > 0) + { + release_PlateData_list(plate_data_src); } +#if defined(__linux__) || defined(__LINUX__) + if (g_cli_callback_mgr.is_started()) { + PrintBase::SlicingStatus slicing_status{100, "All done, Success"}; + cli_status_callback(slicing_status); + } + + g_cli_callback_mgr.stop(); +#endif + //BBS: flush logs BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", Finished" << std::endl; boost::nowide::cout.flush(); @@ -1485,17 +2339,17 @@ bool CLI::setup(int argc, char **argv) // Notify user that a blacklisted DLL was injected into BambuStudio process (for example Nahimic, see GH #5573). // We hope that if a DLL is being injected into a BambuStudio process, it happens at the very start of the application, // thus we shall detect them now. - //if (BlacklistedLibraryCheck::get_instance().perform_check()) { - // std::wstring text = L"Following DLLs have been injected into the BambuStudio process:\n\n"; - // text += BlacklistedLibraryCheck::get_instance().get_blacklisted_string(); - // text += L"\n\n" - // L"BambuStudio is known to not run correctly with these DLLs injected. " - // L"We suggest stopping or uninstalling these services if you experience " - // L"crashes or unexpected behaviour while using BambuStudio.\n" - // L"For example, ASUS Sonic Studio injects a Nahimic driver, which makes BambuStudio " - // L"to crash on a secondary monitor, see BambuStudio github issue #5573"; - // MessageBoxW(NULL, text.c_str(), L"Warning"/*L"Incopatible library found"*/, MB_OK); - //} + if (BlacklistedLibraryCheck::get_instance().perform_check()) { + std::wstring text = L"Following DLLs have been injected into the BambuStudio process:\n\n"; + text += BlacklistedLibraryCheck::get_instance().get_blacklisted_string(); + text += L"\n\n" + L"BambuStudio is known to not run correctly with these DLLs injected. " + L"We suggest stopping or uninstalling these services if you experience " + L"crashes or unexpected behaviour while using BambuStudio.\n" + L"For example, ASUS Sonic Studio injects a Nahimic driver, which makes BambuStudio " + L"to crash on a secondary monitor"; + MessageBoxW(NULL, text.c_str(), L"Warning"/*L"Incopatible library found"*/, MB_OK); + } #endif // See Invoking prusa-slicer from $PATH environment variable crashes #5542 @@ -1548,8 +2402,9 @@ bool CLI::setup(int argc, char **argv) #if !BBL_RELEASE_TO_PUBLIC { const ConfigOptionInt *opt_loglevel = m_config.opt("debug"); - if (opt_loglevel != 0) + if (opt_loglevel != 0) { set_logging_level(opt_loglevel->value); + } } #endif @@ -1575,7 +2430,7 @@ bool CLI::setup(int argc, char **argv) void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const { boost::nowide::cout - << SLIC3R_BUILD_ID << ":" + << SLIC3R_APP_KEY <<"-"<< SLIC3R_VERSION << ":" << std::endl << "Usage: bambu-studio [ OPTIONS ] [ file.3mf/file.stl ... ]" << std::endl << std::endl @@ -1641,7 +2496,7 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla store_params.thumbnail_data = thumbnails; store_params.calibration_thumbnail_data = calibration_thumbnails; store_params.id_bboxes = plate_bboxes; - store_params.strategy = store_params.strategy|SaveStrategy::WithGcode; + store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel; success = Slic3r::store_bbs_3mf(store_params); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c5cb96a97..b4d1e72caf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(admesh) # boost/nowide add_subdirectory(boost) add_subdirectory(clipper) +add_subdirectory(clipper2) add_subdirectory(miniz) add_subdirectory(minilzo) add_subdirectory(glu-libtess) @@ -133,7 +134,7 @@ elseif (MSVC) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") else () # Boost on Raspberry-Pi does not link to pthreads explicitely. - target_link_libraries(BambuStudio ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads) + target_link_libraries(BambuStudio ${CMAKE_DL_LIBS} -lstdc++ Threads::Threads pangoft2-1.0) endif () # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. diff --git a/src/clipper2/CMakeLists.txt b/src/clipper2/CMakeLists.txt new file mode 100644 index 0000000000..275f9273b1 --- /dev/null +++ b/src/clipper2/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.10) +project(Clipper2 VERSION 1.0.6 LANGUAGES C CXX) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set_property(GLOBAL PROPERTY USE_FOLDERS OFF) + +option(BUILD_SHARED_LIBS "Build shared libs" OFF) + +include(GNUInstallDirs) + +set(CLIPPER2_INC + Clipper2Lib/include/clipper2/clipper.h + Clipper2Lib/include/clipper2/clipper.core.h + Clipper2Lib/include/clipper2/clipper.engine.h + Clipper2Lib/include/clipper2/clipper.export.h + Clipper2Lib/include/clipper2/clipper.minkowski.h + Clipper2Lib/include/clipper2/clipper.offset.h + Clipper2Lib/include/clipper2/clipper.rectclip.h +) + +set(CLIPPER2_SRC + Clipper2Lib/src/clipper.engine.cpp + Clipper2Lib/src/clipper.offset.cpp + Clipper2Lib/src/clipper.rectclip.cpp +) + +# 2d version of Clipper2 +add_library(Clipper2 ${CLIPPER2_INC} ${CLIPPER2_SRC}) + +target_include_directories(Clipper2 + PUBLIC Clipper2Lib/include +) + +if (WIN32) + target_compile_options(Clipper2 PRIVATE /W4 /WX) +else() + target_compile_options(Clipper2 PRIVATE -Wall -Wextra -Wpedantic -Werror) + target_link_libraries(Clipper2 PUBLIC -lm) + +endif() + +set_target_properties(Clipper2 PROPERTIES FOLDER Libraries + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + PUBLIC_HEADER "${CLIPPER2_INC}" +) + diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h new file mode 100644 index 0000000000..f8d6b42b78 --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.core.h @@ -0,0 +1,653 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 4 November 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : Core Clipper Library structures and functions * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_CORE_H +#define CLIPPER_CORE_H + +#include +#include +#include +#include +#include +#include +#include + +//#define NO_EXCEPTIONS + +namespace Clipper2Lib +{ + +#ifndef NO_EXCEPTIONS + static const char* precision_error = + "Precision exceeds the permitted range"; +#endif + + static double const PI = 3.141592653589793238; + static int64_t const MAX_COORD = LLONG_MAX / 2; + + //By far the most widely used filling rules for polygons are EvenOdd + //and NonZero, sometimes called Alternate and Winding respectively. + //https://en.wikipedia.org/wiki/Nonzero-rule + enum class FillRule { EvenOdd, NonZero, Positive, Negative }; + +// Point ------------------------------------------------------------------------ + +template +struct Point { + T x; + T y; +#ifdef USINGZ + int64_t z; + + template + inline void Init(const T2 x_ = 0, const T2 y_ = 0, const int64_t z_ = 0) + { + if constexpr (std::numeric_limits::is_integer && + !std::numeric_limits::is_integer) + { + x = static_cast(std::round(x_)); + y = static_cast(std::round(y_)); + z = z_; + } + else + { + x = static_cast(x_); + y = static_cast(y_); + z = z_; + } + } + + explicit Point() : x(0), y(0), z(0) {}; + + template + Point(const T2 x_, const T2 y_, const int64_t z_ = 0) + { + Init(x_, y_); + z = z_; + } + + template + explicit Point(const Point& p) + { + Init(p.x, p.y, p.z); + } + + Point operator * (const double scale) const + { + return Point(x * scale, y * scale, z); + } + + + friend std::ostream& operator<<(std::ostream& os, const Point& point) + { + os << point.x << "," << point.y << "," << point.z; + return os; + } + +#else + + template + inline void Init(const T2 x_ = 0, const T2 y_ = 0) + { + if constexpr (std::numeric_limits::is_integer && + !std::numeric_limits::is_integer) + { + x = static_cast(std::round(x_)); + y = static_cast(std::round(y_)); + } + else + { + x = static_cast(x_); + y = static_cast(y_); + } + } + + explicit Point() : x(0), y(0) {}; + + template + Point(const T2 x_, const T2 y_) { Init(x_, y_); } + + template + explicit Point(const Point& p) { Init(p.x, p.y); } + + Point operator * (const double scale) const + { + return Point(x * scale, y * scale); + } + + friend std::ostream& operator<<(std::ostream& os, const Point& point) + { + os << point.x << "," << point.y; + return os; + } +#endif + + friend bool operator==(const Point &a, const Point &b) + { + return a.x == b.x && a.y == b.y; + } + + friend bool operator!=(const Point& a, const Point& b) + { + return !(a == b); + } + + inline Point operator-() const + { + return Point(-x,-y); + } + + inline Point operator+(const Point &b) const + { + return Point(x+b.x, y+b.y); + } + + inline Point operator-(const Point &b) const + { + return Point(x-b.x, y-b.y); + } + + inline void Negate() { x = -x; y = -y; } + +}; + +//nb: using 'using' here (instead of typedef) as they can be used in templates +using Point64 = Point; +using PointD = Point; + +template +using Path = std::vector>; +template +using Paths = std::vector>; + +using Path64 = Path; +using PathD = Path; +using Paths64 = std::vector< Path64>; +using PathsD = std::vector< PathD>; + +template +std::ostream& operator << (std::ostream& outstream, const Path& path) +{ + if (!path.empty()) + { + auto pt = path.cbegin(), last = path.cend() - 1; + while (pt != last) + outstream << *pt++ << ", "; + outstream << *last << std::endl; + } + return outstream; +} + +template +std::ostream& operator << (std::ostream& outstream, const Paths& paths) +{ + for (auto p : paths) + outstream << p; + return outstream; +} + +template +inline Path ScalePath(const Path& path, double scale) +{ + Path result; + result.reserve(path.size()); +#ifdef USINGZ + for (const Point& pt : path) + result.push_back(Point(pt.x * scale, pt.y * scale, pt.z)); +#else + for (const Point& pt : path) + result.push_back(Point(pt.x * scale, pt.y * scale)); +#endif + return result; +} + +template +inline Paths ScalePaths(const Paths& paths, double scale) +{ + Paths result; + result.reserve(paths.size()); + for (const Path& path : paths) + result.push_back(ScalePath(path, scale)); + return result; +} + +template +inline Path TransformPath(const Path& path) +{ + Path result; + result.reserve(path.size()); + std::transform(path.cbegin(), path.cend(), std::back_inserter(result), + [](const Point& pt) {return Point(pt); }); + return result; +} + +template +inline Paths TransformPaths(const Paths& paths) +{ + Paths result; + std::transform(paths.cbegin(), paths.cend(), std::back_inserter(result), + [](const Path& path) {return TransformPath(path); }); + return result; +} + +inline PathD Path64ToPathD(const Path64& path) +{ + return TransformPath(path); +} + +inline PathsD Paths64ToPathsD(const Paths64& paths) +{ + return TransformPaths(paths); +} + +inline Path64 PathDToPath64(const PathD& path) +{ + return TransformPath(path); +} + +inline Paths64 PathsDToPaths64(const PathsD& paths) +{ + return TransformPaths(paths); +} + +template +inline double Sqr(T val) +{ + return static_cast(val) * static_cast(val); +} + +template +inline bool NearEqual(const Point& p1, + const Point& p2, double max_dist_sqrd) +{ + return Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y) < max_dist_sqrd; +} + +template +inline Path StripNearEqual(const Path& path, + double max_dist_sqrd, bool is_closed_path) +{ + if (path.size() == 0) return Path(); + Path result; + result.reserve(path.size()); + typename Path::const_iterator path_iter = path.cbegin(); + Point first_pt = *path_iter++, last_pt = first_pt; + result.push_back(first_pt); + for (; path_iter != path.cend(); ++path_iter) + { + if (!NearEqual(*path_iter, last_pt, max_dist_sqrd)) + { + last_pt = *path_iter; + result.push_back(last_pt); + } + } + if (!is_closed_path) return result; + while (result.size() > 1 && + NearEqual(result.back(), first_pt, max_dist_sqrd)) result.pop_back(); + return result; +} + +template +inline Paths StripNearEqual(const Paths& paths, + double max_dist_sqrd, bool is_closed_path) +{ + Paths result; + result.reserve(paths.size()); + for (typename Paths::const_iterator paths_citer = paths.cbegin(); + paths_citer != paths.cend(); ++paths_citer) + { + result.push_back(StripNearEqual(*paths_citer, max_dist_sqrd, is_closed_path)); + } + return result; +} + +template +inline Path StripDuplicates(const Path& path, bool is_closed_path) +{ + if (path.size() == 0) return Path(); + Path result; + result.reserve(path.size()); + typename Path::const_iterator path_iter = path.cbegin(); + Point first_pt = *path_iter++, last_pt = first_pt; + result.push_back(first_pt); + for (; path_iter != path.cend(); ++path_iter) + { + if (*path_iter != last_pt) + { + last_pt = *path_iter; + result.push_back(last_pt); + } + } + if (!is_closed_path) return result; + while (result.size() > 1 && result.back() == first_pt) result.pop_back(); + return result; +} + +template +inline Paths StripDuplicates(const Paths& paths, bool is_closed_path) +{ + Paths result; + result.reserve(paths.size()); + for (typename Paths::const_iterator paths_citer = paths.cbegin(); + paths_citer != paths.cend(); ++paths_citer) + { + result.push_back(StripDuplicates(*paths_citer, is_closed_path)); + } + return result; +} + +// Rect ------------------------------------------------------------------------ + +template +struct Rect; + +using Rect64 = Rect; +using RectD = Rect; + +template +struct Rect { + T left; + T top; + T right; + T bottom; + + Rect() : + left(0), + top(0), + right(0), + bottom(0) {} + + Rect(T l, T t, T r, T b) : + left(l), + top(t), + right(r), + bottom(b) {} + + + T Width() const { return right - left; } + T Height() const { return bottom - top; } + void Width(T width) { right = left + width; } + void Height(T height) { bottom = top + height; } + + Point MidPoint() const + { + return Point((left + right) / 2, (top + bottom) / 2); + } + + Path AsPath() const + { + Path result; + result.reserve(4); + result.push_back(Point(left, top)); + result.push_back(Point(right, top)); + result.push_back(Point(right, bottom)); + result.push_back(Point(left, bottom)); + return result; + } + + bool Contains(const Point& pt) const + { + return pt.x > left && pt.x < right&& pt.y > top && pt.y < bottom; + } + + bool Contains(const Rect& rec) const + { + return rec.left >= left && rec.right <= right && + rec.top >= top && rec.bottom <= bottom; + } + + void Scale(double scale) { + left *= scale; + top *= scale; + right *= scale; + bottom *= scale; + } + + bool IsEmpty() const { return bottom <= top || right <= left; }; + + bool Intersects(const Rect& rec) const + { + return (std::max(left, rec.left) < std::min(right, rec.right)) && + (std::max(top, rec.top) < std::min(bottom, rec.bottom)); + }; + + friend std::ostream &operator<<(std::ostream &os, const Rect &rect) { + os << "(" + << rect.left << "," << rect.top << "," << rect.right << "," << rect.bottom + << ")"; + return os; + } +}; + +template +inline Rect ScaleRect(const Rect& rect, double scale) +{ + Rect result; + + if constexpr (std::numeric_limits::is_integer && + !std::numeric_limits::is_integer) + { + result.left = static_cast(std::round(rect.left * scale)); + result.top = static_cast(std::round(rect.top * scale)); + result.right = static_cast(std::round(rect.right * scale)); + result.bottom = static_cast(std::round(rect.bottom * scale)); + } + else + { + result.left = rect.left * scale; + result.top = rect.top * scale; + result.right = rect.right * scale; + result.bottom = rect.bottom * scale; + } + return result; +} + +// clipper2Exception --------------------------------------------------------- + +#ifndef NO_EXCEPTIONS +class Clipper2Exception : public std::exception { +public: + explicit Clipper2Exception(const char *description) : + m_descr(description) {} + virtual const char *what() const throw() { return m_descr.c_str(); } + +private: + std::string m_descr; +}; +#endif + +// Miscellaneous ------------------------------------------------------------ + +inline void CheckPrecision(int& precision) +{ + if (precision >= -8 && precision <= 8) return; +#ifdef NO_EXCEPTIONS + precision = precision > 8 ? 8 : -8; +#else + throw Clipper2Exception(precision_error); +#endif +} + +template +inline double CrossProduct(const Point& pt1, const Point& pt2, const Point& pt3) { + return (static_cast(pt2.x - pt1.x) * static_cast(pt3.y - + pt2.y) - static_cast(pt2.y - pt1.y) * static_cast(pt3.x - pt2.x)); +} + +template +inline double CrossProduct(const Point& vec1, const Point& vec2) +{ + return static_cast(vec1.y * vec2.x) - static_cast(vec2.y * vec1.x); +} + +template +inline double DotProduct(const Point& pt1, const Point& pt2, const Point& pt3) { + return (static_cast(pt2.x - pt1.x) * static_cast(pt3.x - pt2.x) + + static_cast(pt2.y - pt1.y) * static_cast(pt3.y - pt2.y)); +} + +template +inline double DotProduct(const Point& vec1, const Point& vec2) +{ + return static_cast(vec1.x * vec2.x) + static_cast(vec1.y * vec2.y); +} + +template +inline double DistanceSqr(const Point pt1, const Point pt2) +{ + return Sqr(pt1.x - pt2.x) + Sqr(pt1.y - pt2.y); +} + +template +inline double DistanceFromLineSqrd(const Point& pt, const Point& ln1, const Point& ln2) +{ + //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) + //see http://en.wikipedia.org/wiki/Perpendicular_distance + double A = static_cast(ln1.y - ln2.y); + double B = static_cast(ln2.x - ln1.x); + double C = A * ln1.x + B * ln1.y; + C = A * pt.x + B * pt.y - C; + return (C * C) / (A * A + B * B); +} + +template +inline double Area(const Path& path) +{ + size_t cnt = path.size(); + if (cnt < 3) return 0.0; + double a = 0.0; + typename Path::const_iterator it1, it2 = path.cend() - 1, stop = it2; + if (!(cnt & 1)) ++stop; + for (it1 = path.cbegin(); it1 != stop;) + { + a += static_cast(it2->y + it1->y) * (it2->x - it1->x); + it2 = it1 + 1; + a += static_cast(it1->y + it2->y) * (it1->x - it2->x); + it1 += 2; + } + if (cnt & 1) + a += static_cast(it2->y + it1->y) * (it2->x - it1->x); + return a * 0.5; +} + +template +inline double Area(const Paths& paths) +{ + double a = 0.0; + for (typename Paths::const_iterator paths_iter = paths.cbegin(); + paths_iter != paths.cend(); ++paths_iter) + { + a += Area(*paths_iter); + } + return a; +} + +template +inline bool IsPositive(const Path& poly) +{ + // A curve has positive orientation [and area] if a region 'R' + // is on the left when traveling around the outside of 'R'. + //https://mathworld.wolfram.com/CurveOrientation.html + //nb: This statement is premised on using Cartesian coordinates + return Area(poly) >= 0; +} + +inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b, + const Point64& seg2a, const Point64& seg2b, bool inclusive = false) +{ + if (inclusive) + { + double res1 = CrossProduct(seg1a, seg2a, seg2b); + double res2 = CrossProduct(seg1b, seg2a, seg2b); + if (res1 * res2 > 0) return false; + double res3 = CrossProduct(seg2a, seg1a, seg1b); + double res4 = CrossProduct(seg2b, seg1a, seg1b); + if (res3 * res4 > 0) return false; + return (res1 || res2 || res3 || res4); // ensures not collinear + } + else { + double dx1 = static_cast(seg1a.x - seg1b.x); + double dy1 = static_cast(seg1a.y - seg1b.y); + double dx2 = static_cast(seg2a.x - seg2b.x); + double dy2 = static_cast(seg2a.y - seg2b.y); + return (((dy1 * (seg2a.x - seg1a.x) - dx1 * (seg2a.y - seg1a.y)) * + (dy1 * (seg2b.x - seg1a.x) - dx1 * (seg2b.y - seg1a.y)) < 0) && + ((dy2 * (seg1a.x - seg2a.x) - dx2 * (seg1a.y - seg2a.y)) * + (dy2 * (seg1b.x - seg2a.x) - dx2 * (seg1b.y - seg2a.y)) < 0)); + } +} + + +enum class PointInPolygonResult { IsOn, IsInside, IsOutside }; + +template +inline PointInPolygonResult PointInPolygon(const Point& pt, const Path& polygon) +{ + if (polygon.size() < 3) + return PointInPolygonResult::IsOutside; + + int val = 0; + typename Path::const_iterator start = polygon.cbegin(), cit = start; + typename Path::const_iterator cend = polygon.cend(), pit = cend - 1; + + while (pit->y == pt.y) + { + if (pit == start) return PointInPolygonResult::IsOutside; + --pit; + } + bool is_above = pit->y < pt.y; + + while (cit != cend) + { + if (is_above) + { + while (cit != cend && cit->y < pt.y) ++cit; + if (cit == cend) break; + } + else + { + while (cit != cend && cit->y > pt.y) ++cit; + if (cit == cend) break; + } + + if (cit == start) pit = cend - 1; + else pit = cit - 1; + + if (cit->y == pt.y) + { + if (cit->x == pt.x || (cit->y == pit->y && + ((pt.x < pit->x) != (pt.x < cit->x)))) + return PointInPolygonResult::IsOn; + ++cit; + continue; + } + + if (pt.x < cit->x && pt.x < pit->x) + { + // we're only interested in edges crossing on the left + } + else if (pt.x > pit->x && pt.x > cit->x) + val = 1 - val; // toggle val + else + { + double d = CrossProduct(*pit, *cit, pt); + if (d == 0) return PointInPolygonResult::IsOn; + if ((d < 0) == is_above) val = 1 - val; + } + is_above = !is_above; + ++cit; + } + return (val == 0) ? + PointInPolygonResult::IsOutside : + PointInPolygonResult::IsInside; +} + +} // namespace + +#endif // CLIPPER_CORE_H diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h new file mode 100644 index 0000000000..34e216ac5a --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.engine.h @@ -0,0 +1,586 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 4 November 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : This is the main polygon clipping module * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_ENGINE_H +#define CLIPPER_ENGINE_H + +constexpr auto CLIPPER2_VERSION = "1.0.6"; + +#include +#include +#include +#include +#include +#include "clipper.core.h" + +namespace Clipper2Lib { + + struct Scanline; + struct IntersectNode; + struct Active; + struct Vertex; + struct LocalMinima; + struct OutRec; + struct Joiner; + + //Note: all clipping operations except for Difference are commutative. + enum class ClipType { None, Intersection, Union, Difference, Xor }; + + enum class PathType { Subject, Clip }; + + enum class VertexFlags : uint32_t { + None = 0, OpenStart = 1, OpenEnd = 2, LocalMax = 4, LocalMin = 8 + }; + + constexpr enum VertexFlags operator &(enum VertexFlags a, enum VertexFlags b) + { + return (enum VertexFlags)(uint32_t(a) & uint32_t(b)); + } + + constexpr enum VertexFlags operator |(enum VertexFlags a, enum VertexFlags b) + { + return (enum VertexFlags)(uint32_t(a) | uint32_t(b)); + } + + struct Vertex { + Point64 pt; + Vertex* next = nullptr; + Vertex* prev = nullptr; + VertexFlags flags = VertexFlags::None; + }; + + struct OutPt { + Point64 pt; + OutPt* next = nullptr; + OutPt* prev = nullptr; + OutRec* outrec; + Joiner* joiner = nullptr; + + OutPt(const Point64& pt_, OutRec* outrec_): pt(pt_), outrec(outrec_) { + next = this; + prev = this; + } + }; + + class PolyPath; + class PolyPath64; + class PolyPathD; + using PolyTree64 = PolyPath64; + using PolyTreeD = PolyPathD; + + struct OutRec; + typedef std::vector OutRecList; + + //OutRec: contains a path in the clipping solution. Edges in the AEL will + //have OutRec pointers assigned when they form part of the clipping solution. + struct OutRec { + size_t idx = 0; + OutRec* owner = nullptr; + OutRecList* splits = nullptr; + Active* front_edge = nullptr; + Active* back_edge = nullptr; + OutPt* pts = nullptr; + PolyPath* polypath = nullptr; + Rect64 bounds = {}; + Path64 path; + bool is_open = false; + ~OutRec() { if (splits) delete splits; }; + }; + + /////////////////////////////////////////////////////////////////// + //Important: UP and DOWN here are premised on Y-axis positive down + //displays, which is the orientation used in Clipper's development. + /////////////////////////////////////////////////////////////////// + + struct Active { + Point64 bot; + Point64 top; + int64_t curr_x = 0; //current (updated at every new scanline) + double dx = 0.0; + int wind_dx = 1; //1 or -1 depending on winding direction + int wind_cnt = 0; + int wind_cnt2 = 0; //winding count of the opposite polytype + OutRec* outrec = nullptr; + //AEL: 'active edge list' (Vatti's AET - active edge table) + // a linked list of all edges (from left to right) that are present + // (or 'active') within the current scanbeam (a horizontal 'beam' that + // sweeps from bottom to top over the paths in the clipping operation). + Active* prev_in_ael = nullptr; + Active* next_in_ael = nullptr; + //SEL: 'sorted edge list' (Vatti's ST - sorted table) + // linked list used when sorting edges into their new positions at the + // top of scanbeams, but also (re)used to process horizontals. + Active* prev_in_sel = nullptr; + Active* next_in_sel = nullptr; + Active* jump = nullptr; + Vertex* vertex_top = nullptr; + LocalMinima* local_min = nullptr; // the bottom of an edge 'bound' (also Vatti) + bool is_left_bound = false; + }; + + struct LocalMinima { + Vertex* vertex; + PathType polytype; + bool is_open; + LocalMinima(Vertex* v, PathType pt, bool open) : + vertex(v), polytype(pt), is_open(open){} + }; + + struct IntersectNode { + Point64 pt; + Active* edge1; + Active* edge2; + IntersectNode() : pt(Point64(0, 0)), edge1(NULL), edge2(NULL) {} + IntersectNode(Active* e1, Active* e2, Point64& pt_) : + pt(pt_), edge1(e1), edge2(e2) + { + } + }; + +#ifdef USINGZ + typedef std::function ZCallback64; + + typedef std::function ZCallbackD; +#endif + + // ClipperBase ------------------------------------------------------------- + + class ClipperBase { + private: + ClipType cliptype_ = ClipType::None; + FillRule fillrule_ = FillRule::EvenOdd; + FillRule fillpos = FillRule::Positive; + int64_t bot_y_ = 0; + bool minima_list_sorted_ = false; + bool using_polytree_ = false; + Active* actives_ = nullptr; + Active *sel_ = nullptr; + Joiner *horz_joiners_ = nullptr; + std::vector minima_list_; //pointers in case of memory reallocs + std::vector::iterator current_locmin_iter_; + std::vector vertex_lists_; + std::priority_queue scanline_list_; + std::vector intersect_nodes_; + std::vector joiner_list_; //pointers in case of memory reallocs + void Reset(); + void InsertScanline(int64_t y); + bool PopScanline(int64_t &y); + bool PopLocalMinima(int64_t y, LocalMinima *&local_minima); + void DisposeAllOutRecs(); + void DisposeVerticesAndLocalMinima(); + void DeleteEdges(Active*& e); + void AddLocMin(Vertex &vert, PathType polytype, bool is_open); + bool IsContributingClosed(const Active &e) const; + inline bool IsContributingOpen(const Active &e) const; + void SetWindCountForClosedPathEdge(Active &edge); + void SetWindCountForOpenPathEdge(Active &e); + void InsertLocalMinimaIntoAEL(int64_t bot_y); + void InsertLeftEdge(Active &e); + inline void PushHorz(Active &e); + inline bool PopHorz(Active *&e); + inline OutPt* StartOpenPath(Active &e, const Point64& pt); + inline void UpdateEdgeIntoAEL(Active *e); + OutPt* IntersectEdges(Active &e1, Active &e2, const Point64& pt); + inline void DeleteFromAEL(Active &e); + inline void AdjustCurrXAndCopyToSEL(const int64_t top_y); + void DoIntersections(const int64_t top_y); + void AddNewIntersectNode(Active &e1, Active &e2, const int64_t top_y); + bool BuildIntersectList(const int64_t top_y); + void ProcessIntersectList(); + void SwapPositionsInAEL(Active& edge1, Active& edge2); + OutPt* AddOutPt(const Active &e, const Point64& pt); + OutPt* AddLocalMinPoly(Active &e1, Active &e2, + const Point64& pt, bool is_new = false); + OutPt* AddLocalMaxPoly(Active &e1, Active &e2, const Point64& pt); + void DoHorizontal(Active &horz); + bool ResetHorzDirection(const Active &horz, const Active *max_pair, + int64_t &horz_left, int64_t &horz_right); + void DoTopOfScanbeam(const int64_t top_y); + Active *DoMaxima(Active &e); + void JoinOutrecPaths(Active &e1, Active &e2); + void CompleteSplit(OutPt* op1, OutPt* op2, OutRec& outrec); + bool ValidateClosedPathEx(OutPt*& outrec); + void CleanCollinear(OutRec* outrec); + void FixSelfIntersects(OutRec* outrec); + void DoSplitOp(OutRec* outRec, OutPt* splitOp); + Joiner* GetHorzTrialParent(const OutPt* op); + bool OutPtInTrialHorzList(OutPt* op); + void SafeDisposeOutPts(OutPt*& op); + void SafeDeleteOutPtJoiners(OutPt* op); + void AddTrialHorzJoin(OutPt* op); + void DeleteTrialHorzJoin(OutPt* op); + void ConvertHorzTrialsToJoins(); + void AddJoin(OutPt* op1, OutPt* op2); + void DeleteJoin(Joiner* joiner); + void ProcessJoinerList(); + OutRec* ProcessJoin(Joiner* joiner); + protected: + bool has_open_paths_ = false; + bool succeeded_ = true; + std::vector outrec_list_; //pointers in case list memory reallocated + bool ExecuteInternal(ClipType ct, FillRule ft, bool use_polytrees); + bool DeepCheckOwner(OutRec* outrec, OutRec* owner); +#ifdef USINGZ + ZCallback64 zCallback_ = nullptr; + void SetZ(const Active& e1, const Active& e2, Point64& pt); +#endif + void CleanUp(); // unlike Clear, CleanUp preserves added paths + void AddPath(const Path64& path, PathType polytype, bool is_open); + void AddPaths(const Paths64& paths, PathType polytype, bool is_open); + public: + virtual ~ClipperBase(); + bool PreserveCollinear = true; + bool ReverseSolution = false; + void Clear(); + }; + + // PolyPath / PolyTree -------------------------------------------------------- + + //PolyTree: is intended as a READ-ONLY data structure for CLOSED paths returned + //by clipping operations. While this structure is more complex than the + //alternative Paths structure, it does preserve path 'ownership' - ie those + //paths that contain (or own) other paths. This will be useful to some users. + + class PolyPath { + protected: + PolyPath* parent_; + public: + PolyPath(PolyPath* parent = nullptr): parent_(parent){} + virtual ~PolyPath() { Clear(); }; + //https://en.cppreference.com/w/cpp/language/rule_of_three + PolyPath(const PolyPath&) = delete; + PolyPath& operator=(const PolyPath&) = delete; + + unsigned Level() const + { + unsigned result = 0; + const PolyPath* p = parent_; + while (p) { ++result; p = p->parent_; } + return result; + } + + virtual PolyPath* AddChild(const Path64& path) = 0; + + virtual void Clear() {}; + virtual size_t Count() const { return 0; } + + const PolyPath* Parent() const { return parent_; } + + bool IsHole() const + { + const PolyPath* pp = parent_; + bool is_hole = pp; + while (pp) { + is_hole = !is_hole; + pp = pp->parent_; + } + return is_hole; + } + }; + + class PolyPath64 : public PolyPath { + private: + std::vector childs_; + Path64 polygon_; + typedef typename std::vector::const_iterator pp64_itor; + public: + PolyPath64(PolyPath64* parent = nullptr) : PolyPath(parent) {} + PolyPath64* operator [] (size_t index) { return static_cast(childs_[index]); } + pp64_itor begin() const { return childs_.cbegin(); } + pp64_itor end() const { return childs_.cend(); } + + PolyPath64* AddChild(const Path64& path) override + { + PolyPath64* result = new PolyPath64(this); + childs_.push_back(result); + result->polygon_ = path; + return result; + } + + void Clear() override + { + for (const PolyPath64* child : childs_) delete child; + childs_.resize(0); + } + + size_t Count() const override + { + return childs_.size(); + } + + const Path64& Polygon() const { return polygon_; }; + + double Area() const + { + double result = Clipper2Lib::Area(polygon_); + for (const PolyPath64* child : childs_) + result += child->Area(); + return result; + } + + friend std::ostream& operator << (std::ostream& outstream, const PolyPath64& polypath) + { + const size_t level_indent = 4; + const size_t coords_per_line = 4; + const size_t last_on_line = coords_per_line - 1; + unsigned level = polypath.Level(); + if (level > 0) + { + std::string level_padding; + level_padding.insert(0, (level - 1) * level_indent, ' '); + std::string caption = polypath.IsHole() ? "Hole " : "Outer Polygon "; + std::string childs = polypath.Count() == 1 ? " child" : " children"; + outstream << level_padding.c_str() << caption << "with " << polypath.Count() << childs << std::endl; + outstream << level_padding; + size_t i = 0, highI = polypath.Polygon().size() - 1; + for (; i < highI; ++i) + { + outstream << polypath.Polygon()[i] << ' '; + if ((i % coords_per_line) == last_on_line) + outstream << std::endl << level_padding; + } + if (highI > 0) outstream << polypath.Polygon()[i]; + outstream << std::endl; + } + for (auto child : polypath) + outstream << *child; + return outstream; + } + + }; + + class PolyPathD : public PolyPath { + private: + std::vector childs_; + double inv_scale_; + PathD polygon_; + typedef typename std::vector::const_iterator ppD_itor; + public: + PolyPathD(PolyPathD* parent = nullptr) : PolyPath(parent) + { + inv_scale_ = parent ? parent->inv_scale_ : 1.0; + } + PolyPathD* operator [] (size_t index) + { + return static_cast(childs_[index]); + } + ppD_itor begin() const { return childs_.cbegin(); } + ppD_itor end() const { return childs_.cend(); } + + void SetInvScale(double value) { inv_scale_ = value; } + double InvScale() { return inv_scale_; } + PolyPathD* AddChild(const Path64& path) override + { + PolyPathD* result = new PolyPathD(this); + childs_.push_back(result); + result->polygon_ = ScalePath(path, inv_scale_); + return result; + } + + void Clear() override + { + for (const PolyPathD* child : childs_) delete child; + childs_.resize(0); + } + + size_t Count() const override + { + return childs_.size(); + } + + const PathD& Polygon() const { return polygon_; }; + + double Area() const + { + double result = Clipper2Lib::Area(polygon_); + for (const PolyPathD* child : childs_) + result += child->Area(); + return result; + } + }; + + class Clipper64 : public ClipperBase + { + private: + void BuildPaths64(Paths64& solutionClosed, Paths64* solutionOpen); + void BuildTree64(PolyPath64& polytree, Paths64& open_paths); + public: +#ifdef USINGZ + void SetZCallback(ZCallback64 cb) { zCallback_ = cb; } +#endif + + void AddSubject(const Paths64& subjects) + { + AddPaths(subjects, PathType::Subject, false); + } + void AddOpenSubject(const Paths64& open_subjects) + { + AddPaths(open_subjects, PathType::Subject, true); + } + void AddClip(const Paths64& clips) + { + AddPaths(clips, PathType::Clip, false); + } + + bool Execute(ClipType clip_type, + FillRule fill_rule, Paths64& closed_paths) + { + Paths64 dummy; + return Execute(clip_type, fill_rule, closed_paths, dummy); + } + + bool Execute(ClipType clip_type, FillRule fill_rule, + Paths64& closed_paths, Paths64& open_paths) + { + closed_paths.clear(); + open_paths.clear(); + if (ExecuteInternal(clip_type, fill_rule, false)) + BuildPaths64(closed_paths, &open_paths); + CleanUp(); + return succeeded_; + } + + bool Execute(ClipType clip_type, FillRule fill_rule, PolyTree64& polytree) + { + Paths64 dummy; + return Execute(clip_type, fill_rule, polytree, dummy); + } + + bool Execute(ClipType clip_type, + FillRule fill_rule, PolyTree64& polytree, Paths64& open_paths) + { + if (ExecuteInternal(clip_type, fill_rule, true)) + { + open_paths.clear(); + polytree.Clear(); + BuildTree64(polytree, open_paths); + } + CleanUp(); + return succeeded_; + } + }; + + class ClipperD : public ClipperBase { + private: + double scale_ = 1.0, invScale_ = 1.0; +#ifdef USINGZ + ZCallbackD zCallback_ = nullptr; +#endif + void BuildPathsD(PathsD& solutionClosed, PathsD* solutionOpen); + void BuildTreeD(PolyPathD& polytree, PathsD& open_paths); + public: + explicit ClipperD(int precision = 2) : ClipperBase() + { + CheckPrecision(precision); + // to optimize scaling / descaling precision + // set the scale to a power of double's radix (2) (#25) + scale_ = std::pow(std::numeric_limits::radix, + std::ilogb(std::pow(10, precision)) + 1); + invScale_ = 1 / scale_; + } + +#ifdef USINGZ + void SetZCallback(ZCallbackD cb) { zCallback_ = cb; }; + + void ZCB(const Point64& e1bot, const Point64& e1top, + const Point64& e2bot, const Point64& e2top, Point64& pt) + { + // de-scale (x & y) + // temporarily convert integers to their initial float values + // this will slow clipping marginally but will make it much easier + // to understand the coordinates passed to the callback function + PointD tmp = PointD(pt) * invScale_; + PointD e1b = PointD(e1bot) * invScale_; + PointD e1t = PointD(e1top) * invScale_; + PointD e2b = PointD(e2bot) * invScale_; + PointD e2t = PointD(e2top) * invScale_; + zCallback_(e1b,e1t, e2b, e2t, tmp); + pt.z = tmp.z; // only update 'z' + }; + + void CheckCallback() + { + if(zCallback_) + // if the user defined float point callback has been assigned + // then assign the proxy callback function + ClipperBase::zCallback_ = + std::bind(&ClipperD::ZCB, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4, std::placeholders::_5); + else + ClipperBase::zCallback_ = nullptr; + } + +#endif + + void AddSubject(const PathsD& subjects) + { + AddPaths(ScalePaths(subjects, scale_), PathType::Subject, false); + } + + void AddOpenSubject(const PathsD& open_subjects) + { + AddPaths(ScalePaths(open_subjects, scale_), PathType::Subject, true); + } + + void AddClip(const PathsD& clips) + { + AddPaths(ScalePaths(clips, scale_), PathType::Clip, false); + } + + bool Execute(ClipType clip_type, FillRule fill_rule, PathsD& closed_paths) + { + PathsD dummy; + return Execute(clip_type, fill_rule, closed_paths, dummy); + } + + bool Execute(ClipType clip_type, + FillRule fill_rule, PathsD& closed_paths, PathsD& open_paths) + { +#ifdef USINGZ + CheckCallback(); +#endif + if (ExecuteInternal(clip_type, fill_rule, false)) + { + BuildPathsD(closed_paths, &open_paths); + } + CleanUp(); + return succeeded_; + } + + bool Execute(ClipType clip_type, FillRule fill_rule, PolyTreeD& polytree) + { + PathsD dummy; + return Execute(clip_type, fill_rule, polytree, dummy); + } + + bool Execute(ClipType clip_type, + FillRule fill_rule, PolyTreeD& polytree, PathsD& open_paths) + { +#ifdef USINGZ + CheckCallback(); +#endif + if (ExecuteInternal(clip_type, fill_rule, true)) + { + polytree.Clear(); + polytree.SetInvScale(invScale_); + open_paths.clear(); + BuildTreeD(polytree, open_paths); + } + CleanUp(); + return succeeded_; + } + + }; + +} // namespace + +#endif // CLIPPER_ENGINE_H diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h new file mode 100644 index 0000000000..e20ac91332 --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.export.h @@ -0,0 +1,830 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 30 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : This module exports the Clipper2 Library (ie DLL/so) * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +// The exported functions below refer to simple structures that +// can be understood across multiple languages. Consequently +// Path64, PathD, Polytree64 etc are converted from C++ classes +// (std::vector<> etc) into the following data structures: +// +// CPath64 (int64_t*) & CPathD (double_t*): +// Path64 and PathD are converted into arrays of x,y coordinates. +// However in these arrays the first x,y coordinate pair is a +// counter with 'x' containing the number of following coordinate +// pairs. ('y' should be 0, with one exception explained below.) +// __________________________________ +// |counter|coord1|coord2|...|coordN| +// |N ,0 |x1, y1|x2, y2|...|xN, yN| +// __________________________________ +// +// CPaths64 (int64_t**) & CPathsD (double_t**): +// These are arrays of pointers to CPath64 and CPathD where +// the first pointer is to a 'counter path'. This 'counter +// path' has a single x,y coord pair with 'y' (not 'x') +// containing the number of paths that follow. ('x' = 0). +// _______________________________ +// |counter|path1|path2|...|pathN| +// |addr0 |addr1|addr2|...|addrN| (*addr0[0]=0; *addr0[1]=N) +// _______________________________ +// +// The structures of CPolytree64 and CPolytreeD are defined +// below and these structures don't need to be explained here. + +#ifndef CLIPPER2_EXPORT_H +#define CLIPPER2_EXPORT_H + +#include +#include + +#include "clipper2/clipper.core.h" +#include "clipper2/clipper.engine.h" +#include "clipper2/clipper.offset.h" +#include "clipper2/clipper.rectclip.h" + +namespace Clipper2Lib { + +typedef int64_t* CPath64; +typedef int64_t** CPaths64; +typedef double* CPathD; +typedef double** CPathsD; + +typedef struct CPolyPath64 { + CPath64 polygon; + uint32_t is_hole; + uint32_t child_count; + CPolyPath64* childs; +} +CPolyTree64; + +typedef struct CPolyPathD { + CPathD polygon; + uint32_t is_hole; + uint32_t child_count; + CPolyPathD* childs; +} +CPolyTreeD; + +template +struct CRect { + T left; + T top; + T right; + T bottom; +}; + +typedef CRect CRect64; +typedef CRect CRectD; + +template +inline bool CRectIsEmpty(const CRect& rect) +{ + return (rect.right <= rect.left) || (rect.bottom <= rect.top); +} + +template +inline Rect CRectToRect(const CRect& rect) +{ + Rect result; + result.left = rect.left; + result.top = rect.top; + result.right = rect.right; + result.bottom = rect.bottom; + return result; +} + +#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport) + +////////////////////////////////////////////////////// +// EXPORTED FUNCTION DEFINITIONS +////////////////////////////////////////////////////// + +EXTERN_DLL_EXPORT const char* Version(); + +// Some of the functions below will return data in the various CPath +// and CPolyTree structures which are pointers to heap allocated +// memory. Eventually this memory will need to be released with one +// of the following 'DisposeExported' functions. (This may be the +// only safe way to release this memory since the executable +// accessing these exported functions may use a memory manager that +// allocates and releases heap memory in a different way. Also, +// CPath structures that have been constructed by the executable +// should not be destroyed using these 'DisposeExported' functions.) +EXTERN_DLL_EXPORT void DisposeExportedCPath64(CPath64 p); +EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& pp); +EXTERN_DLL_EXPORT void DisposeExportedCPathD(CPathD p); +EXTERN_DLL_EXPORT void DisposeExportedCPathsD(CPathsD& pp); +EXTERN_DLL_EXPORT void DisposeExportedCPolyTree64(CPolyTree64*& cpt); +EXTERN_DLL_EXPORT void DisposeExportedCPolyTreeD(CPolyTreeD*& cpt); + +// Boolean clipping: +// cliptype: None=0, Intersection=1, Union=2, Difference=3, Xor=4 +// fillrule: EvenOdd=0, NonZero=1, Positive=2, Negative=3 +EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype, + uint8_t fillrule, const CPaths64 subjects, + const CPaths64 subjects_open, const CPaths64 clips, + CPaths64& solution, CPaths64& solution_open, + bool preserve_collinear = true, bool reverse_solution = false); +EXTERN_DLL_EXPORT int BooleanOpPt64(uint8_t cliptype, + uint8_t fillrule, const CPaths64 subjects, + const CPaths64 subjects_open, const CPaths64 clips, + CPolyTree64*& solution, CPaths64& solution_open, + bool preserve_collinear = true, bool reverse_solution = false); +EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype, + uint8_t fillrule, const CPathsD subjects, + const CPathsD subjects_open, const CPathsD clips, + CPathsD& solution, CPathsD& solution_open, int precision = 2, + bool preserve_collinear = true, bool reverse_solution = false); +EXTERN_DLL_EXPORT int BooleanOpPtD(uint8_t cliptype, + uint8_t fillrule, const CPathsD subjects, + const CPathsD subjects_open, const CPathsD clips, + CPolyTreeD*& solution, CPathsD& solution_open, int precision = 2, + bool preserve_collinear = true, bool reverse_solution = false); + +// Polygon offsetting (inflate/deflate): +// jointype: Square=0, Round=1, Miter=2 +// endtype: Polygon=0, Joined=1, Butt=2, Square=3, Round=4 +EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths, + double delta, uint8_t jointype, uint8_t endtype, + double miter_limit = 2.0, double arc_tolerance = 0.0, + bool reverse_solution = false); +EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths, + double delta, uint8_t jointype, uint8_t endtype, + int precision = 2, double miter_limit = 2.0, + double arc_tolerance = 0.0, bool reverse_solution = false); + +// RectClip & RectClipLines: +EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, + const CPaths64 paths); +EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect, + const CPathsD paths, int precision = 2); +EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect, + const CPaths64 paths); +EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect, + const CPathsD paths, int precision = 2); + +////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +////////////////////////////////////////////////////// + +inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2); +inline CPath64 CreateCPath64(const Path64& p); +inline CPaths64 CreateCPaths64(const Paths64& pp); +inline Path64 ConvertCPath64(const CPath64& p); +inline Paths64 ConvertCPaths64(const CPaths64& pp); + +inline CPathD CreateCPathD(size_t cnt1, size_t cnt2); +inline CPathD CreateCPathD(const PathD& p); +inline CPathsD CreateCPathsD(const PathsD& pp); +inline PathD ConvertCPathD(const CPathD& p); +inline PathsD ConvertCPathsD(const CPathsD& pp); + +// the following function avoid multiple conversions +inline CPathD CreateCPathD(const Path64& p, double scale); +inline CPathsD CreateCPathsD(const Paths64& pp, double scale); +inline Path64 ConvertCPathD(const CPathD& p, double scale); +inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale); + +inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt); +inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale); + +EXTERN_DLL_EXPORT const char* Version() +{ + return CLIPPER2_VERSION; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPath64(CPath64 p) +{ + if (p) delete[] p; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPaths64(CPaths64& pp) +{ + if (!pp) return; + CPaths64 v = pp; + CPath64 cnts = *v; + const size_t cnt = static_cast(cnts[1]); + for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1 + DisposeExportedCPath64(*v++); + delete[] pp; + pp = nullptr; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPathD(CPathD p) +{ + if (p) delete[] p; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPathsD(CPathsD& pp) +{ + if (!pp) return; + CPathsD v = pp; + CPathD cnts = *v; + size_t cnt = static_cast(cnts[1]); + for (size_t i = 0; i <= cnt; ++i) //nb: cnt +1 + DisposeExportedCPathD(*v++); + delete[] pp; + pp = nullptr; +} + +EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype, + uint8_t fillrule, const CPaths64 subjects, + const CPaths64 subjects_open, const CPaths64 clips, + CPaths64& solution, CPaths64& solution_open, + bool preserve_collinear, bool reverse_solution) +{ + if (cliptype > static_cast(ClipType::Xor)) return -4; + if (fillrule > static_cast(FillRule::Negative)) return -3; + + Paths64 sub, sub_open, clp, sol, sol_open; + sub = ConvertCPaths64(subjects); + sub_open = ConvertCPaths64(subjects_open); + clp = ConvertCPaths64(clips); + + Clipper64 clipper; + clipper.PreserveCollinear = preserve_collinear; + clipper.ReverseSolution = reverse_solution; + if (sub.size() > 0) clipper.AddSubject(sub); + if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); + if (clp.size() > 0) clipper.AddClip(clp); + if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open)) + return -1; // clipping bug - should never happen :) + solution = CreateCPaths64(sol); + solution_open = CreateCPaths64(sol_open); + return 0; //success !! +} + +EXTERN_DLL_EXPORT int BooleanOpPt64(uint8_t cliptype, + uint8_t fillrule, const CPaths64 subjects, + const CPaths64 subjects_open, const CPaths64 clips, + CPolyTree64*& solution, CPaths64& solution_open, + bool preserve_collinear, bool reverse_solution) +{ + if (cliptype > static_cast(ClipType::Xor)) return -4; + if (fillrule > static_cast(FillRule::Negative)) return -3; + Paths64 sub, sub_open, clp, sol_open; + sub = ConvertCPaths64(subjects); + sub_open = ConvertCPaths64(subjects_open); + clp = ConvertCPaths64(clips); + + PolyTree64 pt; + Clipper64 clipper; + clipper.PreserveCollinear = preserve_collinear; + clipper.ReverseSolution = reverse_solution; + if (sub.size() > 0) clipper.AddSubject(sub); + if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open); + if (clp.size() > 0) clipper.AddClip(clp); + if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), pt, sol_open)) + return -1; // clipping bug - should never happen :) + + solution = CreateCPolyTree64(pt); + solution_open = CreateCPaths64(sol_open); + return 0; //success !! +} + +EXTERN_DLL_EXPORT int BooleanOpD(uint8_t cliptype, + uint8_t fillrule, const CPathsD subjects, + const CPathsD subjects_open, const CPathsD clips, + CPathsD& solution, CPathsD& solution_open, int precision, + bool preserve_collinear, bool reverse_solution) +{ + if (precision < -8 || precision > 8) return -5; + if (cliptype > static_cast(ClipType::Xor)) return -4; + if (fillrule > static_cast(FillRule::Negative)) return -3; + const double scale = std::pow(10, precision); + + Paths64 sub, sub_open, clp, sol, sol_open; + sub = ConvertCPathsD(subjects, scale); + sub_open = ConvertCPathsD(subjects_open, scale); + clp = ConvertCPathsD(clips, scale); + + Clipper64 clipper; + clipper.PreserveCollinear = preserve_collinear; + clipper.ReverseSolution = reverse_solution; + if (sub.size() > 0) clipper.AddSubject(sub); + if (sub_open.size() > 0) + clipper.AddOpenSubject(sub_open); + if (clp.size() > 0) clipper.AddClip(clp); + if (!clipper.Execute(ClipType(cliptype), + FillRule(fillrule), sol, sol_open)) return -1; + + if (sol.size() > 0) solution = CreateCPathsD(sol, 1 / scale); + if (sol_open.size() > 0) + solution_open = CreateCPathsD(sol_open, 1 / scale); + return 0; +} + +EXTERN_DLL_EXPORT int BooleanOpPtD(uint8_t cliptype, + uint8_t fillrule, const CPathsD subjects, + const CPathsD subjects_open, const CPathsD clips, + CPolyTreeD*& solution, CPathsD& solution_open, int precision, + bool preserve_collinear, bool reverse_solution) +{ + if (precision < -8 || precision > 8) return -5; + if (cliptype > static_cast(ClipType::Xor)) return -4; + if (fillrule > static_cast(FillRule::Negative)) return -3; + + const double scale = std::pow(10, precision); + Paths64 sub, sub_open, clp, sol_open; + sub = ConvertCPathsD(subjects, scale); + sub_open = ConvertCPathsD(subjects_open, scale); + clp = ConvertCPathsD(clips, scale); + + PolyTree64 sol; + Clipper64 clipper; + clipper.PreserveCollinear = preserve_collinear; + clipper.ReverseSolution = reverse_solution; + if (sub.size() > 0) clipper.AddSubject(sub); + if (sub_open.size() > 0) + clipper.AddOpenSubject(sub_open); + if (clp.size() > 0) clipper.AddClip(clp); + if (!clipper.Execute(ClipType(cliptype), + FillRule(fillrule), sol, sol_open)) return -1; + + solution = CreateCPolyTreeD(sol, 1 / scale); + if (sol_open.size() > 0) + solution_open = CreateCPathsD(sol_open, 1 / scale); + return 0; +} + +EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths, + double delta, uint8_t jointype, uint8_t endtype, double miter_limit, + double arc_tolerance, bool reverse_solution) +{ + Paths64 pp; + pp = ConvertCPaths64(paths); + + ClipperOffset clip_offset( miter_limit, + arc_tolerance, reverse_solution); + clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype)); + Paths64 result = clip_offset.Execute(delta); + return CreateCPaths64(result); +} + +EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths, + double delta, uint8_t jointype, uint8_t endtype, + int precision, double miter_limit, + double arc_tolerance, bool reverse_solution) +{ + if (precision < -8 || precision > 8 || !paths) return nullptr; + const double scale = std::pow(10, precision); + ClipperOffset clip_offset(miter_limit, arc_tolerance, reverse_solution); + Paths64 pp = ConvertCPathsD(paths, scale); + clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype)); + Paths64 result = clip_offset.Execute(delta * scale); + return CreateCPathsD(result, 1/scale); +} + +EXTERN_DLL_EXPORT CPaths64 RectClip64(const CRect64& rect, + const CPaths64 paths) +{ + if (CRectIsEmpty(rect) || !paths) return nullptr; + Rect64 r64 = CRectToRect(rect); + class RectClip rc(r64); + Paths64 pp = ConvertCPaths64(paths); + Paths64 result; + result.reserve(pp.size()); + for (const Path64& p : pp) + { + Rect64 pathRec = Bounds(p); + if (!r64.Intersects(pathRec)) continue; + + if (r64.Contains(pathRec)) + result.push_back(p); + else + { + Path64 p2 = rc.Execute(p); + if (!p2.empty()) result.push_back(std::move(p2)); + } + } + return CreateCPaths64(result); +} + +EXTERN_DLL_EXPORT CPathsD RectClipD(const CRectD& rect, + const CPathsD paths, int precision) +{ + if (CRectIsEmpty(rect) || !paths) return nullptr; + if (precision < -8 || precision > 8) return nullptr; + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(CRectToRect(rect), scale); + Paths64 pp = ConvertCPathsD(paths, scale); + class RectClip rc(r); + Paths64 result; + result.reserve(pp.size()); + for (const Path64& p : pp) + { + Rect64 pathRec = Bounds(p); + if (!r.Intersects(pathRec)) continue; + + if (r.Contains(pathRec)) + result.push_back(p); + else + { + Path64 p2 = rc.Execute(p); + if (!p2.empty()) result.push_back(std::move(p2)); + } + } + return CreateCPathsD(result, 1/scale); +} + +EXTERN_DLL_EXPORT CPaths64 RectClipLines64(const CRect64& rect, + const CPaths64 paths) +{ + if (CRectIsEmpty(rect) || !paths) return nullptr; + Rect64 r = CRectToRect(rect); + class RectClipLines rcl (r); + Paths64 pp = ConvertCPaths64(paths); + Paths64 result; + result.reserve(pp.size()); + + for (const Path64& p : pp) + { + Rect64 pathRec = Bounds(p); + if (!r.Intersects(pathRec)) continue; + + if (r.Contains(pathRec)) + result.push_back(p); + else + { + Paths64 pp2 = rcl.Execute(p); + if (!pp2.empty()) + result.insert(result.end(), pp2.begin(), pp2.end()); + } + } + return CreateCPaths64(result); +} + +EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect, + const CPathsD paths, int precision) +{ + Paths64 result; + if (CRectIsEmpty(rect) || !paths) return nullptr; + if (precision < -8 || precision > 8) return nullptr; + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(CRectToRect(rect), scale); + class RectClipLines rcl(r); + Paths64 pp = ConvertCPathsD(paths, scale); + + result.reserve(pp.size()); + for (const Path64& p : pp) + { + Rect64 pathRec = Bounds(p); + if (!r.Intersects(pathRec)) continue; + + if (r.Contains(pathRec)) + result.push_back(p); + else + { + Paths64 pp2 = rcl.Execute(p); + if (pp2.empty()) continue; + result.insert(result.end(), pp2.begin(), pp2.end()); + } + } + return CreateCPathsD(result, 1/scale); +} + +inline CPath64 CreateCPath64(size_t cnt1, size_t cnt2) +{ + // allocates memory for CPath64, fills in the counter, and + // returns the structure ready to be filled with path data + CPath64 result = new int64_t[2 + cnt1 *2]; + result[0] = cnt1; + result[1] = cnt2; + return result; +} + +inline CPath64 CreateCPath64(const Path64& p) +{ + // allocates memory for CPath64, fills the counter + // and returns the memory filled with path data + size_t cnt = p.size(); + if (!cnt) return nullptr; + CPath64 result = CreateCPath64(cnt, 0); + CPath64 v = result; + v += 2; // skip counters + for (const Point64& pt : p) + { + *v++ = pt.x; + *v++ = pt.y; + } + return result; +} + +inline Path64 ConvertCPath64(const CPath64& p) +{ + Path64 result; + if (p && *p) + { + CPath64 v = p; + const size_t cnt = static_cast(p[0]); + v += 2; // skip counters + result.reserve(cnt); + for (size_t i = 0; i < cnt; ++i) + { + // x,y here avoids right to left function evaluation + // result.push_back(Point64(*v++, *v++)); + int64_t x = *v++; + int64_t y = *v++; + result.push_back(Point64(x, y)); + } + } + return result; +} + +inline CPaths64 CreateCPaths64(const Paths64& pp) +{ + // allocates memory for multiple CPath64 and + // and returns this memory filled with path data + size_t cnt = pp.size(), cnt2 = cnt; + + // don't allocate space for empty paths + for (size_t i = 0; i < cnt; ++i) + if (!pp[i].size()) --cnt2; + if (!cnt2) return nullptr; + + CPaths64 result = new int64_t* [cnt2 + 1]; + CPaths64 v = result; + *v++ = CreateCPath64(0, cnt2); // assign a counter path + for (const Path64& p : pp) + { + *v = CreateCPath64(p); + if (*v) ++v; + } + return result; +} + +inline Paths64 ConvertCPaths64(const CPaths64& pp) +{ + Paths64 result; + if (pp) + { + CPaths64 v = pp; + CPath64 cnts = pp[0]; + const size_t cnt = static_cast(cnts[1]); // nb 2nd cnt + ++v; // skip cnts + result.reserve(cnt); + for (size_t i = 0; i < cnt; ++i) + result.push_back(ConvertCPath64(*v++)); + } + return result; +} + +inline CPathD CreateCPathD(size_t cnt1, size_t cnt2) +{ + // allocates memory for CPathD, fills in the counter, and + // returns the structure ready to be filled with path data + CPathD result = new double[2 + cnt1 * 2]; + result[0] = static_cast(cnt1); + result[1] = static_cast(cnt2); + return result; +} + +inline CPathD CreateCPathD(const PathD& p) +{ + // allocates memory for CPath, fills the counter + // and returns the memory fills with path data + size_t cnt = p.size(); + if (!cnt) return nullptr; + CPathD result = CreateCPathD(cnt, 0); + CPathD v = result; + v += 2; // skip counters + for (const PointD& pt : p) + { + *v++ = pt.x; + *v++ = pt.y; + } + return result; +} + +inline PathD ConvertCPathD(const CPathD& p) +{ + PathD result; + if (p) + { + CPathD v = p; + size_t cnt = static_cast(v[0]); + v += 2; // skip counters + result.reserve(cnt); + for (size_t i = 0; i < cnt; ++i) + { + // x,y here avoids right to left function evaluation + // result.push_back(PointD(*v++, *v++)); + double x = *v++; + double y = *v++; + result.push_back(PointD(x, y)); + } + } + return result; +} + +inline CPathsD CreateCPathsD(const PathsD& pp) +{ + size_t cnt = pp.size(), cnt2 = cnt; + // don't allocate space for empty paths + for (size_t i = 0; i < cnt; ++i) + if (!pp[i].size()) --cnt2; + if (!cnt2) return nullptr; + CPathsD result = new double * [cnt2 + 1]; + CPathsD v = result; + *v++ = CreateCPathD(0, cnt2); // assign counter path + for (const PathD& p : pp) + { + *v = CreateCPathD(p); + if (*v) { ++v; } + } + return result; +} + +inline PathsD ConvertCPathsD(const CPathsD& pp) +{ + PathsD result; + if (pp) + { + CPathsD v = pp; + CPathD cnts = v[0]; + size_t cnt = static_cast(cnts[1]); + ++v; // skip cnts path + result.reserve(cnt); + for (size_t i = 0; i < cnt; ++i) + result.push_back(ConvertCPathD(*v++)); + } + return result; +} + +inline Path64 ConvertCPathD(const CPathD& p, double scale) +{ + Path64 result; + if (p) + { + CPathD v = p; + size_t cnt = static_cast(*v); + v += 2; // skip counters + result.reserve(cnt); + for (size_t i = 0; i < cnt; ++i) + { + // x,y here avoids right to left function evaluation + // result.push_back(PointD(*v++, *v++)); + double x = *v++ * scale; + double y = *v++ * scale; + result.push_back(Point64(x, y)); + } + } + return result; +} + +inline Paths64 ConvertCPathsD(const CPathsD& pp, double scale) +{ + Paths64 result; + if (pp) + { + CPathsD v = pp; + CPathD cnts = v[0]; + size_t cnt = static_cast(cnts[1]); + result.reserve(cnt); + ++v; // skip cnts path + for (size_t i = 0; i < cnt; ++i) + result.push_back(ConvertCPathD(*v++, scale)); + } + return result; +} + +inline CPathD CreateCPathD(const Path64& p, double scale) +{ + // allocates memory for CPathD, fills in the counter, and + // returns the structure filled with *scaled* path data + size_t cnt = p.size(); + if (!cnt) return nullptr; + CPathD result = CreateCPathD(cnt, 0); + CPathD v = result; + v += 2; // skip cnts + for (const Point64& pt : p) + { + *v++ = pt.x * scale; + *v++ = pt.y * scale; + } + return result; +} + +inline CPathsD CreateCPathsD(const Paths64& pp, double scale) +{ + // allocates memory for *multiple* CPathD, and + // returns the structure filled with scaled path data + size_t cnt = pp.size(), cnt2 = cnt; + // don't allocate space for empty paths + for (size_t i = 0; i < cnt; ++i) + if (!pp[i].size()) --cnt2; + if (!cnt2) return nullptr; + CPathsD result = new double* [cnt2 + 1]; + CPathsD v = result; + *v++ = CreateCPathD(0, cnt2); + for (const Path64& p : pp) + { + *v = CreateCPathD(p, scale); + if (*v) ++v; + } + return result; +} + +inline void InitCPolyPath64(CPolyTree64* cpt, + bool is_hole, const PolyPath64* pp) +{ + cpt->polygon = CreateCPath64(pp->Polygon()); + cpt->is_hole = is_hole; + size_t child_cnt = pp->Count(); + cpt->child_count = static_cast(child_cnt); + cpt->childs = nullptr; + if (!child_cnt) return; + cpt->childs = new CPolyPath64[child_cnt]; + CPolyPath64* child = cpt->childs; + for (const PolyPath64* pp_child : *pp) + InitCPolyPath64(child++, !is_hole, pp_child); +} + +inline CPolyTree64* CreateCPolyTree64(const PolyTree64& pt) +{ + CPolyTree64* result = new CPolyTree64(); + result->polygon = nullptr; + result->is_hole = false; + size_t child_cnt = pt.Count(); + result->childs = nullptr; + result->child_count = static_cast(child_cnt); + if (!child_cnt) return result; + result->childs = new CPolyPath64[child_cnt]; + CPolyPath64* child = result->childs; + for (const PolyPath64* pp : pt) + InitCPolyPath64(child++, true, pp); + return result; +} + +inline void DisposeCPolyPath64(CPolyPath64* cpp) +{ + if (!cpp->child_count) return; + CPolyPath64* child = cpp->childs; + for (size_t i = 0; i < cpp->child_count; ++i) + DisposeCPolyPath64(child); + delete[] cpp->childs; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPolyTree64(CPolyTree64*& cpt) +{ + if (!cpt) return; + DisposeCPolyPath64(cpt); + delete cpt; + cpt = nullptr; +} + +inline void InitCPolyPathD(CPolyTreeD* cpt, + bool is_hole, const PolyPath64* pp, double scale) +{ + cpt->polygon = CreateCPathD(pp->Polygon(), scale); + cpt->is_hole = is_hole; + size_t child_cnt = pp->Count(); + cpt->child_count = static_cast(child_cnt); + cpt->childs = nullptr; + if (!child_cnt) return; + cpt->childs = new CPolyPathD[child_cnt]; + CPolyPathD* child = cpt->childs; + for (const PolyPath64* pp_child : *pp) + InitCPolyPathD(child++, !is_hole, pp_child, scale); +} + +inline CPolyTreeD* CreateCPolyTreeD(const PolyTree64& pt, double scale) +{ + CPolyTreeD* result = new CPolyTreeD(); + result->polygon = nullptr; + result->is_hole = false; + size_t child_cnt = pt.Count(); + result->child_count = static_cast(child_cnt); + result->childs = nullptr; + if (!child_cnt) return result; + result->childs = new CPolyPathD[child_cnt]; + CPolyPathD* child = result->childs; + for (const PolyPath64* pp : pt) + InitCPolyPathD(child++, true, pp, scale); + return result; +} + +inline void DisposeCPolyPathD(CPolyPathD* cpp) +{ + if (!cpp->child_count) return; + CPolyPathD* child = cpp->childs; + for (size_t i = 0; i < cpp->child_count; ++i) + DisposeCPolyPathD(child++); + delete[] cpp->childs; +} + +EXTERN_DLL_EXPORT void DisposeExportedCPolyTreeD(CPolyTreeD*& cpt) +{ + if (!cpt) return; + DisposeCPolyPathD(cpt); + delete cpt; + cpt = nullptr; +} + +} // end Clipper2Lib namespace + +#endif // CLIPPER2_EXPORT_H diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.h new file mode 100644 index 0000000000..8bebfcf3cd --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.h @@ -0,0 +1,762 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 29 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : This module provides a simple interface to the Clipper Library * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_H +#define CLIPPER_H + +#include +#include + +#include "clipper.core.h" +#include "clipper.engine.h" +#include "clipper.offset.h" +#include "clipper.minkowski.h" +#include "clipper.rectclip.h" + +namespace Clipper2Lib { + + static const Rect64 MaxInvalidRect64 = Rect64( + (std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::lowest)(), + (std::numeric_limits::lowest)()); + + static const RectD MaxInvalidRectD = RectD( + (std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::lowest)(), + (std::numeric_limits::lowest)()); + + inline Paths64 BooleanOp(ClipType cliptype, FillRule fillrule, + const Paths64& subjects, const Paths64& clips) + { + Paths64 result; + Clipper64 clipper; + clipper.AddSubject(subjects); + clipper.AddClip(clips); + clipper.Execute(cliptype, fillrule, result); + return result; + } + + inline void BooleanOp(ClipType cliptype, FillRule fillrule, + const Paths64& subjects, const Paths64& clips, PolyTree64& solution) + { + Paths64 sol_open; + Clipper64 clipper; + clipper.AddSubject(subjects); + clipper.AddClip(clips); + clipper.Execute(cliptype, fillrule, solution, sol_open); + } + + inline PathsD BooleanOp(ClipType cliptype, FillRule fillrule, + const PathsD& subjects, const PathsD& clips, int decimal_prec = 2) + { + CheckPrecision(decimal_prec); + PathsD result; + ClipperD clipper(decimal_prec); + clipper.AddSubject(subjects); + clipper.AddClip(clips); + clipper.Execute(cliptype, fillrule, result); + return result; + } + + inline void BooleanOp(ClipType cliptype, FillRule fillrule, + const PathsD& subjects, const PathsD& clips, + PolyTreeD& polytree, int decimal_prec = 2) + { + CheckPrecision(decimal_prec); + PathsD result; + ClipperD clipper(decimal_prec); + clipper.AddSubject(subjects); + clipper.AddClip(clips); + clipper.Execute(cliptype, fillrule, polytree); + } + + inline Paths64 Intersect(const Paths64& subjects, const Paths64& clips, FillRule fillrule) + { + return BooleanOp(ClipType::Intersection, fillrule, subjects, clips); + } + + inline PathsD Intersect(const PathsD& subjects, const PathsD& clips, FillRule fillrule, int decimal_prec = 2) + { + return BooleanOp(ClipType::Intersection, fillrule, subjects, clips, decimal_prec); + } + + inline Paths64 Union(const Paths64& subjects, const Paths64& clips, FillRule fillrule) + { + return BooleanOp(ClipType::Union, fillrule, subjects, clips); + } + + inline PathsD Union(const PathsD& subjects, const PathsD& clips, FillRule fillrule, int decimal_prec = 2) + { + return BooleanOp(ClipType::Union, fillrule, subjects, clips, decimal_prec); + } + + inline Paths64 Union(const Paths64& subjects, FillRule fillrule) + { + Paths64 result; + Clipper64 clipper; + clipper.AddSubject(subjects); + clipper.Execute(ClipType::Union, fillrule, result); + return result; + } + + inline PathsD Union(const PathsD& subjects, FillRule fillrule, int decimal_prec = 2) + { + CheckPrecision(decimal_prec); + PathsD result; + ClipperD clipper(decimal_prec); + clipper.AddSubject(subjects); + clipper.Execute(ClipType::Union, fillrule, result); + return result; + } + + inline Paths64 Difference(const Paths64& subjects, const Paths64& clips, FillRule fillrule) + { + return BooleanOp(ClipType::Difference, fillrule, subjects, clips); + } + + inline PathsD Difference(const PathsD& subjects, const PathsD& clips, FillRule fillrule, int decimal_prec = 2) + { + return BooleanOp(ClipType::Difference, fillrule, subjects, clips, decimal_prec); + } + + inline Paths64 Xor(const Paths64& subjects, const Paths64& clips, FillRule fillrule) + { + return BooleanOp(ClipType::Xor, fillrule, subjects, clips); + } + + inline PathsD Xor(const PathsD& subjects, const PathsD& clips, FillRule fillrule, int decimal_prec = 2) + { + return BooleanOp(ClipType::Xor, fillrule, subjects, clips, decimal_prec); + } + + inline Paths64 InflatePaths(const Paths64& paths, double delta, + JoinType jt, EndType et, double miter_limit = 2.0) + { + ClipperOffset clip_offset(miter_limit); + clip_offset.AddPaths(paths, jt, et); + return clip_offset.Execute(delta); + } + + inline PathsD InflatePaths(const PathsD& paths, double delta, + JoinType jt, EndType et, double miter_limit = 2.0, int precision = 2) + { + CheckPrecision(precision); + const double scale = std::pow(10, precision); + ClipperOffset clip_offset(miter_limit); + clip_offset.AddPaths(ScalePaths(paths, scale), jt, et); + Paths64 tmp = clip_offset.Execute(delta * scale); + return ScalePaths(tmp, 1 / scale); + } + + inline Path64 TranslatePath(const Path64& path, int64_t dx, int64_t dy) + { + Path64 result; + result.reserve(path.size()); + for (const Point64& pt : path) + result.push_back(Point64(pt.x + dx, pt.y + dy)); + return result; + } + + inline PathD TranslatePath(const PathD& path, double dx, double dy) + { + PathD result; + result.reserve(path.size()); + for (const PointD& pt : path) + result.push_back(PointD(pt.x + dx, pt.y + dy)); + return result; + } + + inline Paths64 TranslatePaths(const Paths64& paths, int64_t dx, int64_t dy) + { + Paths64 result; + result.reserve(paths.size()); + for (const Path64& path : paths) + result.push_back(TranslatePath(path, dx, dy)); + return result; + } + + inline PathsD TranslatePaths(const PathsD& paths, double dx, double dy) + { + PathsD result; + result.reserve(paths.size()); + for (const PathD& path : paths) + result.push_back(TranslatePath(path, dx, dy)); + return result; + } + + inline Rect64 Bounds(const Path64& path) + { + Rect64 rec = MaxInvalidRect64; + for (const Point64& pt : path) + { + if (pt.x < rec.left) rec.left = pt.x; + if (pt.x > rec.right) rec.right = pt.x; + if (pt.y < rec.top) rec.top = pt.y; + if (pt.y > rec.bottom) rec.bottom = pt.y; + } + if (rec.IsEmpty()) return Rect64(); + return rec; + } + + inline Rect64 Bounds(const Paths64& paths) + { + Rect64 rec = MaxInvalidRect64; + for (const Path64& path : paths) + for (const Point64& pt : path) + { + if (pt.x < rec.left) rec.left = pt.x; + if (pt.x > rec.right) rec.right = pt.x; + if (pt.y < rec.top) rec.top = pt.y; + if (pt.y > rec.bottom) rec.bottom = pt.y; + } + if (rec.IsEmpty()) return Rect64(); + return rec; + } + + inline RectD Bounds(const PathD& path) + { + RectD rec = MaxInvalidRectD; + for (const PointD& pt : path) + { + if (pt.x < rec.left) rec.left = pt.x; + if (pt.x > rec.right) rec.right = pt.x; + if (pt.y < rec.top) rec.top = pt.y; + if (pt.y > rec.bottom) rec.bottom = pt.y; + } + if (rec.IsEmpty()) return RectD(); + return rec; + } + + inline RectD Bounds(const PathsD& paths) + { + RectD rec = MaxInvalidRectD; + for (const PathD& path : paths) + for (const PointD& pt : path) + { + if (pt.x < rec.left) rec.left = pt.x; + if (pt.x > rec.right) rec.right = pt.x; + if (pt.y < rec.top) rec.top = pt.y; + if (pt.y > rec.bottom) rec.bottom = pt.y; + } + if (rec.IsEmpty()) return RectD(); + return rec; + } + + inline Path64 RectClip(const Rect64& rect, const Path64& path) + { + if (rect.IsEmpty() || path.empty()) return Path64(); + Rect64 pathRec = Bounds(path); + if (!rect.Intersects(pathRec)) return Path64(); + if (rect.Contains(pathRec)) return path; + class RectClip rc(rect); + return rc.Execute(path); + } + + inline Paths64 RectClip(const Rect64& rect, const Paths64& paths) + { + if (rect.IsEmpty() || paths.empty()) return Paths64(); + class RectClip rc(rect); + Paths64 result; + result.reserve(paths.size()); + + for (const Path64& p : paths) + { + Rect64 pathRec = Bounds(p); + if (!rect.Intersects(pathRec)) + continue; + else if (rect.Contains(pathRec)) + result.push_back(p); + else + { + Path64 p2 = rc.Execute(p); + if (!p2.empty()) result.push_back(std::move(p2)); + } + } + return result; + } + + inline PathD RectClip(const RectD& rect, const PathD& path, int precision = 2) + { + if (rect.IsEmpty() || path.empty() || + !rect.Contains(Bounds(path))) return PathD(); + CheckPrecision(precision); + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(rect, scale); + class RectClip rc(r); + Path64 p = ScalePath(path, scale); + return ScalePath(rc.Execute(p), 1 / scale); + } + + inline PathsD RectClip(const RectD& rect, const PathsD& paths, int precision = 2) + { + if (rect.IsEmpty() || paths.empty()) return PathsD(); + CheckPrecision(precision); + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(rect, scale); + class RectClip rc(r); + PathsD result; + result.reserve(paths.size()); + for (const PathD& path : paths) + { + RectD pathRec = Bounds(path); + if (!rect.Intersects(pathRec)) + continue; + else if (rect.Contains(pathRec)) + result.push_back(path); + else + { + Path64 p = ScalePath(path, scale); + p = rc.Execute(p); + if (!p.empty()) + result.push_back(ScalePath(p, 1 / scale)); + } + } + return result; + } + + inline Paths64 RectClipLines(const Rect64& rect, const Path64& path) + { + Paths64 result; + if (rect.IsEmpty() || path.empty()) return result; + Rect64 pathRec = Bounds(path); + if (!rect.Intersects(pathRec)) return result; + if (rect.Contains(pathRec)) + { + result.push_back(path); + return result; + } + class RectClipLines rcl(rect); + return rcl.Execute(path); + } + + inline Paths64 RectClipLines(const Rect64& rect, const Paths64& paths) + { + Paths64 result; + if (rect.IsEmpty() || paths.empty()) return result; + class RectClipLines rcl(rect); + for (const Path64& p : paths) + { + Rect64 pathRec = Bounds(p); + if (!rect.Intersects(pathRec)) + continue; + else if (rect.Contains(pathRec)) + result.push_back(p); + else + { + Paths64 pp = rcl.Execute(p); + if (!pp.empty()) + result.insert(result.end(), pp.begin(), pp.end()); + } + } + return result; + } + + inline PathsD RectClipLines(const RectD& rect, const PathD& path, int precision = 2) + { + if (rect.IsEmpty() || path.empty() || + !rect.Contains(Bounds(path))) return PathsD(); + CheckPrecision(precision); + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(rect, scale); + class RectClipLines rcl(r); + Path64 p = ScalePath(path, scale); + return ScalePaths(rcl.Execute(p), 1 / scale); + } + + inline PathsD RectClipLines(const RectD& rect, const PathsD& paths, int precision = 2) + { + PathsD result; + if (rect.IsEmpty() || paths.empty()) return result; + CheckPrecision(precision); + const double scale = std::pow(10, precision); + Rect64 r = ScaleRect(rect, scale); + class RectClipLines rcl(r); + result.reserve(paths.size()); + for (const PathD& path : paths) + { + RectD pathRec = Bounds(path); + if (!rect.Intersects(pathRec)) + continue; + else if (rect.Contains(pathRec)) + result.push_back(path); + else + { + Path64 p = ScalePath(path, scale); + Paths64 pp = rcl.Execute(p); + if (pp.empty()) continue; + PathsD ppd = ScalePaths(pp, 1 / scale); + result.insert(result.end(), ppd.begin(), ppd.end()); + } + } + return result; + } + + namespace details + { + + inline void PolyPathToPaths64(const PolyPath64& polypath, Paths64& paths) + { + paths.push_back(polypath.Polygon()); + for (const PolyPath* child : polypath) + PolyPathToPaths64(*(PolyPath64*)(child), paths); + } + + inline void PolyPathToPathsD(const PolyPathD& polypath, PathsD& paths) + { + paths.push_back(polypath.Polygon()); + for (const PolyPath* child : polypath) + PolyPathToPathsD(*(PolyPathD*)(child), paths); + } + + inline bool PolyPath64ContainsChildren(const PolyPath64& pp) + { + for (auto ch : pp) + { + PolyPath64* child = (PolyPath64*)ch; + for (const Point64& pt : child->Polygon()) + if (PointInPolygon(pt, pp.Polygon()) == PointInPolygonResult::IsOutside) + return false; + if (child->Count() > 0 && !PolyPath64ContainsChildren(*child)) + return false; + } + return true; + } + + inline bool GetInt(std::string::const_iterator& iter, const + std::string::const_iterator& end_iter, int64_t& val) + { + val = 0; + bool is_neg = *iter == '-'; + if (is_neg) ++iter; + std::string::const_iterator start_iter = iter; + while (iter != end_iter && + ((*iter >= '0') && (*iter <= '9'))) + { + val = val * 10 + (static_cast(*iter++) - '0'); + } + if (is_neg) val = -val; + return (iter != start_iter); + } + + inline bool GetFloat(std::string::const_iterator& iter, const + std::string::const_iterator& end_iter, double& val) + { + val = 0; + bool is_neg = *iter == '-'; + if (is_neg) ++iter; + int dec_pos = 1; + const std::string::const_iterator start_iter = iter; + while (iter != end_iter && (*iter == '.' || + ((*iter >= '0') && (*iter <= '9')))) + { + if (*iter == '.') + { + if (dec_pos != 1) break; + dec_pos = 0; + ++iter; + continue; + } + if (dec_pos != 1) --dec_pos; + val = val * 10 + ((int64_t)(*iter++) - '0'); + } + if (iter == start_iter || dec_pos == 0) return false; + if (dec_pos < 0) + val *= std::pow(10, dec_pos); + if (is_neg) + val *= -1; + return true; + } + + inline void SkipWhiteSpace(std::string::const_iterator& iter, + const std::string::const_iterator& end_iter) + { + while (iter != end_iter && *iter <= ' ') ++iter; + } + + inline void SkipSpacesWithOptionalComma(std::string::const_iterator& iter, + const std::string::const_iterator& end_iter) + { + bool comma_seen = false; + while (iter != end_iter) + { + if (*iter == ' ') ++iter; + else if (*iter == ',') + { + if (comma_seen) return; // don't skip 2 commas! + comma_seen = true; + ++iter; + } + else return; + } + } + + inline bool has_one_match(const char c, char* chrs) + { + while (*chrs > 0 && c != *chrs) ++chrs; + if (!*chrs) return false; + *chrs = ' '; // only match once per char + return true; + } + + + inline void SkipUserDefinedChars(std::string::const_iterator& iter, + const std::string::const_iterator& end_iter, const std::string& skip_chars) + { + const size_t MAX_CHARS = 16; + char buff[MAX_CHARS] = {0}; + std::copy(skip_chars.cbegin(), skip_chars.cend(), &buff[0]); + while (iter != end_iter && + (*iter <= ' ' || has_one_match(*iter, buff))) ++iter; + return; + } + + } // end details namespace + + inline Paths64 PolyTreeToPaths64(const PolyTree64& polytree) + { + Paths64 result; + for (auto child : polytree) + details::PolyPathToPaths64(*(PolyPath64*)(child), result); + return result; + } + + inline PathsD PolyTreeToPathsD(const PolyTreeD& polytree) + { + PathsD result; + for (auto child : polytree) + details::PolyPathToPathsD(*(PolyPathD*)(child), result); + return result; + } + + inline bool CheckPolytreeFullyContainsChildren(const PolyTree64& polytree) + { + for (auto child : polytree) + if (child->Count() > 0 && + !details::PolyPath64ContainsChildren(*(PolyPath64*)(child))) + return false; + return true; + } + + inline Path64 MakePath(const std::string& s) + { + const std::string skip_chars = " ,(){}[]"; + Path64 result; + std::string::const_iterator s_iter = s.cbegin(); + details::SkipUserDefinedChars(s_iter, s.cend(), skip_chars); + while (s_iter != s.cend()) + { + int64_t y = 0, x = 0; + if (!details::GetInt(s_iter, s.cend(), x)) break; + details::SkipSpacesWithOptionalComma(s_iter, s.cend()); + if (!details::GetInt(s_iter, s.cend(), y)) break; + result.push_back(Point64(x, y)); + details::SkipUserDefinedChars(s_iter, s.cend(), skip_chars); + } + return result; + } + + inline PathD MakePathD(const std::string& s) + { + const std::string skip_chars = " ,(){}[]"; + PathD result; + std::string::const_iterator s_iter = s.cbegin(); + details::SkipUserDefinedChars(s_iter, s.cend(), skip_chars); + while (s_iter != s.cend()) + { + double y = 0, x = 0; + if (!details::GetFloat(s_iter, s.cend(), x)) break; + details::SkipSpacesWithOptionalComma(s_iter, s.cend()); + if (!details::GetFloat(s_iter, s.cend(), y)) break; + result.push_back(PointD(x, y)); + details::SkipUserDefinedChars(s_iter, s.cend(), skip_chars); + } + return result; + } + + inline Path64 TrimCollinear(const Path64& p, bool is_open_path = false) + { + size_t len = p.size(); + if (len < 3) + { + if (!is_open_path || len < 2 || p[0] == p[1]) return Path64(); + else return p; + } + + Path64 dst; + dst.reserve(len); + Path64::const_iterator srcIt = p.cbegin(), prevIt, stop = p.cend() - 1; + + if (!is_open_path) + { + while (srcIt != stop && !CrossProduct(*stop, *srcIt, *(srcIt + 1))) + ++srcIt; + while (srcIt != stop && !CrossProduct(*(stop - 1), *stop, *srcIt)) + --stop; + if (srcIt == stop) return Path64(); + } + + prevIt = srcIt++; + dst.push_back(*prevIt); + for (; srcIt != stop; ++srcIt) + { + if (CrossProduct(*prevIt, *srcIt, *(srcIt + 1))) + { + prevIt = srcIt; + dst.push_back(*prevIt); + } + } + + if (is_open_path) + dst.push_back(*srcIt); + else if (CrossProduct(*prevIt, *stop, dst[0])) + dst.push_back(*stop); + else + { + while (dst.size() > 2 && + !CrossProduct(dst[dst.size() - 1], dst[dst.size() - 2], dst[0])) + dst.pop_back(); + if (dst.size() < 3) return Path64(); + } + return dst; + } + + inline PathD TrimCollinear(const PathD& path, int precision, bool is_open_path = false) + { + CheckPrecision(precision); + const double scale = std::pow(10, precision); + Path64 p = ScalePath(path, scale); + p = TrimCollinear(p, is_open_path); + return ScalePath(p, 1/scale); + } + + template + inline double Distance(const Point pt1, const Point pt2) + { + return std::sqrt(DistanceSqr(pt1, pt2)); + } + + template + inline double Length(const Path& path, bool is_closed_path = false) + { + double result = 0.0; + if (path.size() < 2) return result; + auto it = path.cbegin(), stop = path.end() - 1; + for (; it != stop; ++it) + result += Distance(*it, *(it + 1)); + if (is_closed_path) + result += Distance(*stop, *path.cbegin()); + return result; + } + + + template + inline bool NearCollinear(const Point& pt1, const Point& pt2, const Point& pt3, double sin_sqrd_min_angle_rads) + { + double cp = std::abs(CrossProduct(pt1, pt2, pt3)); + return (cp * cp) / (DistanceSqr(pt1, pt2) * DistanceSqr(pt2, pt3)) < sin_sqrd_min_angle_rads; + } + + template + inline Path Ellipse(const Rect& rect, int steps = 0) + { + return Ellipse(rect.MidPoint(), + static_cast(rect.Width()) *0.5, + static_cast(rect.Height()) * 0.5, steps); + } + + template + inline Path Ellipse(const Point& center, + double radiusX, double radiusY = 0, int steps = 0) + { + if (radiusX <= 0) return Path(); + if (radiusY <= 0) radiusY = radiusX; + if (steps <= 2) + steps = static_cast(PI * sqrt((radiusX + radiusY) / 2)); + + double si = std::sin(2 * PI / steps); + double co = std::cos(2 * PI / steps); + double dx = co, dy = si; + Path result; + result.reserve(steps); + result.push_back(Point(center.x + radiusX, static_cast(center.y))); + for (int i = 1; i < steps; ++i) + { + result.push_back(Point(center.x + radiusX * dx, center.y + radiusY * dy)); + double x = dx * co - dy * si; + dy = dy * co + dx * si; + dx = x; + } + return result; + } + + template + inline double PerpendicDistFromLineSqrd(const Point& pt, + const Point& line1, const Point& line2) + { + double a = static_cast(pt.x - line1.x); + double b = static_cast(pt.y - line1.y); + double c = static_cast(line2.x - line1.x); + double d = static_cast(line2.y - line1.y); + if (c == 0 && d == 0) return 0; + return Sqr(a * d - c * b) / (c * c + d * d); + } + + template + inline void RDP(const Path path, std::size_t begin, + std::size_t end, double epsSqrd, std::vector& flags) + { + typename Path::size_type idx = 0; + double max_d = 0; + while (end > begin && path[begin] == path[end]) flags[end--] = false; + for (typename Path::size_type i = begin + 1; i < end; ++i) + { + // PerpendicDistFromLineSqrd - avoids expensive Sqrt() + double d = PerpendicDistFromLineSqrd(path[i], path[begin], path[end]); + if (d <= max_d) continue; + max_d = d; + idx = i; + } + if (max_d <= epsSqrd) return; + flags[idx] = true; + if (idx > begin + 1) RDP(path, begin, idx, epsSqrd, flags); + if (idx < end - 1) RDP(path, idx, end, epsSqrd, flags); + } + + template + inline Path RamerDouglasPeucker(const Path& path, double epsilon) + { + const typename Path::size_type len = path.size(); + if (len < 5) return Path(path); + std::vector flags(len); + flags[0] = true; + flags[len - 1] = true; + RDP(path, 0, len - 1, Sqr(epsilon), flags); + Path result; + result.reserve(len); + for (typename Path::size_type i = 0; i < len; ++i) + if (flags[i]) + result.push_back(path[i]); + return result; + } + + template + inline Paths RamerDouglasPeucker(const Paths& paths, double epsilon) + { + Paths result; + result.reserve(paths.size()); + for (const Path& path : paths) + result.push_back(RamerDouglasPeucker(path, epsilon)); + return result; + } + +} // end Clipper2Lib namespace + +#endif // CLIPPER_H diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h new file mode 100644 index 0000000000..ca0ab6be81 --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.minkowski.h @@ -0,0 +1,118 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 15 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : Minkowski Sum and Difference * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_MINKOWSKI_H +#define CLIPPER_MINKOWSKI_H + +#include +#include +#include +#include "clipper.core.h" + +namespace Clipper2Lib +{ + + namespace detail + { + inline Paths64 Minkowski(const Path64& pattern, const Path64& path, bool isSum, bool isClosed) + { + size_t delta = isClosed ? 0 : 1; + size_t patLen = pattern.size(), pathLen = path.size(); + if (patLen == 0 || pathLen == 0) return Paths64(); + Paths64 tmp; + tmp.reserve(pathLen); + + if (isSum) + { + for (const Point64& p : path) + { + Path64 path2(pattern.size()); + std::transform(pattern.cbegin(), pattern.cend(), + path2.begin(), [p](const Point64& pt2) {return p + pt2; }); + tmp.push_back(path2); + } + } + else + { + for (const Point64& p : path) + { + Path64 path2(pattern.size()); + std::transform(pattern.cbegin(), pattern.cend(), + path2.begin(), [p](const Point64& pt2) {return p - pt2; }); + tmp.push_back(path2); + } + } + + Paths64 result; + result.reserve((pathLen - delta) * patLen); + size_t g = isClosed ? pathLen - 1 : 0; + for (size_t h = patLen - 1, i = delta; i < pathLen; ++i) + { + for (size_t j = 0; j < patLen; j++) + { + Path64 quad; + quad.reserve(4); + { + quad.push_back(tmp[g][h]); + quad.push_back(tmp[i][h]); + quad.push_back(tmp[i][j]); + quad.push_back(tmp[g][j]); + }; + if (!IsPositive(quad)) + std::reverse(quad.begin(), quad.end()); + result.push_back(quad); + h = j; + } + g = i; + } + return result; + } + + inline Paths64 Union(const Paths64& subjects, FillRule fillrule) + { + Paths64 result; + Clipper64 clipper; + clipper.AddSubject(subjects); + clipper.Execute(ClipType::Union, fillrule, result); + return result; + } + + } // namespace internal + + inline Paths64 MinkowskiSum(const Path64& pattern, const Path64& path, bool isClosed) + { + return detail::Union(detail::Minkowski(pattern, path, true, isClosed), FillRule::NonZero); + } + + inline PathsD MinkowskiSum(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2) + { + double scale = pow(10, decimalPlaces); + Path64 pat64 = ScalePath(pattern, scale); + Path64 path64 = ScalePath(path, scale); + Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, true, isClosed), FillRule::NonZero); + return ScalePaths(tmp, 1 / scale); + } + + inline Paths64 MinkowskiDiff(const Path64& pattern, const Path64& path, bool isClosed) + { + return detail::Union(detail::Minkowski(pattern, path, false, isClosed), FillRule::NonZero); + } + + inline PathsD MinkowskiDiff(const PathD& pattern, const PathD& path, bool isClosed, int decimalPlaces = 2) + { + double scale = pow(10, decimalPlaces); + Path64 pat64 = ScalePath(pattern, scale); + Path64 path64 = ScalePath(path, scale); + Paths64 tmp = detail::Union(detail::Minkowski(pat64, path64, false, isClosed), FillRule::NonZero); + return ScalePaths(tmp, 1 / scale); + } + +} // Clipper2Lib namespace + +#endif // CLIPPER_MINKOWSKI_H diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h new file mode 100644 index 0000000000..4fd130bf4d --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.offset.h @@ -0,0 +1,107 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 15 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : Path Offset (Inflate/Shrink) * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_OFFSET_H_ +#define CLIPPER_OFFSET_H_ + +#include "clipper.core.h" + +namespace Clipper2Lib { + +enum class JoinType { Square, Round, Miter }; + +enum class EndType {Polygon, Joined, Butt, Square, Round}; +//Butt : offsets both sides of a path, with square blunt ends +//Square : offsets both sides of a path, with square extended ends +//Round : offsets both sides of a path, with round extended ends +//Joined : offsets both sides of a path, with joined ends +//Polygon: offsets only one side of a closed path + +class ClipperOffset { +private: + + class Group { + public: + Paths64 paths_in_; + Paths64 paths_out_; + Path64 path_; + bool is_reversed_ = false; + JoinType join_type_; + EndType end_type_; + Group(const Paths64& paths, JoinType join_type, EndType end_type) : + paths_in_(paths), join_type_(join_type), end_type_(end_type) {} + }; + + double group_delta_ = 0.0; + double abs_group_delta_ = 0.0; + double temp_lim_ = 0.0; + double steps_per_rad_ = 0.0; + PathD norms; + Paths64 solution; + std::vector groups_; + JoinType join_type_ = JoinType::Square; + + double miter_limit_ = 0.0; + double arc_tolerance_ = 0.0; + bool merge_groups_ = true; + bool preserve_collinear_ = false; + bool reverse_solution_ = false; + + void DoSquare(Group& group, const Path64& path, size_t j, size_t k); + void DoMiter(Group& group, const Path64& path, size_t j, size_t k, double cos_a); + void DoRound(Group& group, const Path64& path, size_t j, size_t k, double angle); + void BuildNormals(const Path64& path); + void OffsetPolygon(Group& group, Path64& path); + void OffsetOpenJoined(Group& group, Path64& path); + void OffsetOpenPath(Group& group, Path64& path, EndType endType); + void OffsetPoint(Group& group, Path64& path, size_t j, size_t& k); + void DoGroupOffset(Group &group, double delta); +public: + ClipperOffset(double miter_limit = 2.0, + double arc_tolerance = 0.0, + bool preserve_collinear = false, + bool reverse_solution = false) : + miter_limit_(miter_limit), arc_tolerance_(arc_tolerance), + preserve_collinear_(preserve_collinear), + reverse_solution_(reverse_solution) { }; + + ~ClipperOffset() { Clear(); }; + + void AddPath(const Path64& path, JoinType jt_, EndType et_); + void AddPaths(const Paths64& paths, JoinType jt_, EndType et_); + void AddPath(const PathD &p, JoinType jt_, EndType et_); + void AddPaths(const PathsD &p, JoinType jt_, EndType et_); + void Clear() { groups_.clear(); norms.clear(); }; + + Paths64 Execute(double delta); + + double MiterLimit() const { return miter_limit_; } + void MiterLimit(double miter_limit) { miter_limit_ = miter_limit; } + + //ArcTolerance: needed for rounded offsets (See offset_triginometry2.svg) + double ArcTolerance() const { return arc_tolerance_; } + void ArcTolerance(double arc_tolerance) { arc_tolerance_ = arc_tolerance; } + + //MergeGroups: A path group is one or more paths added via the AddPath or + //AddPaths methods. By default these path groups will be offset + //independently of other groups and this may cause overlaps (intersections). + //However, when MergeGroups is enabled, any overlapping offsets will be + //merged (via a clipping union operation) to remove overlaps. + bool MergeGroups() const { return merge_groups_; } + void MergeGroups(bool merge_groups) { merge_groups_ = merge_groups; } + + bool PreserveCollinear() const { return preserve_collinear_; } + void PreserveCollinear(bool preserve_collinear){preserve_collinear_ = preserve_collinear;} + + bool ReverseSolution() const { return reverse_solution_; } + void ReverseSolution(bool reverse_solution) {reverse_solution_ = reverse_solution;} +}; + +} +#endif /* CLIPPER_OFFSET_H_ */ diff --git a/src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h b/src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h new file mode 100644 index 0000000000..98f43e0b2d --- /dev/null +++ b/src/clipper2/Clipper2Lib/include/clipper2/clipper.rectclip.h @@ -0,0 +1,50 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 26 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : FAST rectangular clipping * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#ifndef CLIPPER_RECTCLIP_H +#define CLIPPER_RECTCLIP_H + +#include +#include +#include "clipper.h" +#include "clipper.core.h" + +namespace Clipper2Lib +{ + + enum class Location { Left, Top, Right, Bottom, Inside }; + + class RectClip { + protected: + const Rect64 rect_; + const Point64 mp_; + const Path64 rectPath_; + Path64 result_; + std::vector start_locs_; + + void GetNextLocation(const Path64& path, + Location& loc, int& i, int highI); + void AddCorner(Location prev, Location curr); + void AddCorner(Location& loc, bool isClockwise); + public: + RectClip(const Rect64& rect) : + rect_(rect), + mp_(rect.MidPoint()), + rectPath_(rect.AsPath()) {} + Path64 Execute(const Path64& path); + }; + + class RectClipLines : public RectClip { + public: + RectClipLines(const Rect64& rect) : RectClip(rect) {}; + Paths64 Execute(const Path64& path); + }; + +} // Clipper2Lib namespace +#endif // CLIPPER_RECTCLIP_H diff --git a/src/clipper2/Clipper2Lib/src/clipper.engine.cpp b/src/clipper2/Clipper2Lib/src/clipper.engine.cpp new file mode 100644 index 0000000000..0c0d47f37a --- /dev/null +++ b/src/clipper2/Clipper2Lib/src/clipper.engine.cpp @@ -0,0 +1,3591 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 4 November 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : This is the main polygon clipping module * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "clipper2/clipper.engine.h" + +namespace Clipper2Lib { + + static const double FloatingPointTolerance = 1.0e-12; + static const Rect64 invalid_rect = Rect64( + std::numeric_limits::max(), + std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max() + ); + + //Every closed path (or polygon) is made up of a series of vertices forming + //edges that alternate between going up (relative to the Y-axis) and going + //down. Edges consecutively going up or consecutively going down are called + //'bounds' (or sides if they're simple polygons). 'Local Minima' refer to + //vertices where descending bounds become ascending ones. + + struct Scanline { + int64_t y = 0; + Scanline* next = nullptr; + + explicit Scanline(int64_t y_) : y(y_) {} + }; + + struct Joiner { + int idx; + OutPt* op1; + OutPt* op2; + Joiner* next1; + Joiner* next2; + Joiner* nextH; + + explicit Joiner(OutPt* op1_, OutPt* op2_, Joiner* nexth) : + op1(op1_), op2(op2_), nextH(nexth) + { + idx = -1; + next1 = op1->joiner; + op1->joiner = this; + + if (op2) + { + next2 = op2->joiner; + op2->joiner = this; + } + else + next2 = nullptr; + } + + }; + + struct LocMinSorter { + inline bool operator()(const LocalMinima* locMin1, const LocalMinima* locMin2) + { + if (locMin2->vertex->pt.y != locMin1->vertex->pt.y) + return locMin2->vertex->pt.y < locMin1->vertex->pt.y; + else + return locMin2->vertex->pt.x < locMin1->vertex->pt.x; + } + }; + + inline bool IsOdd(int val) + { + return (val & 1) ? true : false; + } + + + inline bool IsHotEdge(const Active& e) + { + return (e.outrec); + } + + + inline bool IsOpen(const Active& e) + { + return (e.local_min->is_open); + } + + + inline bool IsOpenEnd(const Vertex& v) + { + return (v.flags & (VertexFlags::OpenStart | VertexFlags::OpenEnd)) != + VertexFlags::None; + } + + + inline bool IsOpenEnd(const Active& ae) + { + return IsOpenEnd(*ae.vertex_top); + } + + + inline Active* GetPrevHotEdge(const Active& e) + { + Active* prev = e.prev_in_ael; + while (prev && (IsOpen(*prev) || !IsHotEdge(*prev))) + prev = prev->prev_in_ael; + return prev; + } + + inline bool IsFront(const Active& e) + { + return (&e == e.outrec->front_edge); + } + + inline bool IsInvalidPath(OutPt* op) + { + return (!op || op->next == op); + } + + /******************************************************************************* + * Dx: 0(90deg) * + * | * + * +inf (180deg) <--- o ---> -inf (0deg) * + *******************************************************************************/ + + inline double GetDx(const Point64& pt1, const Point64& pt2) + { + double dy = double(pt2.y - pt1.y); + if (dy != 0) + return double(pt2.x - pt1.x) / dy; + else if (pt2.x > pt1.x) + return -std::numeric_limits::max(); + else + return std::numeric_limits::max(); + } + + + inline int64_t TopX(const Active& ae, const int64_t currentY) + { + if ((currentY == ae.top.y) || (ae.top.x == ae.bot.x)) return ae.top.x; + else if (currentY == ae.bot.y) return ae.bot.x; + else return ae.bot.x + static_cast(std::nearbyint(ae.dx * (currentY - ae.bot.y))); + // nb: std::nearbyint (or std::round) substantially *improves* performance here + // as it greatly improves the likelihood of edge adjacency in ProcessIntersectList(). + } + + + inline bool IsHorizontal(const Active& e) + { + return (e.top.y == e.bot.y); + } + + + inline bool IsHeadingRightHorz(const Active& e) + { + return e.dx == -std::numeric_limits::max(); + } + + + inline bool IsHeadingLeftHorz(const Active& e) + { + return e.dx == std::numeric_limits::max(); + } + + + inline void SwapActives(Active*& e1, Active*& e2) + { + Active* e = e1; + e1 = e2; + e2 = e; + } + + + inline PathType GetPolyType(const Active& e) + { + return e.local_min->polytype; + } + + + inline bool IsSamePolyType(const Active& e1, const Active& e2) + { + return e1.local_min->polytype == e2.local_min->polytype; + } + + inline Point64 GetEndE1ClosestToEndE2( + const Active& e1, const Active& e2) + { + double d[] = { + DistanceSqr(e1.bot, e2.bot), + DistanceSqr(e1.top, e2.top), + DistanceSqr(e1.top, e2.bot), + DistanceSqr(e1.bot, e2.top) + }; + if (d[0] == 0) return e1.bot; + int idx = 0; + for (int i = 1; i < 4; ++i) + { + if (d[i] < d[idx]) idx = i; + if (d[i] == 0) break; + } + switch (idx) + { + case 1: case 2: return e1.top; + default: return e1.bot; + } + } + + Point64 GetIntersectPoint(const Active& e1, const Active& e2) + { + double b1, b2, q = (e1.dx - e2.dx); + if (std::abs(q) < 1e-5) // 1e-5 is a rough empirical limit + return GetEndE1ClosestToEndE2(e1, e2); // ie almost parallel + + if (e1.dx == 0) + { + if (IsHorizontal(e2)) return Point64(e1.bot.x, e2.bot.y); + b2 = e2.bot.y - (e2.bot.x / e2.dx); + return Point64(e1.bot.x, + static_cast(std::round(e1.bot.x / e2.dx + b2))); + } + else if (e2.dx == 0) + { + if (IsHorizontal(e1)) return Point64(e2.bot.x, e1.bot.y); + b1 = e1.bot.y - (e1.bot.x / e1.dx); + return Point64(e2.bot.x, + static_cast(std::round(e2.bot.x / e1.dx + b1))); + } + else + { + b1 = e1.bot.x - e1.bot.y * e1.dx; + b2 = e2.bot.x - e2.bot.y * e2.dx; + + q = (b2 - b1) / q; + return (abs(e1.dx) < abs(e2.dx)) ? + Point64(static_cast(e1.dx * q + b1), + static_cast((q))) : + Point64(static_cast(e2.dx * q + b2), + static_cast((q))); + } + } + + bool GetIntersectPoint(const Point64& ln1a, const Point64& ln1b, + const Point64& ln2a, const Point64& ln2b, PointD& ip) + { + ip = PointD(0, 0); + double m1, b1, m2, b2; + if (ln1b.x == ln1a.x) + { + if (ln2b.x == ln2a.x) return false; + m2 = static_cast(ln2b.y - ln2a.y) / + static_cast(ln2b.x - ln2a.x); + b2 = ln2a.y - m2 * ln2a.x; + ip.x = static_cast(ln1a.x); + ip.y = m2 * ln1a.x + b2; + } + else if (ln2b.x == ln2a.x) + { + m1 = static_cast(ln1b.y - ln1a.y) / + static_cast(ln1b.x - ln1a.x); + b1 = ln1a.y - m1 * ln1a.x; + ip.x = static_cast(ln2a.x); + ip.y = m1 * ln2a.x + b1; + } + else + { + m1 = static_cast(ln1b.y - ln1a.y) / + static_cast(ln1b.x - ln1a.x); + b1 = ln1a.y - m1 * ln1a.x; + m2 = static_cast(ln2b.y - ln2a.y) / + static_cast(ln2b.x - ln2a.x); + b2 = ln2a.y - m2 * ln2a.x; + if (std::abs(m1 - m2) > FloatingPointTolerance) + { + ip.x = (b2 - b1) / (m1 - m2); + ip.y = m1 * ip.x + b1; + } + else + { + ip.x = static_cast(ln1a.x + ln1b.x) / 2; + ip.y = static_cast(ln1a.y + ln1b.y) / 2; + } + } + return true; + } + + + inline void SetDx(Active& e) + { + e.dx = GetDx(e.bot, e.top); + } + + + inline Vertex* NextVertex(const Active& e) + { + if (e.wind_dx > 0) + return e.vertex_top->next; + else + return e.vertex_top->prev; + } + + + //PrevPrevVertex: useful to get the (inverted Y-axis) top of the + //alternate edge (ie left or right bound) during edge insertion. + inline Vertex* PrevPrevVertex(const Active& ae) + { + if (ae.wind_dx > 0) + return ae.vertex_top->prev->prev; + else + return ae.vertex_top->next->next; + } + + + inline Active* ExtractFromSEL(Active* ae) + { + Active* res = ae->next_in_sel; + if (res) + res->prev_in_sel = ae->prev_in_sel; + ae->prev_in_sel->next_in_sel = res; + return res; + } + + + inline void Insert1Before2InSEL(Active* ae1, Active* ae2) + { + ae1->prev_in_sel = ae2->prev_in_sel; + if (ae1->prev_in_sel) + ae1->prev_in_sel->next_in_sel = ae1; + ae1->next_in_sel = ae2; + ae2->prev_in_sel = ae1; + } + + inline bool IsMaxima(const Vertex& v) + { + return ((v.flags & VertexFlags::LocalMax) != VertexFlags::None); + } + + + inline bool IsMaxima(const Active& e) + { + return IsMaxima(*e.vertex_top); + } + + Vertex* GetCurrYMaximaVertex(const Active& e) + { + Vertex* result = e.vertex_top; + if (e.wind_dx > 0) + while (result->next->pt.y == result->pt.y) result = result->next; + else + while (result->prev->pt.y == result->pt.y) result = result->prev; + if (!IsMaxima(*result)) result = nullptr; // not a maxima + return result; + } + + Active* GetMaximaPair(const Active& e) + { + Active* e2; + e2 = e.next_in_ael; + while (e2) + { + if (e2->vertex_top == e.vertex_top) return e2; // Found! + e2 = e2->next_in_ael; + } + return nullptr; + } + + Active* GetHorzMaximaPair(const Active& horz, const Vertex* vert_max) + { + //we can't be sure whether the MaximaPair is on the left or right, so ... + Active* result = horz.prev_in_ael; + while (result && result->curr_x >= vert_max->pt.x) + { + if (result->vertex_top == vert_max) return result; // Found! + result = result->prev_in_ael; + } + result = horz.next_in_ael; + while (result && TopX(*result, horz.top.y) <= vert_max->pt.x) + { + if (result->vertex_top == vert_max) return result; // Found! + result = result->next_in_ael; + } + return nullptr; + } + + inline int PointCount(OutPt* op) + { + OutPt* op2 = op; + int cnt = 0; + do + { + op2 = op2->next; + ++cnt; + } while (op2 != op); + return cnt; + } + + + inline OutPt* InsertOp(const Point64& pt, OutPt* insertAfter) + { + OutPt* result = new OutPt(pt, insertAfter->outrec); + result->next = insertAfter->next; + insertAfter->next->prev = result; + insertAfter->next = result; + result->prev = insertAfter; + return result; + } + + + inline OutPt* DisposeOutPt(OutPt* op) + { + OutPt* result = op->next; + op->prev->next = op->next; + op->next->prev = op->prev; + delete op; + return result; + } + + + inline void DisposeOutPts(OutRec& outrec) + { + if (!outrec.pts) return; + OutPt* op2 = outrec.pts->next; + while (op2 != outrec.pts) + { + OutPt* tmp = op2->next; + delete op2; + op2 = tmp; + } + delete outrec.pts; + outrec.pts = nullptr; + } + + + bool IntersectListSort(const IntersectNode& a, const IntersectNode& b) + { + //note different inequality tests ... + return (a.pt.y == b.pt.y) ? (a.pt.x < b.pt.x) : (a.pt.y > b.pt.y); + } + + + inline void SetSides(OutRec& outrec, Active& start_edge, Active& end_edge) + { + outrec.front_edge = &start_edge; + outrec.back_edge = &end_edge; + } + + + void SwapOutrecs(Active& e1, Active& e2) + { + OutRec* or1 = e1.outrec; + OutRec* or2 = e2.outrec; + if (or1 == or2) + { + Active* e = or1->front_edge; + or1->front_edge = or1->back_edge; + or1->back_edge = e; + return; + } + if (or1) + { + if (&e1 == or1->front_edge) + or1->front_edge = &e2; + else + or1->back_edge = &e2; + } + if (or2) + { + if (&e2 == or2->front_edge) + or2->front_edge = &e1; + else + or2->back_edge = &e1; + } + e1.outrec = or2; + e2.outrec = or1; + } + + + double Area(OutPt* op) + { + //https://en.wikipedia.org/wiki/Shoelace_formula + double result = 0.0; + OutPt* op2 = op; + do + { + result += static_cast(op2->prev->pt.y + op2->pt.y) * + static_cast(op2->prev->pt.x - op2->pt.x); + op2 = op2->next; + } while (op2 != op); + return result * 0.5; + } + + inline double AreaTriangle(const Point64& pt1, + const Point64& pt2, const Point64& pt3) + { + return (static_cast(pt3.y + pt1.y) * static_cast(pt3.x - pt1.x) + + static_cast(pt1.y + pt2.y) * static_cast(pt1.x - pt2.x) + + static_cast(pt2.y + pt3.y) * static_cast(pt2.x - pt3.x)); + } + + void ReverseOutPts(OutPt* op) + { + if (!op) return; + + OutPt* op1 = op; + OutPt* op2; + + do + { + op2 = op1->next; + op1->next = op1->prev; + op1->prev = op2; + op1 = op2; + } while (op1 != op); + } + + + inline void SwapSides(OutRec& outrec) + { + Active* e2 = outrec.front_edge; + outrec.front_edge = outrec.back_edge; + outrec.back_edge = e2; + outrec.pts = outrec.pts->next; + } + + + inline OutRec* GetRealOutRec(OutRec* outrec) + { + while (outrec && !outrec->pts) outrec = outrec->owner; + return outrec; + } + + + inline void UncoupleOutRec(Active ae) + { + OutRec* outrec = ae.outrec; + if (!outrec) return; + outrec->front_edge->outrec = nullptr; + outrec->back_edge->outrec = nullptr; + outrec->front_edge = nullptr; + outrec->back_edge = nullptr; + } + + + inline bool PtsReallyClose(const Point64& pt1, const Point64& pt2) + { + return (std::llabs(pt1.x - pt2.x) < 2) && (std::llabs(pt1.y - pt2.y) < 2); + } + + inline bool IsVerySmallTriangle(const OutPt& op) + { + return op.next->next == op.prev && + (PtsReallyClose(op.prev->pt, op.next->pt) || + PtsReallyClose(op.pt, op.next->pt) || + PtsReallyClose(op.pt, op.prev->pt)); + } + + inline bool IsValidClosedPath(const OutPt* op) + { + return op && (op->next != op) && (op->next != op->prev) && + !IsVerySmallTriangle(*op); + } + + inline bool OutrecIsAscending(const Active* hotEdge) + { + return (hotEdge == hotEdge->outrec->front_edge); + } + + inline void SwapFrontBackSides(OutRec& outrec) + { + Active* tmp = outrec.front_edge; + outrec.front_edge = outrec.back_edge; + outrec.back_edge = tmp; + outrec.pts = outrec.pts->next; + } + + inline bool EdgesAdjacentInAEL(const IntersectNode& inode) + { + return (inode.edge1->next_in_ael == inode.edge2) || (inode.edge1->prev_in_ael == inode.edge2); + } + + inline bool TestJoinWithPrev1(const Active& e) + { + //this is marginally quicker than TestJoinWithPrev2 + //but can only be used when e.PrevInAEL.currX is accurate + return IsHotEdge(e) && !IsOpen(e) && + e.prev_in_ael && e.prev_in_ael->curr_x == e.curr_x && + IsHotEdge(*e.prev_in_ael) && !IsOpen(*e.prev_in_ael) && + (CrossProduct(e.prev_in_ael->top, e.bot, e.top) == 0); + } + + inline bool TestJoinWithPrev2(const Active& e, const Point64& curr_pt) + { + return IsHotEdge(e) && !IsOpen(e) && + e.prev_in_ael && !IsOpen(*e.prev_in_ael) && + IsHotEdge(*e.prev_in_ael) && (e.prev_in_ael->top.y < e.bot.y) && + (std::llabs(TopX(*e.prev_in_ael, curr_pt.y) - curr_pt.x) < 2) && + (CrossProduct(e.prev_in_ael->top, curr_pt, e.top) == 0); + } + + inline bool TestJoinWithNext1(const Active& e) + { + //this is marginally quicker than TestJoinWithNext2 + //but can only be used when e.NextInAEL.currX is accurate + return IsHotEdge(e) && !IsOpen(e) && + e.next_in_ael && (e.next_in_ael->curr_x == e.curr_x) && + IsHotEdge(*e.next_in_ael) && !IsOpen(*e.next_in_ael) && + (CrossProduct(e.next_in_ael->top, e.bot, e.top) == 0); + } + + inline bool TestJoinWithNext2(const Active& e, const Point64& curr_pt) + { + return IsHotEdge(e) && !IsOpen(e) && + e.next_in_ael && !IsOpen(*e.next_in_ael) && + IsHotEdge(*e.next_in_ael) && (e.next_in_ael->top.y < e.bot.y) && + (std::llabs(TopX(*e.next_in_ael, curr_pt.y) - curr_pt.x) < 2) && + (CrossProduct(e.next_in_ael->top, curr_pt, e.top) == 0); + } + + //------------------------------------------------------------------------------ + // ClipperBase methods ... + //------------------------------------------------------------------------------ + + ClipperBase::~ClipperBase() + { + Clear(); + } + + void ClipperBase::DeleteEdges(Active*& e) + { + while (e) + { + Active* e2 = e; + e = e->next_in_ael; + delete e2; + } + } + + void ClipperBase::CleanUp() + { + DeleteEdges(actives_); + scanline_list_ = std::priority_queue(); + intersect_nodes_.clear(); + DisposeAllOutRecs(); + } + + + void ClipperBase::Clear() + { + CleanUp(); + DisposeVerticesAndLocalMinima(); + current_locmin_iter_ = minima_list_.begin(); + minima_list_sorted_ = false; + has_open_paths_ = false; + } + + + void ClipperBase::Reset() + { + if (!minima_list_sorted_) + { + std::sort(minima_list_.begin(), minima_list_.end(), LocMinSorter()); + minima_list_sorted_ = true; + } + std::vector::const_reverse_iterator i; + for (i = minima_list_.rbegin(); i != minima_list_.rend(); ++i) + InsertScanline((*i)->vertex->pt.y); + + current_locmin_iter_ = minima_list_.begin(); + actives_ = nullptr; + sel_ = nullptr; + succeeded_ = true; + } + + +#ifdef USINGZ + void ClipperBase::SetZ(const Active& e1, const Active& e2, Point64& ip) + { + if (!zCallback_) return; + // prioritize subject over clip vertices by passing + // subject vertices before clip vertices in the callback + if (GetPolyType(e1) == PathType::Subject) + { + if (ip == e1.bot) ip.z = e1.bot.z; + else if (ip == e1.top) ip.z = e1.top.z; + else if (ip == e2.bot) ip.z = e2.bot.z; + else if (ip == e2.top) ip.z = e2.top.z; + zCallback_(e1.bot, e1.top, e2.bot, e2.top, ip); + } + else + { + if (ip == e2.bot) ip.z = e2.bot.z; + else if (ip == e2.top) ip.z = e2.top.z; + else if (ip == e1.bot) ip.z = e1.bot.z; + else if (ip == e1.top) ip.z = e1.top.z; + zCallback_(e2.bot, e2.top, e1.bot, e1.top, ip); + } + } +#endif + + void ClipperBase::AddPath(const Path64& path, PathType polytype, bool is_open) + { + Paths64 tmp; + tmp.push_back(path); + AddPaths(tmp, polytype, is_open); + } + + + void ClipperBase::AddPaths(const Paths64& paths, PathType polytype, bool is_open) + { + if (is_open) has_open_paths_ = true; + minima_list_sorted_ = false; + + Path64::size_type total_vertex_count = 0; + for (const Path64& path : paths) total_vertex_count += path.size(); + if (total_vertex_count == 0) return; + Vertex* vertices = new Vertex[total_vertex_count], *v = vertices; + for (const Path64& path : paths) + { + //for each path create a circular double linked list of vertices + Vertex *v0 = v, *curr_v = v, *prev_v = nullptr; + + v->prev = nullptr; + int cnt = 0; + for (const Point64& pt : path) + { + if (prev_v) + { + if (prev_v->pt == pt) continue; // ie skips duplicates + prev_v->next = curr_v; + } + curr_v->prev = prev_v; + curr_v->pt = pt; + curr_v->flags = VertexFlags::None; + prev_v = curr_v++; + cnt++; + } + if (!prev_v || !prev_v->prev) continue; + if (!is_open && prev_v->pt == v0->pt) + prev_v = prev_v->prev; + prev_v->next = v0; + v0->prev = prev_v; + v = curr_v; // ie get ready for next path + if (cnt < 2 || (cnt == 2 && !is_open)) continue; + + //now find and assign local minima + bool going_up, going_up0; + if (is_open) + { + curr_v = v0->next; + while (curr_v != v0 && curr_v->pt.y == v0->pt.y) + curr_v = curr_v->next; + going_up = curr_v->pt.y <= v0->pt.y; + if (going_up) + { + v0->flags = VertexFlags::OpenStart; + AddLocMin(*v0, polytype, true); + } + else + v0->flags = VertexFlags::OpenStart | VertexFlags::LocalMax; + } + else // closed path + { + prev_v = v0->prev; + while (prev_v != v0 && prev_v->pt.y == v0->pt.y) + prev_v = prev_v->prev; + if (prev_v == v0) + continue; // only open paths can be completely flat + going_up = prev_v->pt.y > v0->pt.y; + } + + going_up0 = going_up; + prev_v = v0; + curr_v = v0->next; + while (curr_v != v0) + { + if (curr_v->pt.y > prev_v->pt.y && going_up) + { + prev_v->flags = (prev_v->flags | VertexFlags::LocalMax); + going_up = false; + } + else if (curr_v->pt.y < prev_v->pt.y && !going_up) + { + going_up = true; + AddLocMin(*prev_v, polytype, is_open); + } + prev_v = curr_v; + curr_v = curr_v->next; + } + + if (is_open) + { + prev_v->flags = prev_v->flags | VertexFlags::OpenEnd; + if (going_up) + prev_v->flags = prev_v->flags | VertexFlags::LocalMax; + else + AddLocMin(*prev_v, polytype, is_open); + } + else if (going_up != going_up0) + { + if (going_up0) AddLocMin(*prev_v, polytype, false); + else prev_v->flags = prev_v->flags | VertexFlags::LocalMax; + } + } // end processing current path + + vertex_lists_.emplace_back(vertices); + } // end AddPaths + + + inline void ClipperBase::InsertScanline(int64_t y) + { + scanline_list_.push(y); + } + + + bool ClipperBase::PopScanline(int64_t& y) + { + if (scanline_list_.empty()) return false; + y = scanline_list_.top(); + scanline_list_.pop(); + while (!scanline_list_.empty() && y == scanline_list_.top()) + scanline_list_.pop(); // Pop duplicates. + return true; + } + + + bool ClipperBase::PopLocalMinima(int64_t y, LocalMinima*& local_minima) + { + if (current_locmin_iter_ == minima_list_.end() || (*current_locmin_iter_)->vertex->pt.y != y) return false; + local_minima = (*current_locmin_iter_++); + return true; + } + + + void ClipperBase::DisposeAllOutRecs() + { + for (auto outrec : outrec_list_) + { + if (outrec->pts) DisposeOutPts(*outrec); + delete outrec; + } + outrec_list_.resize(0); + } + + + void ClipperBase::DisposeVerticesAndLocalMinima() + { + for (auto lm : minima_list_) delete lm; + minima_list_.clear(); + for (auto v : vertex_lists_) delete[] v; + vertex_lists_.clear(); + } + + + void ClipperBase::AddLocMin(Vertex& vert, PathType polytype, bool is_open) + { + //make sure the vertex is added only once ... + if ((VertexFlags::LocalMin & vert.flags) != VertexFlags::None) return; + + vert.flags = (vert.flags | VertexFlags::LocalMin); + minima_list_.push_back(new LocalMinima(&vert, polytype, is_open)); + } + + bool ClipperBase::IsContributingClosed(const Active & e) const + { + switch (fillrule_) + { + case FillRule::EvenOdd: + break; + case FillRule::NonZero: + if (abs(e.wind_cnt) != 1) return false; + break; + case FillRule::Positive: + if (e.wind_cnt != 1) return false; + break; + case FillRule::Negative: + if (e.wind_cnt != -1) return false; + break; + } + + switch (cliptype_) + { + case ClipType::None: + return false; + case ClipType::Intersection: + switch (fillrule_) + { + case FillRule::Positive: + return (e.wind_cnt2 > 0); + case FillRule::Negative: + return (e.wind_cnt2 < 0); + default: + return (e.wind_cnt2 != 0); + } + break; + + case ClipType::Union: + switch (fillrule_) + { + case FillRule::Positive: + return (e.wind_cnt2 <= 0); + case FillRule::Negative: + return (e.wind_cnt2 >= 0); + default: + return (e.wind_cnt2 == 0); + } + break; + + case ClipType::Difference: + bool result; + switch (fillrule_) + { + case FillRule::Positive: + result = (e.wind_cnt2 <= 0); + break; + case FillRule::Negative: + result = (e.wind_cnt2 >= 0); + break; + default: + result = (e.wind_cnt2 == 0); + } + if (GetPolyType(e) == PathType::Subject) + return result; + else + return !result; + break; + + case ClipType::Xor: return true; break; + } + return false; // we should never get here + } + + + inline bool ClipperBase::IsContributingOpen(const Active& e) const + { + bool is_in_clip, is_in_subj; + switch (fillrule_) + { + case FillRule::Positive: + is_in_clip = e.wind_cnt2 > 0; + is_in_subj = e.wind_cnt > 0; + break; + case FillRule::Negative: + is_in_clip = e.wind_cnt2 < 0; + is_in_subj = e.wind_cnt < 0; + break; + default: + is_in_clip = e.wind_cnt2 != 0; + is_in_subj = e.wind_cnt != 0; + } + + switch (cliptype_) + { + case ClipType::Intersection: return is_in_clip; + case ClipType::Union: return (!is_in_subj && !is_in_clip); + default: return !is_in_clip; + } + } + + + void ClipperBase::SetWindCountForClosedPathEdge(Active& e) + { + //Wind counts refer to polygon regions not edges, so here an edge's WindCnt + //indicates the higher of the wind counts for the two regions touching the + //edge. (NB Adjacent regions can only ever have their wind counts differ by + //one. Also, open paths have no meaningful wind directions or counts.) + + Active* e2 = e.prev_in_ael; + //find the nearest closed path edge of the same PolyType in AEL (heading left) + PathType pt = GetPolyType(e); + while (e2 && (GetPolyType(*e2) != pt || IsOpen(*e2))) e2 = e2->prev_in_ael; + + if (!e2) + { + e.wind_cnt = e.wind_dx; + e2 = actives_; + } + else if (fillrule_ == FillRule::EvenOdd) + { + e.wind_cnt = e.wind_dx; + e.wind_cnt2 = e2->wind_cnt2; + e2 = e2->next_in_ael; + } + else + { + //NonZero, positive, or negative filling here ... + //if e's WindCnt is in the SAME direction as its WindDx, then polygon + //filling will be on the right of 'e'. + //NB neither e2.WindCnt nor e2.WindDx should ever be 0. + if (e2->wind_cnt * e2->wind_dx < 0) + { + //opposite directions so 'e' is outside 'e2' ... + if (abs(e2->wind_cnt) > 1) + { + //outside prev poly but still inside another. + if (e2->wind_dx * e.wind_dx < 0) + //reversing direction so use the same WC + e.wind_cnt = e2->wind_cnt; + else + //otherwise keep 'reducing' the WC by 1 (ie towards 0) ... + e.wind_cnt = e2->wind_cnt + e.wind_dx; + } + else + //now outside all polys of same polytype so set own WC ... + e.wind_cnt = (IsOpen(e) ? 1 : e.wind_dx); + } + else + { + //'e' must be inside 'e2' + if (e2->wind_dx * e.wind_dx < 0) + //reversing direction so use the same WC + e.wind_cnt = e2->wind_cnt; + else + //otherwise keep 'increasing' the WC by 1 (ie away from 0) ... + e.wind_cnt = e2->wind_cnt + e.wind_dx; + } + e.wind_cnt2 = e2->wind_cnt2; + e2 = e2->next_in_ael; // ie get ready to calc WindCnt2 + } + + //update wind_cnt2 ... + if (fillrule_ == FillRule::EvenOdd) + while (e2 != &e) + { + if (GetPolyType(*e2) != pt && !IsOpen(*e2)) + e.wind_cnt2 = (e.wind_cnt2 == 0 ? 1 : 0); + e2 = e2->next_in_ael; + } + else + while (e2 != &e) + { + if (GetPolyType(*e2) != pt && !IsOpen(*e2)) + e.wind_cnt2 += e2->wind_dx; + e2 = e2->next_in_ael; + } + } + + + void ClipperBase::SetWindCountForOpenPathEdge(Active& e) + { + Active* e2 = actives_; + if (fillrule_ == FillRule::EvenOdd) + { + int cnt1 = 0, cnt2 = 0; + while (e2 != &e) + { + if (GetPolyType(*e2) == PathType::Clip) + cnt2++; + else if (!IsOpen(*e2)) + cnt1++; + e2 = e2->next_in_ael; + } + e.wind_cnt = (IsOdd(cnt1) ? 1 : 0); + e.wind_cnt2 = (IsOdd(cnt2) ? 1 : 0); + } + else + { + while (e2 != &e) + { + if (GetPolyType(*e2) == PathType::Clip) + e.wind_cnt2 += e2->wind_dx; + else if (!IsOpen(*e2)) + e.wind_cnt += e2->wind_dx; + e2 = e2->next_in_ael; + } + } + } + + + bool IsValidAelOrder(const Active& resident, const Active& newcomer) + { + if (newcomer.curr_x != resident.curr_x) + return newcomer.curr_x > resident.curr_x; + + //get the turning direction a1.top, a2.bot, a2.top + double d = CrossProduct(resident.top, newcomer.bot, newcomer.top); + if (d != 0) return d < 0; + + //edges must be collinear to get here + //for starting open paths, place them according to + //the direction they're about to turn + if (!IsMaxima(resident) && (resident.top.y > newcomer.top.y)) + { + return CrossProduct(newcomer.bot, + resident.top, NextVertex(resident)->pt) <= 0; + } + else if (!IsMaxima(newcomer) && (newcomer.top.y > resident.top.y)) + { + return CrossProduct(newcomer.bot, + newcomer.top, NextVertex(newcomer)->pt) >= 0; + } + + int64_t y = newcomer.bot.y; + bool newcomerIsLeft = newcomer.is_left_bound; + + if (resident.bot.y != y || resident.local_min->vertex->pt.y != y) + return newcomer.is_left_bound; + //resident must also have just been inserted + else if (resident.is_left_bound != newcomerIsLeft) + return newcomerIsLeft; + else if (CrossProduct(PrevPrevVertex(resident)->pt, + resident.bot, resident.top) == 0) return true; + else + //compare turning direction of the alternate bound + return (CrossProduct(PrevPrevVertex(resident)->pt, + newcomer.bot, PrevPrevVertex(newcomer)->pt) > 0) == newcomerIsLeft; + } + + + void ClipperBase::InsertLeftEdge(Active& e) + { + Active* e2; + if (!actives_) + { + e.prev_in_ael = nullptr; + e.next_in_ael = nullptr; + actives_ = &e; + } + else if (!IsValidAelOrder(*actives_, e)) + { + e.prev_in_ael = nullptr; + e.next_in_ael = actives_; + actives_->prev_in_ael = &e; + actives_ = &e; + } + else + { + e2 = actives_; + while (e2->next_in_ael && IsValidAelOrder(*e2->next_in_ael, e)) + e2 = e2->next_in_ael; + e.next_in_ael = e2->next_in_ael; + if (e2->next_in_ael) e2->next_in_ael->prev_in_ael = &e; + e.prev_in_ael = e2; + e2->next_in_ael = &e; + } + } + + + void InsertRightEdge(Active& e, Active& e2) + { + e2.next_in_ael = e.next_in_ael; + if (e.next_in_ael) e.next_in_ael->prev_in_ael = &e2; + e2.prev_in_ael = &e; + e.next_in_ael = &e2; + } + + + void ClipperBase::InsertLocalMinimaIntoAEL(int64_t bot_y) + { + LocalMinima* local_minima; + Active* left_bound, * right_bound; + //Add any local minima (if any) at BotY ... + //nb: horizontal local minima edges should contain locMin.vertex.prev + + while (PopLocalMinima(bot_y, local_minima)) + { + if ((local_minima->vertex->flags & VertexFlags::OpenStart) != VertexFlags::None) + { + left_bound = nullptr; + } + else + { + left_bound = new Active(); + left_bound->bot = local_minima->vertex->pt; + left_bound->curr_x = left_bound->bot.x; + left_bound->wind_cnt = 0, + left_bound->wind_cnt2 = 0, + left_bound->wind_dx = -1, + left_bound->vertex_top = local_minima->vertex->prev; // ie descending + left_bound->top = left_bound->vertex_top->pt; + left_bound->outrec = nullptr; + left_bound->local_min = local_minima; + SetDx(*left_bound); + } + + if ((local_minima->vertex->flags & VertexFlags::OpenEnd) != VertexFlags::None) + { + right_bound = nullptr; + } + else + { + right_bound = new Active(); + right_bound->bot = local_minima->vertex->pt; + right_bound->curr_x = right_bound->bot.x; + right_bound->wind_cnt = 0, + right_bound->wind_cnt2 = 0, + right_bound->wind_dx = 1, + right_bound->vertex_top = local_minima->vertex->next; // ie ascending + right_bound->top = right_bound->vertex_top->pt; + right_bound->outrec = nullptr; + right_bound->local_min = local_minima; + SetDx(*right_bound); + } + + //Currently LeftB is just the descending bound and RightB is the ascending. + //Now if the LeftB isn't on the left of RightB then we need swap them. + if (left_bound && right_bound) + { + if (IsHorizontal(*left_bound)) + { + if (IsHeadingRightHorz(*left_bound)) SwapActives(left_bound, right_bound); + } + else if (IsHorizontal(*right_bound)) + { + if (IsHeadingLeftHorz(*right_bound)) SwapActives(left_bound, right_bound); + } + else if (left_bound->dx < right_bound->dx) + SwapActives(left_bound, right_bound); + } + else if (!left_bound) + { + left_bound = right_bound; + right_bound = nullptr; + } + + bool contributing; + left_bound->is_left_bound = true; + InsertLeftEdge(*left_bound); + + if (IsOpen(*left_bound)) + { + SetWindCountForOpenPathEdge(*left_bound); + contributing = IsContributingOpen(*left_bound); + } + else + { + SetWindCountForClosedPathEdge(*left_bound); + contributing = IsContributingClosed(*left_bound); + } + + if (right_bound) + { + right_bound->is_left_bound = false; + right_bound->wind_cnt = left_bound->wind_cnt; + right_bound->wind_cnt2 = left_bound->wind_cnt2; + InsertRightEdge(*left_bound, *right_bound); /////// + if (contributing) + { + AddLocalMinPoly(*left_bound, *right_bound, left_bound->bot, true); + if (!IsHorizontal(*left_bound) && TestJoinWithPrev1(*left_bound)) + { + OutPt* op = AddOutPt(*left_bound->prev_in_ael, left_bound->bot); + AddJoin(op, left_bound->outrec->pts); + } + } + + while (right_bound->next_in_ael && + IsValidAelOrder(*right_bound->next_in_ael, *right_bound)) + { + IntersectEdges(*right_bound, *right_bound->next_in_ael, right_bound->bot); + SwapPositionsInAEL(*right_bound, *right_bound->next_in_ael); + } + + if (!IsHorizontal(*right_bound) && + TestJoinWithNext1(*right_bound)) + { + OutPt* op = AddOutPt(*right_bound->next_in_ael, right_bound->bot); + AddJoin(right_bound->outrec->pts, op); + } + + if (IsHorizontal(*right_bound)) + PushHorz(*right_bound); + else + InsertScanline(right_bound->top.y); + } + else if (contributing) + { + StartOpenPath(*left_bound, left_bound->bot); + } + + if (IsHorizontal(*left_bound)) + PushHorz(*left_bound); + else + InsertScanline(left_bound->top.y); + } // while (PopLocalMinima()) + } + + + inline void ClipperBase::PushHorz(Active& e) + { + e.next_in_sel = (sel_ ? sel_ : nullptr); + sel_ = &e; + } + + + inline bool ClipperBase::PopHorz(Active*& e) + { + e = sel_; + if (!e) return false; + sel_ = sel_->next_in_sel; + return true; + } + + + OutPt* ClipperBase::AddLocalMinPoly(Active& e1, Active& e2, + const Point64& pt, bool is_new) + { + OutRec* outrec = new OutRec(); + outrec->idx = (unsigned)outrec_list_.size(); + outrec_list_.push_back(outrec); + outrec->pts = nullptr; + outrec->polypath = nullptr; + e1.outrec = outrec; + e2.outrec = outrec; + + //Setting the owner and inner/outer states (above) is an essential + //precursor to setting edge 'sides' (ie left and right sides of output + //polygons) and hence the orientation of output paths ... + + if (IsOpen(e1)) + { + outrec->owner = nullptr; + outrec->is_open = true; + if (e1.wind_dx > 0) + SetSides(*outrec, e1, e2); + else + SetSides(*outrec, e2, e1); + } + else + { + Active* prevHotEdge = GetPrevHotEdge(e1); + //e.windDx is the winding direction of the **input** paths + //and unrelated to the winding direction of output polygons. + //Output orientation is determined by e.outrec.frontE which is + //the ascending edge (see AddLocalMinPoly). + if (prevHotEdge) + { + outrec->owner = prevHotEdge->outrec; + if (OutrecIsAscending(prevHotEdge) == is_new) + SetSides(*outrec, e2, e1); + else + SetSides(*outrec, e1, e2); + } + else + { + outrec->owner = nullptr; + if (is_new) + SetSides(*outrec, e1, e2); + else + SetSides(*outrec, e2, e1); + } + } + + OutPt* op = new OutPt(pt, outrec); + outrec->pts = op; + return op; + } + + + OutPt* ClipperBase::AddLocalMaxPoly(Active& e1, Active& e2, const Point64& pt) + { + if (IsFront(e1) == IsFront(e2)) + { + if (IsOpenEnd(e1)) + SwapFrontBackSides(*e1.outrec); + else if (IsOpenEnd(e2)) + SwapFrontBackSides(*e2.outrec); + else + { + succeeded_ = false; + return nullptr; + } + } + + OutPt* result = AddOutPt(e1, pt); + if (e1.outrec == e2.outrec) + { + OutRec& outrec = *e1.outrec; + outrec.pts = result; + + UncoupleOutRec(e1); + if (!IsOpen(e1)) CleanCollinear(&outrec); + result = outrec.pts; + if (using_polytree_ && outrec.owner && !outrec.owner->front_edge) + outrec.owner = GetRealOutRec(outrec.owner->owner); + } + //and to preserve the winding orientation of outrec ... + else if (IsOpen(e1)) + { + if (e1.wind_dx < 0) + JoinOutrecPaths(e1, e2); + else + JoinOutrecPaths(e2, e1); + } + else if (e1.outrec->idx < e2.outrec->idx) + JoinOutrecPaths(e1, e2); + else + JoinOutrecPaths(e2, e1); + + return result; + } + + void ClipperBase::JoinOutrecPaths(Active& e1, Active& e2) + { + //join e2 outrec path onto e1 outrec path and then delete e2 outrec path + //pointers. (NB Only very rarely do the joining ends share the same coords.) + OutPt* p1_st = e1.outrec->pts; + OutPt* p2_st = e2.outrec->pts; + OutPt* p1_end = p1_st->next; + OutPt* p2_end = p2_st->next; + if (IsFront(e1)) + { + p2_end->prev = p1_st; + p1_st->next = p2_end; + p2_st->next = p1_end; + p1_end->prev = p2_st; + e1.outrec->pts = p2_st; + e1.outrec->front_edge = e2.outrec->front_edge; + if (e1.outrec->front_edge) + e1.outrec->front_edge->outrec = e1.outrec; + } + else + { + p1_end->prev = p2_st; + p2_st->next = p1_end; + p1_st->next = p2_end; + p2_end->prev = p1_st; + e1.outrec->back_edge = e2.outrec->back_edge; + if (e1.outrec->back_edge) + e1.outrec->back_edge->outrec = e1.outrec; + } + + //an owner must have a lower idx otherwise + //it can't be a valid owner + if (e2.outrec->owner && e2.outrec->owner->idx < e1.outrec->idx) + { + if (!e1.outrec->owner || e2.outrec->owner->idx < e1.outrec->owner->idx) + e1.outrec->owner = e2.outrec->owner; + } + + //after joining, the e2.OutRec must contains no vertices ... + e2.outrec->front_edge = nullptr; + e2.outrec->back_edge = nullptr; + e2.outrec->pts = nullptr; + e2.outrec->owner = e1.outrec; + + if (IsOpenEnd(e1)) + { + e2.outrec->pts = e1.outrec->pts; + e1.outrec->pts = nullptr; + } + + //and e1 and e2 are maxima and are about to be dropped from the Actives list. + e1.outrec = nullptr; + e2.outrec = nullptr; + } + + + OutPt* ClipperBase::AddOutPt(const Active& e, const Point64& pt) + { + OutPt* new_op = nullptr; + + //Outrec.OutPts: a circular doubly-linked-list of POutPt where ... + //op_front[.Prev]* ~~~> op_back & op_back == op_front.Next + OutRec* outrec = e.outrec; + bool to_front = IsFront(e); + OutPt* op_front = outrec->pts; + OutPt* op_back = op_front->next; + + if (to_front && (pt == op_front->pt)) + new_op = op_front; + else if (!to_front && (pt == op_back->pt)) + new_op = op_back; + else + { + new_op = new OutPt(pt, outrec); + op_back->prev = new_op; + new_op->prev = op_front; + new_op->next = op_back; + op_front->next = new_op; + if (to_front) outrec->pts = new_op; + } + return new_op; + } + + + bool ClipperBase::ValidateClosedPathEx(OutPt*& outpt) + { + if (IsValidClosedPath(outpt)) return true; + if (outpt) SafeDisposeOutPts(outpt); + return false; + } + + + void ClipperBase::CleanCollinear(OutRec* outrec) + { + outrec = GetRealOutRec(outrec); + if (!outrec || outrec->is_open || + outrec->front_edge || !ValidateClosedPathEx(outrec->pts)) return; + + OutPt* startOp = outrec->pts, * op2 = startOp; + for (; ; ) + { + if (op2->joiner) return; + + //NB if preserveCollinear == true, then only remove 180 deg. spikes + if ((CrossProduct(op2->prev->pt, op2->pt, op2->next->pt) == 0) && + (op2->pt == op2->prev->pt || + op2->pt == op2->next->pt || !PreserveCollinear || + DotProduct(op2->prev->pt, op2->pt, op2->next->pt) < 0)) + { + + if (op2 == outrec->pts) outrec->pts = op2->prev; + + op2 = DisposeOutPt(op2); + if (!ValidateClosedPathEx(op2)) + { + outrec->pts = nullptr; + return; + } + startOp = op2; + continue; + } + op2 = op2->next; + if (op2 == startOp) break; + } + FixSelfIntersects(outrec); + } + + void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp) + { + // splitOp.prev -> splitOp && + // splitOp.next -> splitOp.next.next are intersecting + OutPt* prevOp = splitOp->prev; + OutPt* nextNextOp = splitOp->next->next; + outrec->pts = prevOp; + PointD ipD; + GetIntersectPoint(prevOp->pt, + splitOp->pt, splitOp->next->pt, nextNextOp->pt, ipD); + Point64 ip = Point64(ipD); +#ifdef USINGZ + if (zCallback_) + zCallback_(prevOp->pt, splitOp->pt, splitOp->next->pt, nextNextOp->pt, ip); +#endif + double area1 = Area(outrec->pts); + double absArea1 = std::fabs(area1); + if (absArea1 < 2) + { + SafeDisposeOutPts(outrec->pts); + // outrec.pts == nil; :) + return; + } + + // nb: area1 is the path's area *before* splitting, whereas area2 is + // the area of the triangle containing splitOp & splitOp.next. + // So the only way for these areas to have the same sign is if + // the split triangle is larger than the path containing prevOp or + // if there's more than one self=intersection. + double area2 = AreaTriangle(ip, splitOp->pt, splitOp->next->pt); + double absArea2 = std::fabs(area2); + + // de-link splitOp and splitOp.next from the path + // while inserting the intersection point + if (ip == prevOp->pt || ip == nextNextOp->pt) + { + nextNextOp->prev = prevOp; + prevOp->next = nextNextOp; + } + else + { + OutPt* newOp2 = new OutPt(ip, prevOp->outrec); + newOp2->prev = prevOp; + newOp2->next = nextNextOp; + nextNextOp->prev = newOp2; + prevOp->next = newOp2; + } + + SafeDeleteOutPtJoiners(splitOp->next); + SafeDeleteOutPtJoiners(splitOp); + + if (absArea2 >= 1 && + (absArea2 > absArea1 || (area2 > 0) == (area1 > 0))) + { + OutRec* newOutRec = new OutRec(); + newOutRec->idx = outrec_list_.size(); + outrec_list_.push_back(newOutRec); + newOutRec->owner = prevOp->outrec->owner; + newOutRec->polypath = nullptr; + splitOp->outrec = newOutRec; + splitOp->next->outrec = newOutRec; + + OutPt* newOp = new OutPt(ip, newOutRec); + newOp->prev = splitOp->next; + newOp->next = splitOp; + newOutRec->pts = newOp; + splitOp->prev = newOp; + splitOp->next->next = newOp; + } + else + { + delete splitOp->next; + delete splitOp; + } + } + + void ClipperBase::FixSelfIntersects(OutRec* outrec) + { + OutPt* op2 = outrec->pts; + for (; ; ) + { + // triangles can't self-intersect + if (op2->prev == op2->next->next) break; + if (SegmentsIntersect(op2->prev->pt, + op2->pt, op2->next->pt, op2->next->next->pt)) + { + if (op2 == outrec->pts || op2->next == outrec->pts) + outrec->pts = outrec->pts->prev; + DoSplitOp(outrec, op2); + if (!outrec->pts) break; + op2 = outrec->pts; + continue; + } + else + op2 = op2->next; + + if (op2 == outrec->pts) break; + } + } + + + inline void UpdateOutrecOwner(OutRec* outrec) + { + OutPt* opCurr = outrec->pts; + for (; ; ) + { + opCurr->outrec = outrec; + opCurr = opCurr->next; + if (opCurr == outrec->pts) return; + } + } + + + void ClipperBase::SafeDisposeOutPts(OutPt*& op) + { + OutRec* outrec = GetRealOutRec(op->outrec); + if (outrec->front_edge) + outrec->front_edge->outrec = nullptr; + if (outrec->back_edge) + outrec->back_edge->outrec = nullptr; + + op->prev->next = nullptr; + while (op) + { + SafeDeleteOutPtJoiners(op); + OutPt* tmp = op->next; + delete op; + op = tmp; + } + outrec->pts = nullptr; + } + + + void ClipperBase::CompleteSplit(OutPt* op1, OutPt* op2, OutRec& outrec) + { + double area1 = Area(op1); + double area2 = Area(op2); + bool signs_change = (area1 > 0) == (area2 < 0); + + if (area1 == 0 || (signs_change && std::abs(area1) < 2)) + { + SafeDisposeOutPts(op1); + outrec.pts = op2; + } + else if (area2 == 0 || (signs_change && std::abs(area2) < 2)) + { + SafeDisposeOutPts(op2); + outrec.pts = op1; + } + else + { + OutRec* newOr = new OutRec(); + newOr->idx = outrec_list_.size(); + outrec_list_.push_back(newOr); + newOr->polypath = nullptr; + + if (using_polytree_) + { + if (!outrec.splits) outrec.splits = new OutRecList(); + outrec.splits->push_back(newOr); + } + + if (std::abs(area1) >= std::abs(area2)) + { + outrec.pts = op1; + newOr->pts = op2; + } + else + { + outrec.pts = op2; + newOr->pts = op1; + } + + if ((area1 > 0) == (area2 > 0)) + newOr->owner = outrec.owner; + else + newOr->owner = &outrec; + + UpdateOutrecOwner(newOr); + CleanCollinear(newOr); + } + } + + + OutPt* ClipperBase::StartOpenPath(Active& e, const Point64& pt) + { + OutRec* outrec = new OutRec(); + outrec->idx = outrec_list_.size(); + outrec_list_.push_back(outrec); + outrec->owner = nullptr; + outrec->is_open = true; + outrec->pts = nullptr; + outrec->polypath = nullptr; + + if (e.wind_dx > 0) + { + outrec->front_edge = &e; + outrec->back_edge = nullptr; + } + else + { + outrec->front_edge = nullptr; + outrec->back_edge =& e; + } + + e.outrec = outrec; + + OutPt* op = new OutPt(pt, outrec); + outrec->pts = op; + return op; + } + + + inline void ClipperBase::UpdateEdgeIntoAEL(Active* e) + { + e->bot = e->top; + e->vertex_top = NextVertex(*e); + e->top = e->vertex_top->pt; + e->curr_x = e->bot.x; + SetDx(*e); + if (IsHorizontal(*e)) return; + InsertScanline(e->top.y); + if (TestJoinWithPrev1(*e)) + { + OutPt* op1 = AddOutPt(*e->prev_in_ael, e->bot); + OutPt* op2 = AddOutPt(*e, e->bot); + AddJoin(op1, op2); + } + } + + + Active* FindEdgeWithMatchingLocMin(Active* e) + { + Active* result = e->next_in_ael; + while (result) + { + if (result->local_min == e->local_min) return result; + else if (!IsHorizontal(*result) && e->bot != result->bot) result = nullptr; + else result = result->next_in_ael; + } + result = e->prev_in_ael; + while (result) + { + if (result->local_min == e->local_min) return result; + else if (!IsHorizontal(*result) && e->bot != result->bot) return nullptr; + else result = result->prev_in_ael; + } + return result; + } + + + OutPt* ClipperBase::IntersectEdges(Active& e1, Active& e2, const Point64& pt) + { + //MANAGE OPEN PATH INTERSECTIONS SEPARATELY ... + if (has_open_paths_ && (IsOpen(e1) || IsOpen(e2))) + { + if (IsOpen(e1) && IsOpen(e2)) return nullptr; + + Active* edge_o, * edge_c; + if (IsOpen(e1)) + { + edge_o = &e1; + edge_c = &e2; + } + else + { + edge_o = &e2; + edge_c = &e1; + } + + if (abs(edge_c->wind_cnt) != 1) return nullptr; + switch (cliptype_) + { + case ClipType::Union: + if (!IsHotEdge(*edge_c)) return nullptr; + break; + default: + if (edge_c->local_min->polytype == PathType::Subject) + return nullptr; + } + + switch (fillrule_) + { + case FillRule::Positive: if (edge_c->wind_cnt != 1) return nullptr; break; + case FillRule::Negative: if (edge_c->wind_cnt != -1) return nullptr; break; + default: if (std::abs(edge_c->wind_cnt) != 1) return nullptr; break; + } + + //toggle contribution ... + if (IsHotEdge(*edge_o)) + { + OutPt* resultOp = AddOutPt(*edge_o, pt); +#ifdef USINGZ + if (zCallback_) SetZ(e1, e2, resultOp->pt); +#endif + if (IsFront(*edge_o)) edge_o->outrec->front_edge = nullptr; + else edge_o->outrec->back_edge = nullptr; + edge_o->outrec = nullptr; + return resultOp; + } + + //horizontal edges can pass under open paths at a LocMins + else if (pt == edge_o->local_min->vertex->pt && + !IsOpenEnd(*edge_o->local_min->vertex)) + { + //find the other side of the LocMin and + //if it's 'hot' join up with it ... + Active* e3 = FindEdgeWithMatchingLocMin(edge_o); + if (e3 && IsHotEdge(*e3)) + { + edge_o->outrec = e3->outrec; + if (edge_o->wind_dx > 0) + SetSides(*e3->outrec, *edge_o, *e3); + else + SetSides(*e3->outrec, *e3, *edge_o); + return e3->outrec->pts; + } + else + return StartOpenPath(*edge_o, pt); + } + else + return StartOpenPath(*edge_o, pt); + } + + + //MANAGING CLOSED PATHS FROM HERE ON + + //UPDATE WINDING COUNTS... + + int old_e1_windcnt, old_e2_windcnt; + if (e1.local_min->polytype == e2.local_min->polytype) + { + if (fillrule_ == FillRule::EvenOdd) + { + old_e1_windcnt = e1.wind_cnt; + e1.wind_cnt = e2.wind_cnt; + e2.wind_cnt = old_e1_windcnt; + } + else + { + if (e1.wind_cnt + e2.wind_dx == 0) + e1.wind_cnt = -e1.wind_cnt; + else + e1.wind_cnt += e2.wind_dx; + if (e2.wind_cnt - e1.wind_dx == 0) + e2.wind_cnt = -e2.wind_cnt; + else + e2.wind_cnt -= e1.wind_dx; + } + } + else + { + if (fillrule_ != FillRule::EvenOdd) + { + e1.wind_cnt2 += e2.wind_dx; + e2.wind_cnt2 -= e1.wind_dx; + } + else + { + e1.wind_cnt2 = (e1.wind_cnt2 == 0 ? 1 : 0); + e2.wind_cnt2 = (e2.wind_cnt2 == 0 ? 1 : 0); + } + } + + switch (fillrule_) + { + case FillRule::EvenOdd: + case FillRule::NonZero: + old_e1_windcnt = abs(e1.wind_cnt); + old_e2_windcnt = abs(e2.wind_cnt); + break; + default: + if (fillrule_ == fillpos) + { + old_e1_windcnt = e1.wind_cnt; + old_e2_windcnt = e2.wind_cnt; + } + else + { + old_e1_windcnt = -e1.wind_cnt; + old_e2_windcnt = -e2.wind_cnt; + } + break; + } + + const bool e1_windcnt_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1; + const bool e2_windcnt_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1; + + if ((!IsHotEdge(e1) && !e1_windcnt_in_01) || (!IsHotEdge(e2) && !e2_windcnt_in_01)) + { + return nullptr; + } + + //NOW PROCESS THE INTERSECTION ... + OutPt* resultOp = nullptr; + //if both edges are 'hot' ... + if (IsHotEdge(e1) && IsHotEdge(e2)) + { + if ((old_e1_windcnt != 0 && old_e1_windcnt != 1) || (old_e2_windcnt != 0 && old_e2_windcnt != 1) || + (e1.local_min->polytype != e2.local_min->polytype && cliptype_ != ClipType::Xor)) + { + resultOp = AddLocalMaxPoly(e1, e2, pt); +#ifdef USINGZ + if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt); +#endif + } + else if (IsFront(e1) || (e1.outrec == e2.outrec)) + { + //this 'else if' condition isn't strictly needed but + //it's sensible to split polygons that ony touch at + //a common vertex (not at common edges). + + resultOp = AddLocalMaxPoly(e1, e2, pt); + OutPt* op2 = AddLocalMinPoly(e1, e2, pt); +#ifdef USINGZ + if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt); + if (zCallback_) SetZ(e1, e2, op2->pt); +#endif + if (resultOp && resultOp->pt == op2->pt && + !IsHorizontal(e1) && !IsHorizontal(e2) && + (CrossProduct(e1.bot, resultOp->pt, e2.bot) == 0)) + AddJoin(resultOp, op2); + } + else + { + resultOp = AddOutPt(e1, pt); +#ifdef USINGZ + OutPt* op2 = AddOutPt(e2, pt); + if (zCallback_) + { + SetZ(e1, e2, resultOp->pt); + SetZ(e1, e2, op2->pt); + } +#else + AddOutPt(e2, pt); +#endif + SwapOutrecs(e1, e2); + } + } + else if (IsHotEdge(e1)) + { + resultOp = AddOutPt(e1, pt); +#ifdef USINGZ + if (zCallback_) SetZ(e1, e2, resultOp->pt); +#endif + SwapOutrecs(e1, e2); + } + else if (IsHotEdge(e2)) + { + resultOp = AddOutPt(e2, pt); +#ifdef USINGZ + if (zCallback_) SetZ(e1, e2, resultOp->pt); +#endif + SwapOutrecs(e1, e2); + } + else + { + int64_t e1Wc2, e2Wc2; + switch (fillrule_) + { + case FillRule::EvenOdd: + case FillRule::NonZero: + e1Wc2 = abs(e1.wind_cnt2); + e2Wc2 = abs(e2.wind_cnt2); + break; + default: + if (fillrule_ == fillpos) + { + e1Wc2 = e1.wind_cnt2; + e2Wc2 = e2.wind_cnt2; + } + else + { + e1Wc2 = -e1.wind_cnt2; + e2Wc2 = -e2.wind_cnt2; + } + break; + } + + if (!IsSamePolyType(e1, e2)) + { + resultOp = AddLocalMinPoly(e1, e2, pt, false); +#ifdef USINGZ + if (zCallback_) SetZ(e1, e2, resultOp->pt); +#endif + } + else if (old_e1_windcnt == 1 && old_e2_windcnt == 1) + { + resultOp = nullptr; + switch (cliptype_) + { + case ClipType::Union: + if (e1Wc2 <= 0 && e2Wc2 <= 0) + resultOp = AddLocalMinPoly(e1, e2, pt, false); + break; + case ClipType::Difference: + if (((GetPolyType(e1) == PathType::Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((GetPolyType(e1) == PathType::Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + { + resultOp = AddLocalMinPoly(e1, e2, pt, false); + } + break; + case ClipType::Xor: + resultOp = AddLocalMinPoly(e1, e2, pt, false); + break; + default: + if (e1Wc2 > 0 && e2Wc2 > 0) + resultOp = AddLocalMinPoly(e1, e2, pt, false); + break; + } +#ifdef USINGZ + if (resultOp && zCallback_) SetZ(e1, e2, resultOp->pt); +#endif + } + } + return resultOp; + } + + + inline void ClipperBase::DeleteFromAEL(Active& e) + { + Active* prev = e.prev_in_ael; + Active* next = e.next_in_ael; + if (!prev && !next && (&e != actives_)) return; // already deleted + if (prev) + prev->next_in_ael = next; + else + actives_ = next; + if (next) next->prev_in_ael = prev; + delete& e; + } + + + inline void ClipperBase::AdjustCurrXAndCopyToSEL(const int64_t top_y) + { + Active* e = actives_; + sel_ = e; + while (e) + { + e->prev_in_sel = e->prev_in_ael; + e->next_in_sel = e->next_in_ael; + e->jump = e->next_in_sel; + e->curr_x = TopX(*e, top_y); + e = e->next_in_ael; + } + } + + + bool ClipperBase::ExecuteInternal(ClipType ct, FillRule fillrule, bool use_polytrees) + { + cliptype_ = ct; + fillrule_ = fillrule; + using_polytree_ = use_polytrees; + Reset(); + int64_t y; + if (ct == ClipType::None || !PopScanline(y)) return true; + + while (succeeded_) + { + InsertLocalMinimaIntoAEL(y); + Active* e; + while (PopHorz(e)) DoHorizontal(*e); + if (horz_joiners_) ConvertHorzTrialsToJoins(); + bot_y_ = y; // bot_y_ == bottom of scanbeam + if (!PopScanline(y)) break; // y new top of scanbeam + DoIntersections(y); + DoTopOfScanbeam(y); + while (PopHorz(e)) DoHorizontal(*e); + } + ProcessJoinerList(); + return succeeded_; + } + + void ClipperBase::DoIntersections(const int64_t top_y) + { + if (BuildIntersectList(top_y)) + { + ProcessIntersectList(); + intersect_nodes_.clear(); + } + } + + void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y) + { + Point64 pt = GetIntersectPoint(e1, e2); + + //rounding errors can occasionally place the calculated intersection + //point either below or above the scanbeam, so check and correct ... + if (pt.y > bot_y_) + { + //e.curr.y is still the bottom of scanbeam + pt.y = bot_y_; + //use the more vertical of the 2 edges to derive pt.x ... + if (abs(e1.dx) < abs(e2.dx)) + pt.x = TopX(e1, bot_y_); + else + pt.x = TopX(e2, bot_y_); + } + else if (pt.y < top_y) + { + //top_y is at the top of the scanbeam + pt.y = top_y; + if (e1.top.y == top_y) + pt.x = e1.top.x; + else if (e2.top.y == top_y) + pt.x = e2.top.x; + else if (abs(e1.dx) < abs(e2.dx)) + pt.x = e1.curr_x; + else + pt.x = e2.curr_x; + } + + intersect_nodes_.push_back(IntersectNode(&e1, &e2, pt)); + } + + + bool ClipperBase::BuildIntersectList(const int64_t top_y) + { + if (!actives_ || !actives_->next_in_ael) return false; + + //Calculate edge positions at the top of the current scanbeam, and from this + //we will determine the intersections required to reach these new positions. + AdjustCurrXAndCopyToSEL(top_y); + //Find all edge intersections in the current scanbeam using a stable merge + //sort that ensures only adjacent edges are intersecting. Intersect info is + //stored in FIntersectList ready to be processed in ProcessIntersectList. + //Re merge sorts see https://stackoverflow.com/a/46319131/359538 + + Active* left = sel_, * right, * l_end, * r_end, * curr_base, * tmp; + + while (left && left->jump) + { + Active* prev_base = nullptr; + while (left && left->jump) + { + curr_base = left; + right = left->jump; + l_end = right; + r_end = right->jump; + left->jump = r_end; + while (left != l_end && right != r_end) + { + if (right->curr_x < left->curr_x) + { + tmp = right->prev_in_sel; + for (; ; ) + { + AddNewIntersectNode(*tmp, *right, top_y); + if (tmp == left) break; + tmp = tmp->prev_in_sel; + } + + tmp = right; + right = ExtractFromSEL(tmp); + l_end = right; + Insert1Before2InSEL(tmp, left); + if (left == curr_base) + { + curr_base = tmp; + curr_base->jump = r_end; + if (!prev_base) sel_ = curr_base; + else prev_base->jump = curr_base; + } + } + else left = left->next_in_sel; + } + prev_base = curr_base; + left = r_end; + } + left = sel_; + } + return intersect_nodes_.size() > 0; + } + + void ClipperBase::ProcessIntersectList() + { + //We now have a list of intersections required so that edges will be + //correctly positioned at the top of the scanbeam. However, it's important + //that edge intersections are processed from the bottom up, but it's also + //crucial that intersections only occur between adjacent edges. + + //First we do a quicksort so intersections proceed in a bottom up order ... + std::sort(intersect_nodes_.begin(), intersect_nodes_.end(), IntersectListSort); + //Now as we process these intersections, we must sometimes adjust the order + //to ensure that intersecting edges are always adjacent ... + + std::vector::iterator node_iter, node_iter2; + for (node_iter = intersect_nodes_.begin(); + node_iter != intersect_nodes_.end(); ++node_iter) + { + if (!EdgesAdjacentInAEL(*node_iter)) + { + node_iter2 = node_iter + 1; + while (!EdgesAdjacentInAEL(*node_iter2)) ++node_iter2; + std::swap(*node_iter, *node_iter2); + } + + IntersectNode& node = *node_iter; + IntersectEdges(*node.edge1, *node.edge2, node.pt); + SwapPositionsInAEL(*node.edge1, *node.edge2); + + if (TestJoinWithPrev2(*node.edge2, node.pt)) + { + OutPt* op1 = AddOutPt(*node.edge2->prev_in_ael, node.pt); + OutPt* op2 = AddOutPt(*node.edge2, node.pt); + if (op1 != op2) AddJoin(op1, op2); + } + else if (TestJoinWithNext2(*node.edge1, node.pt)) + { + OutPt* op1 = AddOutPt(*node.edge1, node.pt); + OutPt* op2 = AddOutPt(*node.edge1->next_in_ael, node.pt); + if (op1 != op2) AddJoin(op1, op2); + } + } + } + + + void ClipperBase::SwapPositionsInAEL(Active& e1, Active& e2) + { + //preconditon: e1 must be immediately to the left of e2 + Active* next = e2.next_in_ael; + if (next) next->prev_in_ael = &e1; + Active* prev = e1.prev_in_ael; + if (prev) prev->next_in_ael = &e2; + e2.prev_in_ael = prev; + e2.next_in_ael = &e1; + e1.prev_in_ael = &e2; + e1.next_in_ael = next; + if (!e2.prev_in_ael) actives_ = &e2; + } + + + bool ClipperBase::ResetHorzDirection(const Active& horz, + const Active* max_pair, int64_t& horz_left, int64_t& horz_right) + { + if (horz.bot.x == horz.top.x) + { + //the horizontal edge is going nowhere ... + horz_left = horz.curr_x; + horz_right = horz.curr_x; + Active* e = horz.next_in_ael; + while (e && e != max_pair) e = e->next_in_ael; + return e != nullptr; + } + else if (horz.curr_x < horz.top.x) + { + horz_left = horz.curr_x; + horz_right = horz.top.x; + return true; + } + else + { + horz_left = horz.top.x; + horz_right = horz.curr_x; + return false; // right to left + } + } + + inline bool HorzIsSpike(const Active& horzEdge) + { + Point64 nextPt = NextVertex(horzEdge)->pt; + return (nextPt.y == horzEdge.bot.y) && + (horzEdge.bot.x < horzEdge.top.x) != (horzEdge.top.x < nextPt.x); + } + + inline void TrimHorz(Active& horzEdge, bool preserveCollinear) + { + bool wasTrimmed = false; + Point64 pt = NextVertex(horzEdge)->pt; + while (pt.y == horzEdge.top.y) + { + //always trim 180 deg. spikes (in closed paths) + //but otherwise break if preserveCollinear = true + if (preserveCollinear && + ((pt.x < horzEdge.top.x) != (horzEdge.bot.x < horzEdge.top.x))) + break; + + horzEdge.vertex_top = NextVertex(horzEdge); + horzEdge.top = pt; + wasTrimmed = true; + if (IsMaxima(horzEdge)) break; + pt = NextVertex(horzEdge)->pt; + } + + if (wasTrimmed) SetDx(horzEdge); // +/-infinity + } + + + void ClipperBase::DoHorizontal(Active& horz) + /******************************************************************************* + * Notes: Horizontal edges (HEs) at scanline intersections (ie at the top or * + * bottom of a scanbeam) are processed as if layered.The order in which HEs * + * are processed doesn't matter. HEs intersect with the bottom vertices of * + * other HEs[#] and with non-horizontal edges [*]. Once these intersections * + * are completed, intermediate HEs are 'promoted' to the next edge in their * + * bounds, and they in turn may be intersected[%] by other HEs. * + * * + * eg: 3 horizontals at a scanline: / | / / * + * | / | (HE3)o ========%========== o * + * o ======= o(HE2) / | / / * + * o ============#=========*======*========#=========o (HE1) * + * / | / | / * + *******************************************************************************/ + { + Point64 pt; + bool horzIsOpen = IsOpen(horz); + int64_t y = horz.bot.y; + Vertex* vertex_max = nullptr; + Active* max_pair = nullptr; + + if (!horzIsOpen) + { + vertex_max = GetCurrYMaximaVertex(horz); + if (vertex_max) + { + max_pair = GetHorzMaximaPair(horz, vertex_max); + //remove 180 deg.spikes and also simplify + //consecutive horizontals when PreserveCollinear = true + if (vertex_max != horz.vertex_top) + TrimHorz(horz, PreserveCollinear); + } + } + + int64_t horz_left, horz_right; + bool is_left_to_right = + ResetHorzDirection(horz, max_pair, horz_left, horz_right); + + if (IsHotEdge(horz)) + AddOutPt(horz, Point64(horz.curr_x, y)); + + OutPt* op; + while (true) // loop through consec. horizontal edges + { + if (horzIsOpen && IsMaxima(horz) && !IsOpenEnd(horz)) + { + vertex_max = GetCurrYMaximaVertex(horz); + if (vertex_max) + max_pair = GetHorzMaximaPair(horz, vertex_max); + } + + Active* e; + if (is_left_to_right) e = horz.next_in_ael; + else e = horz.prev_in_ael; + + while (e) + { + + if (e == max_pair) + { + if (IsHotEdge(horz)) + { + while (horz.vertex_top != e->vertex_top) + { + AddOutPt(horz, horz.top); + UpdateEdgeIntoAEL(&horz); + } + op = AddLocalMaxPoly(horz, *e, horz.top); + if (op && !IsOpen(horz) && op->pt == horz.top) + AddTrialHorzJoin(op); + } + DeleteFromAEL(*e); + DeleteFromAEL(horz); + return; + } + + //if horzEdge is a maxima, keep going until we reach + //its maxima pair, otherwise check for break conditions + if (vertex_max != horz.vertex_top || IsOpenEnd(horz)) + { + //otherwise stop when 'ae' is beyond the end of the horizontal line + if ((is_left_to_right && e->curr_x > horz_right) || + (!is_left_to_right && e->curr_x < horz_left)) break; + + if (e->curr_x == horz.top.x && !IsHorizontal(*e)) + { + pt = NextVertex(horz)->pt; + if (is_left_to_right) + { + //with open paths we'll only break once past horz's end + if (IsOpen(*e) && !IsSamePolyType(*e, horz) && !IsHotEdge(*e)) + { + if (TopX(*e, pt.y) > pt.x) break; + } + //otherwise we'll only break when horz's outslope is greater than e's + else if (TopX(*e, pt.y) >= pt.x) break; + } + else + { + if (IsOpen(*e) && !IsSamePolyType(*e, horz) && !IsHotEdge(*e)) + { + if (TopX(*e, pt.y) < pt.x) break; + } + else if (TopX(*e, pt.y) <= pt.x) break; + } + } + } + + pt = Point64(e->curr_x, horz.bot.y); + + if (is_left_to_right) + { + op = IntersectEdges(horz, *e, pt); + SwapPositionsInAEL(horz, *e); + // todo: check if op->pt == pt test is still needed + // expect op != pt only after AddLocalMaxPoly when horz.outrec == nullptr + if (IsHotEdge(horz) && op && !IsOpen(horz) && op->pt == pt) + AddTrialHorzJoin(op); + + if (!IsHorizontal(*e) && TestJoinWithPrev1(*e)) + { + op = AddOutPt(*e->prev_in_ael, pt); + OutPt* op2 = AddOutPt(*e, pt); + AddJoin(op, op2); + } + + horz.curr_x = e->curr_x; + e = horz.next_in_ael; + } + else + { + op = IntersectEdges(*e, horz, pt); + SwapPositionsInAEL(*e, horz); + + if (IsHotEdge(horz) && op && + !IsOpen(horz) && op->pt == pt) + AddTrialHorzJoin(op); + + if (!IsHorizontal(*e) && TestJoinWithNext1(*e)) + { + op = AddOutPt(*e, pt); + OutPt* op2 = AddOutPt(*e->next_in_ael, pt); + AddJoin(op, op2); + } + + horz.curr_x = e->curr_x; + e = horz.prev_in_ael; + } + } + + //check if we've finished with (consecutive) horizontals ... + if (horzIsOpen && IsOpenEnd(horz)) // ie open at top + { + if (IsHotEdge(horz)) + { + AddOutPt(horz, horz.top); + if (IsFront(horz)) + horz.outrec->front_edge = nullptr; + else + horz.outrec->back_edge = nullptr; + horz.outrec = nullptr; + } + DeleteFromAEL(horz); + return; + } + else if (NextVertex(horz)->pt.y != horz.top.y) + break; + + //still more horizontals in bound to process ... + if (IsHotEdge(horz)) + AddOutPt(horz, horz.top); + UpdateEdgeIntoAEL(&horz); + + if (PreserveCollinear && !horzIsOpen && HorzIsSpike(horz)) + TrimHorz(horz, true); + + is_left_to_right = + ResetHorzDirection(horz, max_pair, horz_left, horz_right); + } + + if (IsHotEdge(horz)) + { + op = AddOutPt(horz, horz.top); + if (!IsOpen(horz)) + AddTrialHorzJoin(op); + } + else + op = nullptr; + + if ((horzIsOpen && !IsOpenEnd(horz)) || + (!horzIsOpen && vertex_max != horz.vertex_top)) + { + UpdateEdgeIntoAEL(&horz); // this is the end of an intermediate horiz. + if (IsOpen(horz)) return; + + if (is_left_to_right && TestJoinWithNext1(horz)) + { + OutPt* op2 = AddOutPt(*horz.next_in_ael, horz.bot); + AddJoin(op, op2); + } + else if (!is_left_to_right && TestJoinWithPrev1(horz)) + { + OutPt* op2 = AddOutPt(*horz.prev_in_ael, horz.bot); + AddJoin(op2, op); + } + } + else if (IsHotEdge(horz)) + AddLocalMaxPoly(horz, *max_pair, horz.top); + else + { + DeleteFromAEL(*max_pair); + DeleteFromAEL(horz); + } + } + + + void ClipperBase::DoTopOfScanbeam(const int64_t y) + { + sel_ = nullptr; // sel_ is reused to flag horizontals (see PushHorz below) + Active* e = actives_; + while (e) + { + //nb: 'e' will never be horizontal here + if (e->top.y == y) + { + e->curr_x = e->top.x; + if (IsMaxima(*e)) + { + e = DoMaxima(*e); // TOP OF BOUND (MAXIMA) + continue; + } + else + { + //INTERMEDIATE VERTEX ... + if (IsHotEdge(*e)) AddOutPt(*e, e->top); + UpdateEdgeIntoAEL(e); + if (IsHorizontal(*e)) + PushHorz(*e); // horizontals are processed later + } + } + else // i.e. not the top of the edge + e->curr_x = TopX(*e, y); + + e = e->next_in_ael; + } + } + + + Active* ClipperBase::DoMaxima(Active& e) + { + Active* next_e, * prev_e, * max_pair; + prev_e = e.prev_in_ael; + next_e = e.next_in_ael; + if (IsOpenEnd(e)) + { + if (IsHotEdge(e)) AddOutPt(e, e.top); + if (!IsHorizontal(e)) + { + if (IsHotEdge(e)) + { + if (IsFront(e)) + e.outrec->front_edge = nullptr; + else + e.outrec->back_edge = nullptr; + e.outrec = nullptr; + } + DeleteFromAEL(e); + } + return next_e; + } + else + { + max_pair = GetMaximaPair(e); + if (!max_pair) return next_e; // eMaxPair is horizontal + } + + //only non-horizontal maxima here. + //process any edges between maxima pair ... + while (next_e != max_pair) + { + IntersectEdges(e, *next_e, e.top); + SwapPositionsInAEL(e, *next_e); + next_e = e.next_in_ael; + } + + if (IsOpen(e)) + { + if (IsHotEdge(e)) + AddLocalMaxPoly(e, *max_pair, e.top); + DeleteFromAEL(*max_pair); + DeleteFromAEL(e); + return (prev_e ? prev_e->next_in_ael : actives_); + } + + //here E.next_in_ael == ENext == EMaxPair ... + if (IsHotEdge(e)) + AddLocalMaxPoly(e, *max_pair, e.top); + + DeleteFromAEL(e); + DeleteFromAEL(*max_pair); + return (prev_e ? prev_e->next_in_ael : actives_); + } + + + void ClipperBase::SafeDeleteOutPtJoiners(OutPt* op) + { + Joiner* joiner = op->joiner; + if (!joiner) return; + + while (joiner) + { + if (joiner->idx < 0) + DeleteTrialHorzJoin(op); + else if (horz_joiners_) + { + if (OutPtInTrialHorzList(joiner->op1)) + DeleteTrialHorzJoin(joiner->op1); + if (OutPtInTrialHorzList(joiner->op2)) + DeleteTrialHorzJoin(joiner->op2); + DeleteJoin(joiner); + } + else + DeleteJoin(joiner); + joiner = op->joiner; + } + } + + + Joiner* ClipperBase::GetHorzTrialParent(const OutPt* op) + { + Joiner* joiner = op->joiner; + while (joiner) + { + if (joiner->op1 == op) + { + if (joiner->next1 && joiner->next1->idx < 0) return joiner; + else joiner = joiner->next1; + } + else + { + if (joiner->next2 && joiner->next2->idx < 0) return joiner; + else joiner = joiner->next1; + } + } + return joiner; + } + + + bool ClipperBase::OutPtInTrialHorzList(OutPt* op) + { + return op->joiner && ((op->joiner->idx < 0) || GetHorzTrialParent(op)); + } + + + void ClipperBase::AddTrialHorzJoin(OutPt* op) + { + //make sure 'op' isn't added more than once + if (!op->outrec->is_open && !OutPtInTrialHorzList(op)) + horz_joiners_ = new Joiner(op, nullptr, horz_joiners_); + } + + + Joiner* FindTrialJoinParent(Joiner*& joiner, const OutPt* op) + { + Joiner* parent = joiner; + while (parent) + { + if (op == parent->op1) + { + if (parent->next1 && parent->next1->idx < 0) + { + joiner = parent->next1; + return parent; + } + parent = parent->next1; + } + else + { + if (parent->next2 && parent->next2->idx < 0) + { + joiner = parent->next2; + return parent; + } + parent = parent->next2; + } + } + return nullptr; + } + + + void ClipperBase::DeleteTrialHorzJoin(OutPt* op) + { + if (!horz_joiners_) return; + + Joiner* joiner = op->joiner; + Joiner* parentH, * parentOp = nullptr; + while (joiner) + { + if (joiner->idx < 0) + { + //first remove joiner from FHorzTrials + if (joiner == horz_joiners_) + horz_joiners_ = joiner->nextH; + else + { + parentH = horz_joiners_; + while (parentH->nextH != joiner) + parentH = parentH->nextH; + parentH->nextH = joiner->nextH; + } + + //now remove joiner from op's joiner list + if (!parentOp) + { + //joiner must be first one in list + op->joiner = joiner->next1; + delete joiner; + joiner = op->joiner; + } + else + { + //the trial joiner isn't first + if (op == parentOp->op1) + parentOp->next1 = joiner->next1; + else + parentOp->next2 = joiner->next1; + delete joiner; + joiner = parentOp; + } + } + else + { + //not a trial join so look further along the linked list + parentOp = FindTrialJoinParent(joiner, op); + if (!parentOp) break; + } + //loop in case there's more than one trial join + } + } + + + inline bool GetHorzExtendedHorzSeg(OutPt*& op, OutPt*& op2) + { + OutRec* outrec = GetRealOutRec(op->outrec); + op2 = op; + if (outrec->front_edge) + { + while (op->prev != outrec->pts && + op->prev->pt.y == op->pt.y) op = op->prev; + while (op2 != outrec->pts && + op2->next->pt.y == op2->pt.y) op2 = op2->next; + return op2 != op; + } + else + { + while (op->prev != op2 && op->prev->pt.y == op->pt.y) + op = op->prev; + while (op2->next != op && op2->next->pt.y == op2->pt.y) + op2 = op2->next; + return op2 != op && op2->next != op; + } + } + + + inline bool HorzEdgesOverlap(int64_t x1a, int64_t x1b, int64_t x2a, int64_t x2b) + { + const int64_t minOverlap = 2; + if (x1a > x1b + minOverlap) + { + if (x2a > x2b + minOverlap) + return !((x1a <= x2b) || (x2a <= x1b)); + else + return !((x1a <= x2a) || (x2b <= x1b)); + } + else if (x1b > x1a + minOverlap) + { + if (x2a > x2b + minOverlap) + return !((x1b <= x2b) || (x2a <= x1a)); + else + return !((x1b <= x2a) || (x2b <= x1a)); + } + else + return false; + } + + + inline bool ValueBetween(int64_t val, int64_t end1, int64_t end2) + { + //NB accommodates axis aligned between where end1 == end2 + return ((val != end1) == (val != end2)) && + ((val > end1) == (val < end2)); + } + + + inline bool ValueEqualOrBetween(int64_t val, int64_t end1, int64_t end2) + { + return (val == end1) || (val == end2) || ((val > end1) == (val < end2)); + } + + + inline bool PointBetween(Point64 pt, Point64 corner1, Point64 corner2) + { + //NB points may not be collinear + return ValueBetween(pt.x, corner1.x, corner2.x) && + ValueBetween(pt.y, corner1.y, corner2.y); + } + + inline bool PointEqualOrBetween(Point64 pt, Point64 corner1, Point64 corner2) + { + //NB points may not be collinear + return ValueEqualOrBetween(pt.x, corner1.x, corner2.x) && + ValueEqualOrBetween(pt.y, corner1.y, corner2.y); + } + + + Joiner* FindJoinParent(const Joiner* joiner, OutPt* op) + { + Joiner* result = op->joiner; + for (; ; ) + { + if (op == result->op1) + { + if (result->next1 == joiner) return result; + else result = result->next1; + } + else + { + if (result->next2 == joiner) return result; + else result = result->next2; + } + } + } + + + void ClipperBase::ConvertHorzTrialsToJoins() + { + while (horz_joiners_) + { + Joiner* joiner = horz_joiners_; + horz_joiners_ = horz_joiners_->nextH; + OutPt* op1a = joiner->op1; + if (op1a->joiner == joiner) + { + op1a->joiner = joiner->next1; + } + else + { + Joiner* joinerParent = FindJoinParent(joiner, op1a); + if (joinerParent->op1 == op1a) + joinerParent->next1 = joiner->next1; + else + joinerParent->next2 = joiner->next1; + } + delete joiner; + + OutPt* op1b; + if (!GetHorzExtendedHorzSeg(op1a, op1b)) + { + CleanCollinear(op1a->outrec); + continue; + } + + bool joined = false; + joiner = horz_joiners_; + while (joiner) + { + OutPt* op2a = joiner->op1, * op2b; + if (GetHorzExtendedHorzSeg(op2a, op2b) && + HorzEdgesOverlap(op1a->pt.x, op1b->pt.x, op2a->pt.x, op2b->pt.x)) + { + //overlap found so promote to a 'real' join + joined = true; + if (op1a->pt == op2b->pt) + AddJoin(op1a, op2b); + else if (op1b->pt == op2a->pt) + AddJoin(op1b, op2a); + else if (op1a->pt == op2a->pt) + AddJoin(op1a, op2a); + else if (op1b->pt == op2b->pt) + AddJoin(op1b, op2b); + else if (ValueBetween(op1a->pt.x, op2a->pt.x, op2b->pt.x)) + AddJoin(op1a, InsertOp(op1a->pt, op2a)); + else if (ValueBetween(op1b->pt.x, op2a->pt.x, op2b->pt.x)) + AddJoin(op1b, InsertOp(op1b->pt, op2a)); + else if (ValueBetween(op2a->pt.x, op1a->pt.x, op1b->pt.x)) + AddJoin(op2a, InsertOp(op2a->pt, op1a)); + else if (ValueBetween(op2b->pt.x, op1a->pt.x, op1b->pt.x)) + AddJoin(op2b, InsertOp(op2b->pt, op1a)); + break; + } + joiner = joiner->nextH; + } + if (!joined) + CleanCollinear(op1a->outrec); + } + } + + + void ClipperBase::AddJoin(OutPt* op1, OutPt* op2) + { + if ((op1->outrec == op2->outrec) && ((op1 == op2) || + //unless op1.next or op1.prev crosses the start-end divide + //don't waste time trying to join adjacent vertices + ((op1->next == op2) && (op1 != op1->outrec->pts)) || + ((op2->next == op1) && (op2 != op1->outrec->pts)))) return; + + Joiner* j = new Joiner(op1, op2, nullptr); + j->idx = static_cast(joiner_list_.size()); + joiner_list_.push_back(j); + } + + + void ClipperBase::DeleteJoin(Joiner* joiner) + { + //This method deletes a single join, and it doesn't check for or + //delete trial horz. joins. For that, use the following method. + OutPt* op1 = joiner->op1, * op2 = joiner->op2; + + Joiner* parent_joiner; + if (op1->joiner != joiner) + { + parent_joiner = FindJoinParent(joiner, op1); + if (parent_joiner->op1 == op1) + parent_joiner->next1 = joiner->next1; + else + parent_joiner->next2 = joiner->next1; + } + else + op1->joiner = joiner->next1; + + if (op2->joiner != joiner) + { + parent_joiner = FindJoinParent(joiner, op2); + if (parent_joiner->op1 == op2) + parent_joiner->next1 = joiner->next2; + else + parent_joiner->next2 = joiner->next2; + } + else + op2->joiner = joiner->next2; + + joiner_list_[joiner->idx] = nullptr; + delete joiner; + } + + + void ClipperBase::ProcessJoinerList() + { + for (Joiner* j : joiner_list_) + { + if (!j) continue; + if (succeeded_) + { + OutRec* outrec = ProcessJoin(j); + CleanCollinear(outrec); + } + else + delete j; + } + + joiner_list_.resize(0); + } + + + bool CheckDisposeAdjacent(OutPt*& op, const OutPt* guard, OutRec& outRec) + { + bool result = false; + while (op->prev != op) + { + if (op->pt == op->prev->pt && op != guard && + op->prev->joiner && !op->joiner) + { + if (op == outRec.pts) outRec.pts = op->prev; + op = DisposeOutPt(op); + op = op->prev; + } + else + break; + } + + while (op->next != op) + { + if (op->pt == op->next->pt && op != guard && + op->next->joiner && !op->joiner) + { + if (op == outRec.pts) outRec.pts = op->prev; + op = DisposeOutPt(op); + op = op->prev; + } + else + break; + } + return result; + } + + + inline bool IsValidPath(OutPt* op) + { + return (op && op->next != op); + } + + + bool CollinearSegsOverlap(const Point64& seg1a, const Point64& seg1b, + const Point64& seg2a, const Point64& seg2b) + { + //precondition: seg1 and seg2 are collinear + if (seg1a.x == seg1b.x) + { + if (seg2a.x != seg1a.x || seg2a.x != seg2b.x) return false; + } + else if (seg1a.x < seg1b.x) + { + if (seg2a.x < seg2b.x) + { + if (seg2a.x >= seg1b.x || seg2b.x <= seg1a.x) return false; + } + else + { + if (seg2b.x >= seg1b.x || seg2a.x <= seg1a.x) return false; + } + } + else + { + if (seg2a.x < seg2b.x) + { + if (seg2a.x >= seg1a.x || seg2b.x <= seg1b.x) return false; + } + else + { + if (seg2b.x >= seg1a.x || seg2a.x <= seg1b.x) return false; + } + } + + if (seg1a.y == seg1b.y) + { + if (seg2a.y != seg1a.y || seg2a.y != seg2b.y) return false; + } + else if (seg1a.y < seg1b.y) + { + if (seg2a.y < seg2b.y) + { + if (seg2a.y >= seg1b.y || seg2b.y <= seg1a.y) return false; + } + else + { + if (seg2b.y >= seg1b.y || seg2a.y <= seg1a.y) return false; + } + } + else + { + if (seg2a.y < seg2b.y) + { + if (seg2a.y >= seg1a.y || seg2b.y <= seg1b.y) return false; + } + else + { + if (seg2b.y >= seg1a.y || seg2a.y <= seg1b.y) return false; + } + } + return true; + } + + OutRec* ClipperBase::ProcessJoin(Joiner* joiner) + { + OutPt* op1 = joiner->op1, * op2 = joiner->op2; + OutRec* or1 = GetRealOutRec(op1->outrec); + OutRec* or2 = GetRealOutRec(op2->outrec); + DeleteJoin(joiner); + + if (or2->pts == nullptr) return or1; + else if (!IsValidClosedPath(op2)) + { + SafeDisposeOutPts(op2); + return or1; + } + else if ((or1->pts == nullptr) || !IsValidClosedPath(op1)) + { + SafeDisposeOutPts(op1); + return or2; + } + else if (or1 == or2 && + ((op1 == op2) || (op1->next == op2) || (op1->prev == op2))) return or1; + + CheckDisposeAdjacent(op1, op2, *or1); + CheckDisposeAdjacent(op2, op1, *or2); + if (op1->next == op2 || op2->next == op1) return or1; + OutRec* result = or1; + + for (; ; ) + { + if (!IsValidPath(op1) || !IsValidPath(op2) || + (or1 == or2 && (op1->prev == op2 || op1->next == op2))) return or1; + + if (op1->prev->pt == op2->next->pt || + ((CrossProduct(op1->prev->pt, op1->pt, op2->next->pt) == 0) && + CollinearSegsOverlap(op1->prev->pt, op1->pt, op2->pt, op2->next->pt))) + { + if (or1 == or2) + { + //SPLIT REQUIRED + //make sure op1.prev and op2.next match positions + //by inserting an extra vertex if needed + if (op1->prev->pt != op2->next->pt) + { + if (PointEqualOrBetween(op1->prev->pt, op2->pt, op2->next->pt)) + op2->next = InsertOp(op1->prev->pt, op2); + else + op1->prev = InsertOp(op2->next->pt, op1->prev); + } + + //current to new + //op1.p[opA] >>> op1 ... opA \ / op1 + //op2.n[opB] <<< op2 ... opB / \ op2 + OutPt* opA = op1->prev, * opB = op2->next; + opA->next = opB; + opB->prev = opA; + op1->prev = op2; + op2->next = op1; + CompleteSplit(op1, opA, *or1); + } + else + { + //JOIN, NOT SPLIT + OutPt* opA = op1->prev, * opB = op2->next; + opA->next = opB; + opB->prev = opA; + op1->prev = op2; + op2->next = op1; + + //SafeDeleteOutPtJoiners(op2); + //DisposeOutPt(op2); + + if (or1->idx < or2->idx) + { + or1->pts = op1; + or2->pts = nullptr; + if (or1->owner && (!or2->owner || + or2->owner->idx < or1->owner->idx)) + or1->owner = or2->owner; + or2->owner = or1; + } + else + { + result = or2; + or2->pts = op1; + or1->pts = nullptr; + if (or2->owner && (!or1->owner || + or1->owner->idx < or2->owner->idx)) + or2->owner = or1->owner; + or1->owner = or2; + } + } + break; + } + else if (op1->next->pt == op2->prev->pt || + ((CrossProduct(op1->next->pt, op2->pt, op2->prev->pt) == 0) && + CollinearSegsOverlap(op1->next->pt, op1->pt, op2->pt, op2->prev->pt))) + { + if (or1 == or2) + { + //SPLIT REQUIRED + //make sure op2.prev and op1.next match positions + //by inserting an extra vertex if needed + if (op2->prev->pt != op1->next->pt) + { + if (PointEqualOrBetween(op2->prev->pt, op1->pt, op1->next->pt)) + op1->next = InsertOp(op2->prev->pt, op1); + else + op2->prev = InsertOp(op1->next->pt, op2->prev); + } + + //current to new + //op2.p[opA] >>> op2 ... opA \ / op2 + //op1.n[opB] <<< op1 ... opB / \ op1 + OutPt* opA = op2->prev, * opB = op1->next; + opA->next = opB; + opB->prev = opA; + op2->prev = op1; + op1->next = op2; + CompleteSplit(op1, opA, *or1); + } + else + { + //JOIN, NOT SPLIT + OutPt* opA = op1->next, * opB = op2->prev; + opA->prev = opB; + opB->next = opA; + op1->next = op2; + op2->prev = op1; + + //SafeDeleteOutPtJoiners(op2); + //DisposeOutPt(op2); + + if (or1->idx < or2->idx) + { + or1->pts = op1; + or2->pts = nullptr; + if (or1->owner && (!or2->owner || + or2->owner->idx < or1->owner->idx)) + or1->owner = or2->owner; + or2->owner = or1; + } + else + { + result = or2; + or2->pts = op1; + or1->pts = nullptr; + if (or2->owner && (!or1->owner || + or1->owner->idx < or2->owner->idx)) + or2->owner = or1->owner; + or1->owner = or2; + } + } + break; + } + else if (PointBetween(op1->next->pt, op2->pt, op2->prev->pt) && + DistanceFromLineSqrd(op1->next->pt, op2->pt, op2->prev->pt) < 2.01) + { + InsertOp(op1->next->pt, op2->prev); + continue; + } + else if (PointBetween(op2->next->pt, op1->pt, op1->prev->pt) && + DistanceFromLineSqrd(op2->next->pt, op1->pt, op1->prev->pt) < 2.01) + { + InsertOp(op2->next->pt, op1->prev); + continue; + } + else if (PointBetween(op1->prev->pt, op2->pt, op2->next->pt) && + DistanceFromLineSqrd(op1->prev->pt, op2->pt, op2->next->pt) < 2.01) + { + InsertOp(op1->prev->pt, op2); + continue; + } + else if (PointBetween(op2->prev->pt, op1->pt, op1->next->pt) && + DistanceFromLineSqrd(op2->prev->pt, op1->pt, op1->next->pt) < 2.01) + { + InsertOp(op2->prev->pt, op1); + continue; + } + + //something odd needs tidying up + if (CheckDisposeAdjacent(op1, op2, *or1)) continue; + else if (CheckDisposeAdjacent(op2, op1, *or1)) continue; + else if (op1->prev->pt != op2->next->pt && + (DistanceSqr(op1->prev->pt, op2->next->pt) < 2.01)) + { + op1->prev->pt = op2->next->pt; + continue; + } + else if (op1->next->pt != op2->prev->pt && + (DistanceSqr(op1->next->pt, op2->prev->pt) < 2.01)) + { + op2->prev->pt = op1->next->pt; + continue; + } + else + { + //OK, there doesn't seem to be a way to join after all + //so just tidy up the polygons + or1->pts = op1; + if (or2 != or1) + { + or2->pts = op2; + CleanCollinear(or2); + } + break; + } + } + return result; + + } + + inline bool Path1InsidePath2(const OutRec* or1, const OutRec* or2) + { + PointInPolygonResult result = PointInPolygonResult::IsOn; + OutPt* op = or1->pts; + do + { + result = PointInPolygon(op->pt, or2->path); + if (result != PointInPolygonResult::IsOn) break; + op = op->next; + } while (op != or1->pts); + if (result == PointInPolygonResult::IsOn) + return Area(op) < Area(or2->pts); + else + return result == PointInPolygonResult::IsInside; + } + + inline Rect64 GetBounds(const Path64& path) + { + if (path.empty()) return Rect64(); + Rect64 result = invalid_rect; + for(const Point64& pt : path) + { + if (pt.x < result.left) result.left = pt.x; + if (pt.x > result.right) result.right = pt.x; + if (pt.y < result.top) result.top = pt.y; + if (pt.y > result.bottom) result.bottom = pt.y; + } + return result; + } + + bool BuildPath64(OutPt* op, bool reverse, bool isOpen, Path64& path) + { + if (op->next == op || (!isOpen && op->next == op->prev)) + return false; + + path.resize(0); + Point64 lastPt; + OutPt* op2; + if (reverse) + { + lastPt = op->pt; + op2 = op->prev; + } + else + { + op = op->next; + lastPt = op->pt; + op2 = op->next; + } + path.push_back(lastPt); + + while (op2 != op) + { + if (op2->pt != lastPt) + { + lastPt = op2->pt; + path.push_back(lastPt); + } + if (reverse) + op2 = op2->prev; + else + op2 = op2->next; + } + + if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false; + else return true; + } + + bool ClipperBase::DeepCheckOwner(OutRec* outrec, OutRec* owner) + { + if (owner->bounds.IsEmpty()) owner->bounds = GetBounds(owner->path); + bool is_inside_owner_bounds = owner->bounds.Contains(outrec->bounds); + + // while looking for the correct owner, check the owner's + // splits **before** checking the owner itself because + // splits can occur internally, and checking the owner + // first would miss the inner split's true ownership + if (owner->splits) + { + for (OutRec* split : *owner->splits) + { + split = GetRealOutRec(split); + if (!split || split->idx <= owner->idx || split == outrec) continue; + + if (split->splits && DeepCheckOwner(outrec, split)) return true; + + if (!split->path.size()) + BuildPath64(split->pts, ReverseSolution, false, split->path); + if (split->bounds.IsEmpty()) split->bounds = GetBounds(split->path); + + if (split->bounds.Contains(outrec->bounds) && + Path1InsidePath2(outrec, split)) + { + outrec->owner = split; + return true; + } + } + } + + // only continue past here when not inside recursion + if (owner != outrec->owner) return false; + + for (;;) + { + if (is_inside_owner_bounds && Path1InsidePath2(outrec, outrec->owner)) + return true; + // otherwise keep trying with owner's owner + outrec->owner = outrec->owner->owner; + if (!outrec->owner) return true; // true or false + is_inside_owner_bounds = outrec->owner->bounds.Contains(outrec->bounds); + } + } + + void Clipper64::BuildPaths64(Paths64& solutionClosed, Paths64* solutionOpen) + { + solutionClosed.resize(0); + solutionClosed.reserve(outrec_list_.size()); + if (solutionOpen) + { + solutionOpen->resize(0); + solutionOpen->reserve(outrec_list_.size()); + } + + for (OutRec* outrec : outrec_list_) + { + if (outrec->pts == nullptr) continue; + + Path64 path; + if (solutionOpen && outrec->is_open) + { + if (BuildPath64(outrec->pts, ReverseSolution, true, path)) + solutionOpen->emplace_back(std::move(path)); + } + else + { + //closed paths should always return a Positive orientation + if (BuildPath64(outrec->pts, ReverseSolution, false, path)) + solutionClosed.emplace_back(std::move(path)); + } + } + } + + void Clipper64::BuildTree64(PolyPath64& polytree, Paths64& open_paths) + { + polytree.Clear(); + open_paths.resize(0); + if (has_open_paths_) + open_paths.reserve(outrec_list_.size()); + + for (OutRec* outrec : outrec_list_) + { + if (!outrec || !outrec->pts) continue; + if (outrec->is_open) + { + Path64 path; + if (BuildPath64(outrec->pts, ReverseSolution, true, path)) + open_paths.push_back(path); + continue; + } + + if (!BuildPath64(outrec->pts, ReverseSolution, false, outrec->path)) + continue; + if (outrec->bounds.IsEmpty()) outrec->bounds = GetBounds(outrec->path); + outrec->owner = GetRealOutRec(outrec->owner); + if (outrec->owner) DeepCheckOwner(outrec, outrec->owner); + + // swap the order when a child preceeds its owner + // (because owners must preceed children in polytrees) + if (outrec->owner && outrec->idx < outrec->owner->idx) + { + OutRec* tmp = outrec->owner; + outrec_list_[outrec->owner->idx] = outrec; + outrec_list_[outrec->idx] = tmp; + size_t tmp_idx = outrec->idx; + outrec->idx = tmp->idx; + tmp->idx = tmp_idx; + outrec = tmp; + outrec->owner = GetRealOutRec(outrec->owner); + BuildPath64(outrec->pts, ReverseSolution, false, outrec->path); + if (outrec->bounds.IsEmpty()) outrec->bounds = GetBounds(outrec->path); + if (outrec->owner) DeepCheckOwner(outrec, outrec->owner); + } + + PolyPath* owner_polypath; + if (outrec->owner && outrec->owner->polypath) + owner_polypath = outrec->owner->polypath; + else + owner_polypath = &polytree; + outrec->polypath = owner_polypath->AddChild(outrec->path); + } + } + + bool BuildPathD(OutPt* op, bool reverse, bool isOpen, PathD& path, double inv_scale) + { + if (op->next == op || (!isOpen && op->next == op->prev)) return false; + path.resize(0); + Point64 lastPt; + OutPt* op2; + if (reverse) + { + lastPt = op->pt; + op2 = op->prev; + } + else + { + op = op->next; + lastPt = op->pt; + op2 = op->next; + } + path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale)); + + while (op2 != op) + { + if (op2->pt != lastPt) + { + lastPt = op2->pt; + path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale)); + } + if (reverse) + op2 = op2->prev; + else + op2 = op2->next; + } + if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false; + return true; + } + + void ClipperD::BuildPathsD(PathsD& solutionClosed, PathsD* solutionOpen) + { + solutionClosed.resize(0); + solutionClosed.reserve(outrec_list_.size()); + if (solutionOpen) + { + solutionOpen->resize(0); + solutionOpen->reserve(outrec_list_.size()); + } + + for (OutRec* outrec : outrec_list_) + { + if (outrec->pts == nullptr) continue; + + PathD path; + if (solutionOpen && outrec->is_open) + { + if (BuildPathD(outrec->pts, ReverseSolution, true, path, invScale_)) + solutionOpen->emplace_back(std::move(path)); + } + else + { + //closed paths should always return a Positive orientation + if (BuildPathD(outrec->pts, ReverseSolution, false, path, invScale_)) + solutionClosed.emplace_back(std::move(path)); + } + } + } + + void ClipperD::BuildTreeD(PolyPathD& polytree, PathsD& open_paths) + { + polytree.Clear(); + open_paths.resize(0); + if (has_open_paths_) + open_paths.reserve(outrec_list_.size()); + + for (OutRec* outrec : outrec_list_) + { + if (!outrec || !outrec->pts) continue; + if (outrec->is_open) + { + PathD path; + if (BuildPathD(outrec->pts, ReverseSolution, true, path, invScale_)) + open_paths.push_back(path); + continue; + } + + if (!BuildPath64(outrec->pts, ReverseSolution, false, outrec->path)) + continue; + if (outrec->bounds.IsEmpty()) outrec->bounds = GetBounds(outrec->path); + outrec->owner = GetRealOutRec(outrec->owner); + if (outrec->owner) DeepCheckOwner(outrec, outrec->owner); + + // swap the order when a child preceeds its owner + // (because owners must preceed children in polytrees) + if (outrec->owner && outrec->idx < outrec->owner->idx) + { + OutRec* tmp = outrec->owner; + outrec_list_[outrec->owner->idx] = outrec; + outrec_list_[outrec->idx] = tmp; + size_t tmp_idx = outrec->idx; + outrec->idx = tmp->idx; + tmp->idx = tmp_idx; + outrec = tmp; + outrec->owner = GetRealOutRec(outrec->owner); + BuildPath64(outrec->pts, ReverseSolution, false, outrec->path); + if (outrec->bounds.IsEmpty()) outrec->bounds = GetBounds(outrec->path); + if (outrec->owner) DeepCheckOwner(outrec, outrec->owner); + } + + PolyPath* owner_polypath; + if (outrec->owner && outrec->owner->polypath) + owner_polypath = outrec->owner->polypath; + else + owner_polypath = &polytree; + outrec->polypath = owner_polypath->AddChild(outrec->path); + } + } + +} // namespace clipper2lib diff --git a/src/clipper2/Clipper2Lib/src/clipper.offset.cpp b/src/clipper2/Clipper2Lib/src/clipper.offset.cpp new file mode 100644 index 0000000000..a19a6ff459 --- /dev/null +++ b/src/clipper2/Clipper2Lib/src/clipper.offset.cpp @@ -0,0 +1,485 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 15 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : Path Offset (Inflate/Shrink) * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#include +#include "clipper2/clipper.h" +#include "clipper2/clipper.offset.h" + +namespace Clipper2Lib { + +const double default_arc_tolerance = 0.25; +const double floating_point_tolerance = 1e-12; + +//------------------------------------------------------------------------------ +// Miscellaneous methods +//------------------------------------------------------------------------------ + +Paths64::size_type GetLowestPolygonIdx(const Paths64& paths) +{ + Paths64::size_type result = 0; + Point64 lp = Point64(static_cast(0), + std::numeric_limits::min()); + + for (Paths64::size_type i = 0 ; i < paths.size(); ++i) + for (const Point64& p : paths[i]) + { + if (p.y < lp.y || (p.y == lp.y && p.x >= lp.x)) continue; + result = i; + lp = p; + } + return result; +} + +PointD GetUnitNormal(const Point64& pt1, const Point64& pt2) +{ + double dx, dy, inverse_hypot; + if (pt1 == pt2) return PointD(0.0, 0.0); + dx = static_cast(pt2.x - pt1.x); + dy = static_cast(pt2.y - pt1.y); + inverse_hypot = 1.0 / hypot(dx, dy); + dx *= inverse_hypot; + dy *= inverse_hypot; + return PointD(dy, -dx); +} + +inline bool AlmostZero(double value, double epsilon = 0.001) +{ + return std::fabs(value) < epsilon; +} + +inline double Hypot(double x, double y) +{ + //see https://stackoverflow.com/a/32436148/359538 + return std::sqrt(x * x + y * y); +} + +inline PointD NormalizeVector(const PointD& vec) +{ + + double h = Hypot(vec.x, vec.y); + if (AlmostZero(h)) return PointD(0,0); + double inverseHypot = 1 / h; + return PointD(vec.x * inverseHypot, vec.y * inverseHypot); +} + +inline PointD GetAvgUnitVector(const PointD& vec1, const PointD& vec2) +{ + return NormalizeVector(PointD(vec1.x + vec2.x, vec1.y + vec2.y)); +} + +inline bool IsClosedPath(EndType et) +{ + return et == EndType::Polygon || et == EndType::Joined; +} + +inline Point64 GetPerpendic(const Point64& pt, const PointD& norm, double delta) +{ + return Point64(pt.x + norm.x * delta, pt.y + norm.y * delta); +} + +inline PointD GetPerpendicD(const Point64& pt, const PointD& norm, double delta) +{ + return PointD(pt.x + norm.x * delta, pt.y + norm.y * delta); +} + +//------------------------------------------------------------------------------ +// ClipperOffset methods +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPath(const Path64& path, JoinType jt_, EndType et_) +{ + Paths64 paths; + paths.push_back(path); + AddPaths(paths, jt_, et_); +} + +void ClipperOffset::AddPaths(const Paths64 &paths, JoinType jt_, EndType et_) +{ + if (paths.size() == 0) return; + groups_.push_back(Group(paths, jt_, et_)); +} + +void ClipperOffset::AddPath(const Clipper2Lib::PathD& path, JoinType jt_, EndType et_) +{ + PathsD paths; + paths.push_back(path); + AddPaths(paths, jt_, et_); +} + +void ClipperOffset::AddPaths(const PathsD& paths, JoinType jt_, EndType et_) +{ + if (paths.size() == 0) return; + groups_.push_back(Group(PathsDToPaths64(paths), jt_, et_)); +} + +void ClipperOffset::BuildNormals(const Path64& path) +{ + norms.clear(); + norms.reserve(path.size()); + if (path.size() == 0) return; + Path64::const_iterator path_iter, path_last_iter = --path.cend(); + for (path_iter = path.cbegin(); path_iter != path_last_iter; ++path_iter) + norms.push_back(GetUnitNormal(*path_iter,*(path_iter +1))); + norms.push_back(GetUnitNormal(*path_last_iter, *(path.cbegin()))); +} + +inline PointD TranslatePoint(const PointD& pt, double dx, double dy) +{ + return PointD(pt.x + dx, pt.y + dy); +} + +inline PointD ReflectPoint(const PointD& pt, const PointD& pivot) +{ + return PointD(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y)); +} + +PointD IntersectPoint(const PointD& pt1a, const PointD& pt1b, + const PointD& pt2a, const PointD& pt2b) +{ + if (pt1a.x == pt1b.x) //vertical + { + if (pt2a.x == pt2b.x) return PointD(0, 0); + + double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x); + double b2 = pt2a.y - m2 * pt2a.x; + return PointD(pt1a.x, m2 * pt1a.x + b2); + } + else if (pt2a.x == pt2b.x) //vertical + { + double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x); + double b1 = pt1a.y - m1 * pt1a.x; + return PointD(pt2a.x, m1 * pt2a.x + b1); + } + else + { + double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x); + double b1 = pt1a.y - m1 * pt1a.x; + double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x); + double b2 = pt2a.y - m2 * pt2a.x; + if (m1 == m2) return PointD(0, 0); + double x = (b2 - b1) / (m1 - m2); + return PointD(x, m1 * x + b1); + } +} + +void ClipperOffset::DoSquare(Group& group, const Path64& path, size_t j, size_t k) +{ + PointD vec; + if (j == k) + vec = PointD(norms[0].y, -norms[0].x); + else + vec = GetAvgUnitVector( + PointD(-norms[k].y, norms[k].x), + PointD(norms[j].y, -norms[j].x)); + + // now offset the original vertex delta units along unit vector + PointD ptQ = PointD(path[j]); + ptQ = TranslatePoint(ptQ, abs_group_delta_ * vec.x, abs_group_delta_ * vec.y); + // get perpendicular vertices + PointD pt1 = TranslatePoint(ptQ, group_delta_ * vec.y, group_delta_ * -vec.x); + PointD pt2 = TranslatePoint(ptQ, group_delta_ * -vec.y, group_delta_ * vec.x); + // get 2 vertices along one edge offset + PointD pt3 = GetPerpendicD(path[k], norms[k], group_delta_); + if (j == k) + { + PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_); + PointD pt = IntersectPoint(pt1, pt2, pt3, pt4); + //get the second intersect point through reflecion + group.path_.push_back(Point64(ReflectPoint(pt, ptQ))); + group.path_.push_back(Point64(pt)); + } + else + { + PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_); + PointD pt = IntersectPoint(pt1, pt2, pt3, pt4); + group.path_.push_back(Point64(pt)); + //get the second intersect point through reflecion + group.path_.push_back(Point64(ReflectPoint(pt, ptQ))); + } +} + +void ClipperOffset::DoMiter(Group& group, const Path64& path, size_t j, size_t k, double cos_a) +{ + double q = group_delta_ / (cos_a + 1); + group.path_.push_back(Point64( + path[j].x + (norms[k].x + norms[j].x) * q, + path[j].y + (norms[k].y + norms[j].y) * q)); +} + +void ClipperOffset::DoRound(Group& group, const Path64& path, size_t j, size_t k, double angle) +{ + //even though angle may be negative this is a convex join + Point64 pt = path[j]; + int steps = static_cast(std::ceil(steps_per_rad_ * std::abs(angle))); + double step_sin = std::sin(angle / steps); + double step_cos = std::cos(angle / steps); + + PointD pt2 = PointD(norms[k].x * group_delta_, norms[k].y * group_delta_); + if (j == k) pt2.Negate(); + + group.path_.push_back(Point64(pt.x + pt2.x, pt.y + pt2.y)); + for (int i = 0; i < steps; i++) + { + pt2 = PointD(pt2.x * step_cos - step_sin * pt2.y, + pt2.x * step_sin + pt2.y * step_cos); + group.path_.push_back(Point64(pt.x + pt2.x, pt.y + pt2.y)); + } + group.path_.push_back(GetPerpendic(path[j], norms[j], group_delta_)); +} + +void ClipperOffset::OffsetPoint(Group& group, Path64& path, size_t j, size_t& k) +{ + // Let A = change in angle where edges join + // A == 0: ie no change in angle (flat join) + // A == PI: edges 'spike' + // sin(A) < 0: right turning + // cos(A) < 0: change in angle is more than 90 degree + + if (path[j] == path[k]) { k = j; return; } + + double sin_a = CrossProduct(norms[j], norms[k]); + double cos_a = DotProduct(norms[j], norms[k]); + if (sin_a > 1.0) sin_a = 1.0; + else if (sin_a < -1.0) sin_a = -1.0; + + bool almostNoAngle = AlmostZero(sin_a) && cos_a > 0; + // when there's almost no angle of deviation or it's concave + if (almostNoAngle || (sin_a * group_delta_ < 0)) + { + Point64 p1 = Point64( + path[j].x + norms[k].x * group_delta_, + path[j].y + norms[k].y * group_delta_); + Point64 p2 = Point64( + path[j].x + norms[j].x * group_delta_, + path[j].y + norms[j].y * group_delta_); + group.path_.push_back(p1); + if (p1 != p2) + { + // when concave add an extra vertex to ensure neat clipping + if (!almostNoAngle) group.path_.push_back(path[j]); + group.path_.push_back(p2); + } + } + else // it's convex + { + if (join_type_ == JoinType::Round) + DoRound(group, path, j, k, std::atan2(sin_a, cos_a)); + else if (join_type_ == JoinType::Miter) + { + // miter unless the angle is so acute the miter would exceeds ML + if (cos_a > temp_lim_ - 1) DoMiter(group, path, j, k, cos_a); + else DoSquare(group, path, j, k); + } + // don't bother squaring angles that deviate < ~20 degrees because + // squaring will be indistinguishable from mitering and just be a lot slower + else if (cos_a > 0.9) + DoMiter(group, path, j, k, cos_a); + else + DoSquare(group, path, j, k); + } + k = j; +} + +void ClipperOffset::OffsetPolygon(Group& group, Path64& path) +{ + group.path_.clear(); + for (Path64::size_type i = 0, j = path.size() -1; i < path.size(); j = i, ++i) + OffsetPoint(group, path, i, j); + group.paths_out_.push_back(group.path_); +} + +void ClipperOffset::OffsetOpenJoined(Group& group, Path64& path) +{ + OffsetPolygon(group, path); + std::reverse(path.begin(), path.end()); + BuildNormals(path); + OffsetPolygon(group, path); +} + +void ClipperOffset::OffsetOpenPath(Group& group, Path64& path, EndType end_type) +{ + group.path_.clear(); + + // do the line start cap + switch (end_type) + { + case EndType::Butt: + group.path_.push_back(Point64( + path[0].x - norms[0].x * group_delta_, + path[0].y - norms[0].y * group_delta_)); + group.path_.push_back(GetPerpendic(path[0], norms[0], group_delta_)); + break; + case EndType::Round: + DoRound(group, path, 0,0, PI); + break; + default: + DoSquare(group, path, 0, 0); + break; + } + + size_t highI = path.size() - 1; + + // offset the left side going forward + for (Path64::size_type i = 1, k = 0; i < highI; ++i) + OffsetPoint(group, path, i, k); + + // reverse normals + for (size_t i = highI; i > 0; --i) + norms[i] = PointD(-norms[i - 1].x, -norms[i - 1].y); + norms[0] = norms[highI]; + + // do the line end cap + switch (end_type) + { + case EndType::Butt: + group.path_.push_back(Point64( + path[highI].x - norms[highI].x * group_delta_, + path[highI].y - norms[highI].y * group_delta_)); + group.path_.push_back(GetPerpendic(path[highI], norms[highI], group_delta_)); + break; + case EndType::Round: + DoRound(group, path, highI, highI, PI); + break; + default: + DoSquare(group, path, highI, highI); + break; + } + + for (size_t i = highI, k = 0; i > 0; --i) + OffsetPoint(group, path, i, k); + group.paths_out_.push_back(group.path_); +} + +void ClipperOffset::DoGroupOffset(Group& group, double delta) +{ + if (group.end_type_ != EndType::Polygon) delta = std::abs(delta) * 0.5; + bool isClosedPaths = IsClosedPath(group.end_type_); + + if (isClosedPaths) + { + //the lowermost polygon must be an outer polygon. So we can use that as the + //designated orientation for outer polygons (needed for tidy-up clipping) + Paths64::size_type lowestIdx = GetLowestPolygonIdx(group.paths_in_); + // nb: don't use the default orientation here ... + double area = Area(group.paths_in_[lowestIdx]); + if (area == 0) return; + group.is_reversed_ = (area < 0); + if (group.is_reversed_) delta = -delta; + } + else + group.is_reversed_ = false; + + group_delta_ = delta; + abs_group_delta_ = std::abs(group_delta_); + join_type_ = group.join_type_; + + double arcTol = (arc_tolerance_ > floating_point_tolerance ? arc_tolerance_ + : std::log10(2 + abs_group_delta_) * default_arc_tolerance); // empirically derived + +//calculate a sensible number of steps (for 360 deg for the given offset + if (group.join_type_ == JoinType::Round || group.end_type_ == EndType::Round) + { + steps_per_rad_ = PI / std::acos(1 - arcTol / abs_group_delta_) / (PI *2); + } + + bool is_closed_path = IsClosedPath(group.end_type_); + Paths64::const_iterator path_iter; + for(path_iter = group.paths_in_.cbegin(); path_iter != group.paths_in_.cend(); ++path_iter) + { + Path64 path = StripDuplicates(*path_iter, is_closed_path); + Path64::size_type cnt = path.size(); + if (cnt == 0) continue; + + if (cnt == 1) // single point - only valid with open paths + { + group.path_ = Path64(); + //single vertex so build a circle or square ... + if (group.join_type_ == JoinType::Round) + { + double radius = abs_group_delta_; + group.path_ = Ellipse(path[0], radius, radius); + } + else + { + int d = (int)std::ceil(abs_group_delta_); + Rect64 r = Rect64(path[0].x - d, path[0].y - d, path[0].x + d, path[0].y + d); + group.path_ = r.AsPath(); + } + group.paths_out_.push_back(group.path_); + } + else + { + BuildNormals(path); + if (group.end_type_ == EndType::Polygon) OffsetPolygon(group, path); + else if (group.end_type_ == EndType::Joined) OffsetOpenJoined(group, path); + else OffsetOpenPath(group, path, group.end_type_); + } + } + + if (!merge_groups_) + { + //clean up self-intersections ... + Clipper64 c; + c.PreserveCollinear = false; + //the solution should retain the orientation of the input + c.ReverseSolution = reverse_solution_ != group.is_reversed_; + c.AddSubject(group.paths_out_); + if (group.is_reversed_) + c.Execute(ClipType::Union, FillRule::Negative, group.paths_out_); + else + c.Execute(ClipType::Union, FillRule::Positive, group.paths_out_); + } + + solution.reserve(solution.size() + group.paths_out_.size()); + copy(group.paths_out_.begin(), group.paths_out_.end(), back_inserter(solution)); + group.paths_out_.clear(); +} + +Paths64 ClipperOffset::Execute(double delta) +{ + solution.clear(); + if (std::abs(delta) < default_arc_tolerance) + { + for (const Group& group : groups_) + { + solution.reserve(solution.size() + group.paths_in_.size()); + copy(group.paths_in_.begin(), group.paths_in_.end(), back_inserter(solution)); + } + return solution; + } + + temp_lim_ = (miter_limit_ <= 1) ? + 2.0 : + 2.0 / (miter_limit_ * miter_limit_); + + std::vector::iterator groups_iter; + for (groups_iter = groups_.begin(); + groups_iter != groups_.end(); ++groups_iter) + { + DoGroupOffset(*groups_iter, delta); + } + + if (merge_groups_ && groups_.size() > 0) + { + //clean up self-intersections ... + Clipper64 c; + c.PreserveCollinear = false; + //the solution should retain the orientation of the input + c.ReverseSolution = reverse_solution_ != groups_[0].is_reversed_; + + c.AddSubject(solution); + if (groups_[0].is_reversed_) + c.Execute(ClipType::Union, FillRule::Negative, solution); + else + c.Execute(ClipType::Union, FillRule::Positive, solution); + } + return solution; +} + +} // namespace diff --git a/src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp b/src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp new file mode 100644 index 0000000000..0f6bb9c519 --- /dev/null +++ b/src/clipper2/Clipper2Lib/src/clipper.rectclip.cpp @@ -0,0 +1,547 @@ +/******************************************************************************* +* Author : Angus Johnson * +* Date : 26 October 2022 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2022 * +* Purpose : FAST rectangular clipping * +* License : http://www.boost.org/LICENSE_1_0.txt * +*******************************************************************************/ + +#include +#include "clipper2/clipper.h" +#include "clipper2/clipper.rectclip.h" + +namespace Clipper2Lib { + + //------------------------------------------------------------------------------ + // Miscellaneous methods + //------------------------------------------------------------------------------ + + inline PointInPolygonResult Path1ContainsPath2(Path64 path1, Path64 path2) + { + PointInPolygonResult result = PointInPolygonResult::IsOn; + for(const Point64& pt : path2) + { + result = PointInPolygon(pt, path1); + if (result != PointInPolygonResult::IsOn) break; + } + return result; + } + + inline bool GetLocation(const Rect64& rec, + const Point64& pt, Location& loc) + { + if (pt.x == rec.left && pt.y >= rec.top && pt.y <= rec.bottom) + { + loc = Location::Left; + return false; + } + else if (pt.x == rec.right && pt.y >= rec.top && pt.y <= rec.bottom) + { + loc = Location::Right; + return false; + } + else if (pt.y == rec.top && pt.x >= rec.left && pt.x <= rec.right) + { + loc = Location::Top; + return false; + } + else if (pt.y == rec.bottom && pt.x >= rec.left && pt.x <= rec.right) + { + loc = Location::Bottom; + return false; + } + else if (pt.x < rec.left) loc = Location::Left; + else if (pt.x > rec.right) loc = Location::Right; + else if (pt.y < rec.top) loc = Location::Top; + else if (pt.y > rec.bottom) loc = Location::Bottom; + else loc = Location::Inside; + return true; + } + + Point64 GetIntersectPoint64(const Point64& ln1a, const Point64& ln1b, + const Point64& ln2a, const Point64& ln2b) + { + // see http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/ + if (ln1b.x == ln1a.x) + { + if (ln2b.x == ln2a.x) return Point64(); // parallel lines + double m2 = static_cast(ln2b.y - ln2a.y) / (ln2b.x - ln2a.x); + double b2 = ln2a.y - m2 * ln2a.x; + return Point64(ln1a.x, static_cast(std::round(m2 * ln1a.x + b2))); + } + else if (ln2b.x == ln2a.x) + { + double m1 = static_cast(ln1b.y - ln1a.y) / (ln1b.x - ln1a.x); + double b1 = ln1a.y - m1 * ln1a.x; + return Point64(ln2a.x, static_cast(std::round(m1 * ln2a.x + b1))); + } + else + { + double m1 = static_cast(ln1b.y - ln1a.y) / (ln1b.x - ln1a.x); + double b1 = ln1a.y - m1 * ln1a.x; + double m2 = static_cast(ln2b.y - ln2a.y) / (ln2b.x - ln2a.x); + double b2 = ln2a.y - m2 * ln2a.x; + if (std::fabs(m1 - m2) > 1.0E-15) + { + double x = (b2 - b1) / (m1 - m2); + return Point64(x, m1 * x + b1); + } + else + return Point64((ln1a.x + ln1b.x) * 0.5, (ln1a.y + ln1b.y) * 0.5); + } + } + + inline bool GetIntersection(const Path64& rectPath, + const Point64& p, const Point64& p2, Location& loc, Point64& ip) + { + // gets the intersection closest to 'p' + // when Result = false, loc will remain unchanged + switch (loc) + { + case Location::Left: + if (SegmentsIntersect(p, p2, rectPath[0], rectPath[3], true)) + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[3]); + else if (p.y < rectPath[0].y && + SegmentsIntersect(p, p2, rectPath[0], rectPath[1], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[1]); + loc = Location::Top; + } + else if (SegmentsIntersect(p, p2, rectPath[2], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[2], rectPath[3]); + loc = Location::Bottom; + } + else return false; + break; + + case Location::Top: + if (SegmentsIntersect(p, p2, rectPath[0], rectPath[1], true)) + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[1]); + else if (p.x < rectPath[0].x && + SegmentsIntersect(p, p2, rectPath[0], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[3]); + loc = Location::Left; + } + else if (p.x > rectPath[1].x && + SegmentsIntersect(p, p2, rectPath[1], rectPath[2], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[1], rectPath[2]); + loc = Location::Right; + } + else return false; + break; + + case Location::Right: + if (SegmentsIntersect(p, p2, rectPath[1], rectPath[2], true)) + ip = GetIntersectPoint64(p, p2, rectPath[1], rectPath[2]); + else if (p.y < rectPath[0].y && + SegmentsIntersect(p, p2, rectPath[0], rectPath[1], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[1]); + loc = Location::Top; + } + else if (SegmentsIntersect(p, p2, rectPath[2], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[2], rectPath[3]); + loc = Location::Bottom; + } + else return false; + break; + + case Location::Bottom: + if (SegmentsIntersect(p, p2, rectPath[2], rectPath[3], true)) + ip = GetIntersectPoint64(p, p2, rectPath[2], rectPath[3]); + else if (p.x < rectPath[3].x && + SegmentsIntersect(p, p2, rectPath[0], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[3]); + loc = Location::Left; + } + else if (p.x > rectPath[2].x && + SegmentsIntersect(p, p2, rectPath[1], rectPath[2], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[1], rectPath[2]); + loc = Location::Right; + } + else return false; + break; + + default: // loc == rInside + if (SegmentsIntersect(p, p2, rectPath[0], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[3]); + loc = Location::Left; + } + else if (SegmentsIntersect(p, p2, rectPath[0], rectPath[1], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[0], rectPath[1]); + loc = Location::Top; + } + else if (SegmentsIntersect(p, p2, rectPath[1], rectPath[2], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[1], rectPath[2]); + loc = Location::Right; + } + else if (SegmentsIntersect(p, p2, rectPath[2], rectPath[3], true)) + { + ip = GetIntersectPoint64(p, p2, rectPath[2], rectPath[3]); + loc = Location::Bottom; + } + else return false; + break; + } + + return true; + } + + inline Location GetAdjacentLocation(Location loc, bool isClockwise) + { + int delta = (isClockwise) ? 1 : 3; + return static_cast((static_cast(loc) + delta) % 4); + } + + inline bool HeadingClockwise(Location prev, Location curr) + { + return (static_cast(prev) + 1) % 4 == static_cast(curr); + } + + inline bool AreOpposites(Location prev, Location curr) + { + return abs(static_cast(prev) - static_cast(curr)) == 2; + } + + inline bool IsClockwise(Location prev, Location curr, + Point64 prev_pt, Point64 curr_pt, Point64 rect_mp) + { + if (AreOpposites(prev, curr)) + return CrossProduct(prev_pt, rect_mp, curr_pt) < 0; + else + return HeadingClockwise(prev, curr); + } + + //---------------------------------------------------------------------------- + // RectClip64 + //---------------------------------------------------------------------------- + + void RectClip::AddCorner(Location prev, Location curr) + { + if (HeadingClockwise(prev, curr)) + result_.push_back(rectPath_[static_cast(prev)]); + else + result_.push_back(rectPath_[static_cast(curr)]); + } + + void RectClip::AddCorner(Location& loc, bool isClockwise) + { + if (isClockwise) + { + result_.push_back(rectPath_[static_cast(loc)]); + loc = GetAdjacentLocation(loc, true); + } + else + { + loc = GetAdjacentLocation(loc, false); + result_.push_back(rectPath_[static_cast(loc)]); + } + } + + void RectClip::GetNextLocation(const Path64& path, + Location& loc, int& i, int highI) + { + switch (loc) + { + case Location::Left: + while (i <= highI && path[i].x <= rect_.left) ++i; + if (i > highI) break; + else if (path[i].x >= rect_.right) loc = Location::Right; + else if (path[i].y <= rect_.top) loc = Location::Top; + else if (path[i].y >= rect_.bottom) loc = Location::Bottom; + else loc = Location::Inside; + break; + + case Location::Top: + while (i <= highI && path[i].y <= rect_.top) ++i; + if (i > highI) break; + else if (path[i].y >= rect_.bottom) loc = Location::Bottom; + else if (path[i].x <= rect_.left) loc = Location::Left; + else if (path[i].x >= rect_.right) loc = Location::Right; + else loc = Location::Inside; + break; + + case Location::Right: + while (i <= highI && path[i].x >= rect_.right) ++i; + if (i > highI) break; + else if (path[i].x <= rect_.left) loc = Location::Left; + else if (path[i].y <= rect_.top) loc = Location::Top; + else if (path[i].y >= rect_.bottom) loc = Location::Bottom; + else loc = Location::Inside; + break; + + case Location::Bottom: + while (i <= highI && path[i].y >= rect_.bottom) ++i; + if (i > highI) break; + else if (path[i].y <= rect_.top) loc = Location::Top; + else if (path[i].x <= rect_.left) loc = Location::Left; + else if (path[i].x >= rect_.right) loc = Location::Right; + else loc = Location::Inside; + break; + + case Location::Inside: + while (i <= highI) + { + if (path[i].x < rect_.left) loc = Location::Left; + else if (path[i].x > rect_.right) loc = Location::Right; + else if (path[i].y > rect_.bottom) loc = Location::Bottom; + else if (path[i].y < rect_.top) loc = Location::Top; + else { result_.push_back(path[i]); ++i; continue; } + break; //inner loop + } + break; + } //switch + } + + Path64 RectClip::Execute(const Path64& path) + { + if (rect_.IsEmpty() || path.size() < 3) return Path64(); + + result_.clear(); + start_locs_.clear(); + int i = 0, highI = static_cast(path.size()) - 1; + Location prev = Location::Inside, loc; + Location crossing_loc = Location::Inside; + Location first_cross_ = Location::Inside; + if (!GetLocation(rect_, path[highI], loc)) + { + i = highI - 1; + while (i >= 0 && !GetLocation(rect_, path[i], prev)) --i; + if (i < 0) return path; + if (prev == Location::Inside) loc = Location::Inside; + i = 0; + } + Location starting_loc = loc; + + /////////////////////////////////////////////////// + while (i <= highI) + { + prev = loc; + Location crossing_prev = crossing_loc; + + GetNextLocation(path, loc, i, highI); + + if (i > highI) break; + Point64 ip, ip2; + Point64 prev_pt = (i) ? path[static_cast(i - 1)] : path[highI]; + + crossing_loc = loc; + if (!GetIntersection(rectPath_, path[i], prev_pt, crossing_loc, ip)) + { + // ie remaining outside + + if (crossing_prev == Location::Inside) + { + bool isClockw = IsClockwise(prev, loc, prev_pt, path[i], mp_); + do { + start_locs_.push_back(prev); + prev = GetAdjacentLocation(prev, isClockw); + } while (prev != loc); + crossing_loc = crossing_prev; // still not crossed + } + else if (prev != Location::Inside && prev != loc) + { + bool isClockw = IsClockwise(prev, loc, prev_pt, path[i], mp_); + do { + AddCorner(prev, isClockw); + } while (prev != loc); + } + ++i; + continue; + } + + //////////////////////////////////////////////////// + // we must be crossing the rect boundary to get here + //////////////////////////////////////////////////// + + if (loc == Location::Inside) // path must be entering rect + { + if (first_cross_ == Location::Inside) + { + first_cross_ = crossing_loc; + start_locs_.push_back(prev); + } + else if (prev != crossing_loc) + { + bool isClockw = IsClockwise(prev, crossing_loc, prev_pt, path[i], mp_); + do { + AddCorner(prev, isClockw); + } while (prev != crossing_loc); + } + } + else if (prev != Location::Inside) + { + // passing right through rect. 'ip' here will be the second + // intersect pt but we'll also need the first intersect pt (ip2) + loc = prev; + GetIntersection(rectPath_, prev_pt, path[i], loc, ip2); + if (crossing_prev != Location::Inside) + AddCorner(crossing_prev, loc); + + if (first_cross_ == Location::Inside) + { + first_cross_ = loc; + start_locs_.push_back(prev); + } + + loc = crossing_loc; + result_.push_back(ip2); + if (ip == ip2) + { + // it's very likely that path[i] is on rect + GetLocation(rect_, path[i], loc); + AddCorner(crossing_loc, loc); + crossing_loc = loc; + continue; + } + } + else // path must be exiting rect + { + loc = crossing_loc; + if (first_cross_ == Location::Inside) + first_cross_ = crossing_loc; + } + + result_.push_back(ip); + + } //while i <= highI + /////////////////////////////////////////////////// + + if (first_cross_ == Location::Inside) + { + if (starting_loc == Location::Inside) return path; + Rect64 tmp_rect = Bounds(path); + if (tmp_rect.Contains(rect_) && + Path1ContainsPath2(path, rectPath_) != + PointInPolygonResult::IsOutside) return rectPath_; + else + return Path64(); + } + + if (loc != Location::Inside && + (loc != first_cross_ || start_locs_.size() > 2)) + { + if (start_locs_.size() > 0) + { + prev = loc; + for (auto loc2 : start_locs_) + { + if (prev == loc2) continue; + AddCorner(prev, HeadingClockwise(prev, loc2)); + prev = loc2; + } + loc = prev; + } + if (loc != first_cross_) + AddCorner(loc, HeadingClockwise(loc, first_cross_)); + } + + if (result_.size() < 3) return Path64(); + + // tidy up duplicates and collinear segments + Path64 res; + res.reserve(result_.size()); + size_t k = 0; highI = static_cast(result_.size()) - 1; + Point64 prev_pt = result_[highI]; + res.push_back(result_[0]); + Path64::const_iterator cit; + for (cit = result_.cbegin() + 1; cit != result_.cend(); ++cit) + { + if (CrossProduct(prev_pt, res[k], *cit)) + { + prev_pt = res[k++]; + res.push_back(*cit); + } + else + res[k] = *cit; + } + + if (k < 2) return Path64(); + // and a final check for collinearity + else if (!CrossProduct(res[0], res[k - 1], res[k])) res.pop_back(); + return res; + } + + Paths64 RectClipLines::Execute(const Path64& path) + { + result_.clear(); + Paths64 result; + if (rect_.IsEmpty() || path.size() == 0) return result; + + int i = 1, highI = static_cast(path.size()) - 1; + + Location prev = Location::Inside, loc; + Location crossing_loc = Location::Inside; + if (!GetLocation(rect_, path[0], loc)) + { + while (i <= highI && !GetLocation(rect_, path[i], prev)) ++i; + if (i > highI) { + result.push_back(path); + return result; + } + if (prev == Location::Inside) loc = Location::Inside; + i = 1; + } + if (loc == Location::Inside) result_.push_back(path[0]); + + /////////////////////////////////////////////////// + while (i <= highI) + { + prev = loc; + GetNextLocation(path, loc, i, highI); + if (i > highI) break; + Point64 ip, ip2; + Point64 prev_pt = path[static_cast(i - 1)]; + + crossing_loc = loc; + if (!GetIntersection(rectPath_, path[i], prev_pt, crossing_loc, ip)) + { + // ie remaining outside + ++i; + continue; + } + + //////////////////////////////////////////////////// + // we must be crossing the rect boundary to get here + //////////////////////////////////////////////////// + + if (loc == Location::Inside) // path must be entering rect + { + result_.push_back(ip); + } + else if (prev != Location::Inside) + { + // passing right through rect. 'ip' here will be the second + // intersect pt but we'll also need the first intersect pt (ip2) + crossing_loc = prev; + GetIntersection(rectPath_, prev_pt, path[i], crossing_loc, ip2); + result_.push_back(ip2); + result_.push_back(ip); + result.push_back(result_); + result_.clear(); + } + else // path must be exiting rect + { + result_.push_back(ip); + result.push_back(result_); + result_.clear(); + } + } //while i <= highI + /////////////////////////////////////////////////// + + if (result_.size() > 1) + result.push_back(result_); + return result; + } + +} // namespace diff --git a/src/imgui/CMakeLists.txt b/src/imgui/CMakeLists.txt index 235afe1105..213b3b830f 100644 --- a/src/imgui/CMakeLists.txt +++ b/src/imgui/CMakeLists.txt @@ -14,3 +14,7 @@ add_library(imgui STATIC imgui_draw.cpp imgui_widgets.cpp ) + +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) +endif() \ No newline at end of file diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 56e90af952..4c32a701a1 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -139,16 +139,21 @@ namespace ImGui const wchar_t EjectHoverButton = 0x13; const wchar_t CancelButton = 0x14; const wchar_t CancelHoverButton = 0x15; + const wchar_t CloseNotifDarkButton = 0x16; + const wchar_t CloseNotifHoverDarkButton = 0x17; // const wchar_t VarLayerHeightMarker = 0x16; const wchar_t RightArrowButton = 0x18; const wchar_t RightArrowHoverButton = 0x19; const wchar_t PreferencesButton = 0x1A; const wchar_t PreferencesHoverButton = 0x1B; + const wchar_t DocumentationDarkButton = 0x1C; + const wchar_t DocumentationHoverDarkButton = 0x1D; // const wchar_t SinkingObjectMarker = 0x1C; // const wchar_t CustomSupportsMarker = 0x1D; // const wchar_t CustomSeamMarker = 0x1E; // const wchar_t MmuSegmentationMarker = 0x1F; + // Do not forget use following letters only in wstring //BBS use 08xx to avoid unicode character which may be used const wchar_t DocumentationButton = 0x0800; @@ -167,6 +172,20 @@ namespace ImGui const wchar_t SphereButtonIcon = 0x0816; const wchar_t GapFillIcon = 0x0817; + const wchar_t MinimalizeDarkButton = 0x081C; + const wchar_t MinimalizeHoverDarkButton = 0x081D; + const wchar_t RightArrowDarkButton = 0x081E; + const wchar_t RightArrowHoverDarkButton = 0x081F; + const wchar_t PreferencesDarkButton = 0x0820; + const wchar_t PreferencesHoverDarkButton = 0x0821; + + const wchar_t CircleButtonDarkIcon = 0x0822; + const wchar_t TriangleButtonDarkIcon = 0x0823; + const wchar_t FillButtonDarkIcon = 0x0824; + const wchar_t HeightRangeDarkIcon = 0x0825; + const wchar_t SphereButtonDarkIcon = 0x0826; + const wchar_t GapFillDarkIcon = 0x0827; + // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/imgui/imgui.h b/src/imgui/imgui.h index 4aa9dac3e9..750e458246 100644 --- a/src/imgui/imgui.h +++ b/src/imgui/imgui.h @@ -620,6 +620,7 @@ namespace ImGui // - A selectable highlights when hovered, and can display another color when selected. // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool BBLImageSelectable(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& font_size, int font_line, const ImVec4& tint_col, const ImVec2& uv0, const ImVec2& uv1, bool selected = false); IMGUI_API bool BBLSelectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. @@ -659,7 +660,7 @@ namespace ImGui IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! - IMGUI_API bool BBLMenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. + IMGUI_API bool BBLMenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true, float size_arg_y = 0.0f); // return true when activated. IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL @@ -2648,6 +2649,8 @@ struct ImFontAtlas // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesBasic(); // Basic + IMGUI_API const ImWchar* GetGlyphRangesEnglish(); // Basic Latin + Latin Supplement IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs @@ -2655,6 +2658,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + IMGUI_API const ImWchar* GetGlyphRangesOthers(); //------------------------------------------- // [BETA] Custom Rectangles/Glyphs API diff --git a/src/imgui/imgui_draw.cpp b/src/imgui/imgui_draw.cpp index 70f6b04186..8dac5adbc4 100644 --- a/src/imgui/imgui_draw.cpp +++ b/src/imgui/imgui_draw.cpp @@ -53,6 +53,7 @@ Index of this file: #include // alloca #endif #endif +#include // Visual Studio warnings #ifdef _MSC_VER @@ -2345,7 +2346,6 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) dst_tmp_array.resize(atlas->Fonts.Size); memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); - // 1. Initialize font loading structure, check font data validity for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) { @@ -2365,9 +2365,15 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) } // Initialize helper structure for font loading and verify that the TTF/OTF data is correct const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + if (font_offset < 0) + BOOST_LOG_TRIVIAL(info) << "font_name: " << cfg.Name << ", font_offset: " << font_offset << ", font_no: " << cfg.FontNo << ", font_data_tag:" + << ((unsigned char*)cfg.FontData)[0] << ((unsigned char*)cfg.FontData)[1] << ((unsigned char*)cfg.FontData)[2] << ((unsigned char*)cfg.FontData)[3]; IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); - if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) { + BOOST_LOG_TRIVIAL(info) << "stbtt_InitFont failed, font_name: " << cfg.Name << ", font_data_tag:" + << ((unsigned char*)cfg.FontData)[0] << ((unsigned char*)cfg.FontData)[1] << ((unsigned char*)cfg.FontData)[2] << ((unsigned char*)cfg.FontData)[3];; return false; + } // Measure highest codepoints ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; @@ -2806,12 +2812,49 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) } } +const ImWchar* ImFontAtlas::GetGlyphRangesBasic() +{ + static const ImWchar ranges[] = + { + 0x0041, 0x005A, // A-Z + 0x0061, 0x007A, // a-z + 0x0020, 0x0021, + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesEnglish() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesOthers() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0100, 0x017F, // Latin Extended-A + 0x0180, 0x024F, // Latin Extended-B + 0x2000, 0x206F, // General Punctuation + 0xFF00, 0xFFEF, // Half-width characters + 0, + }; + return &ranges[0]; +} + // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { static const ImWchar ranges[] = { - 0x0020, 0x01FF, // Basic Latin + Latin Supplement + 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions @@ -2862,8 +2905,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* //------------------------------------------------------------------------- // [SECTION] ImFontAtlas glyph ranges helpers //------------------------------------------------------------------------- - -const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() // used in bold_font only { // Store 2500 regularly used characters for Simplified Chinese. // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 @@ -2919,14 +2961,15 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() 0x2000, 0x206F, // General Punctuation 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0x4e00, 0x9FAF, // CJK Ideograms - 0xFF00, 0xFFEF // Half-width characters + 0xFF00, 0xFFEF, // Half-width characters + 0X5C4F, 0X5C50, + 0x2103, 0x2104, }; static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; if (!full_ranges[0]) { memcpy(full_ranges, base_ranges, sizeof(base_ranges)); - //UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); } return &full_ranges[0]; } diff --git a/src/imgui/imgui_widgets.cpp b/src/imgui/imgui_widgets.cpp index fc09d6063f..810a62d7a9 100644 --- a/src/imgui/imgui_widgets.cpp +++ b/src/imgui/imgui_widgets.cpp @@ -7064,6 +7064,161 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl return pressed; } +bool ImGui::BBLImageSelectable(ImTextureID user_texture_id, const ImVec2& size_arg, const ImVec2& font_size, int font_line, const ImVec4& tint_col, const ImVec2& uv0, const ImVec2& uv1, bool selected) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#BBLImageSelectable"); + PopID(); + + ImGuiSelectableFlags flags = 0; + + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : 0.0f, size_arg.y != 0.0f ? size_arg.y : 0.0f); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(size, 0.0f); + + // Fill horizontal space + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; + const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; + const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) size.x = ImMax(0.0f, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 text_min = ImVec2(pos.x + arrow_size, pos.y); + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); + if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { + const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += (spacing_x - spacing_L); + bb.Max.y += (spacing_y - spacing_U); + } + // if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) { + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; + } + + bool item_add; + if (flags & ImGuiSelectableFlags_Disabled) { + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + item_add = ItemAdd(bb, id); + g.CurrentItemFlags = backup_item_flags; + } + else { + item_add = ItemAdd(bb, id); + } + + if (span_all_columns) { + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; + } + + if (!item_add) return false; + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_Disabled) { button_flags |= ImGuiButtonFlags_Disabled; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + + if (flags & ImGuiSelectableFlags_Disabled) selected = false; + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (hovered || g.ActiveId == id) { + ImGui::PushStyleColor(ImGuiCol_Border, GetColorU32(ImGuiCol_BorderActive)); + if (arrow_size == 0) { + RenderFrameBorder(bb.Min, ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), style.FrameRounding); + } + else { + RenderFrameBorder(ImVec2(bb.Min.x + style.WindowPadding.x, bb.Min.y), ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), style.FrameRounding); + } + ImGui::PopStyleColor(1); + } + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent, ImRect(bb.Min - window->Pos, bb.Max - window->Pos)); + g.NavDisableHighlight = true; + } + } + if (pressed) MarkItemEdited(id); + + if (flags & ImGuiSelectableFlags_AllowItemOverlap) SetItemAllowOverlap(); + + // In this branch, Selectable() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) hovered = true; + if (hovered || selected) { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + if (arrow_size == 0) { + RenderFrame(bb.Min, ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), col, false, 0.0f); + } + else { + RenderFrame(ImVec2(bb.Min.x + style.WindowPadding.x, bb.Min.y), ImVec2(bb.Max.x - style.WindowPadding.x, bb.Max.y), col, false, 0.0f); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + + if (span_all_columns && window->DC.CurrentColumns) + PopColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); + + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImVec2 p_min = bb.Min + ImVec2(2 * style.ItemSpacing.x, (bb.Max.y - bb.Min.y - font_size.y) / 2); + ImVec2 p_max = p_min + font_size; + window->DrawList->AddImage(user_texture_id, p_min, p_max, uv0, uv1, GetColorU32(tint_col)); + + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.CurrentItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + + return pressed; +} + bool ImGui::BBLSelectable(const char *label, bool selected, ImGuiSelectableFlags flags, const ImVec2 &size_arg) { ImGuiWindow *window = GetCurrentWindow(); @@ -7917,7 +8072,7 @@ void ImGui::EndMenu() EndPopup(); } -bool ImGui::BBLMenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +bool ImGui::BBLMenuItem(const char* label, const char* shortcut, bool selected, bool enabled, float size_arg_y) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -7939,7 +8094,7 @@ bool ImGui::BBLMenuItem(const char* label, const char* shortcut, bool selected, float w = label_size.x; window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); - pressed = BBLSelectable(label, selected, flags, ImVec2(w, 0.0f)); + pressed = BBLSelectable(label, selected, flags, ImVec2(w, size_arg_y)); PopStyleVar(); window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). } @@ -7951,7 +8106,7 @@ bool ImGui::BBLMenuItem(const char* label, const char* shortcut, bool selected, float shortcut_w = shortcut ? CalcTextSize(shortcut, NULL).x : 0.0f; float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, shortcut_w, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); - pressed = BBLSelectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth | ImGuiComboFlags_NoArrowButton, ImVec2(min_w, 0.0f)); + pressed = BBLSelectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth | ImGuiComboFlags_NoArrowButton, ImVec2(min_w, size_arg_y)); if (shortcut_w > 0.0f) { PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); diff --git a/src/imgui/imstb_truetype.h b/src/imgui/imstb_truetype.h index fc815d7452..17cbcbcfd5 100644 --- a/src/imgui/imstb_truetype.h +++ b/src/imgui/imstb_truetype.h @@ -1311,11 +1311,11 @@ static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { stbtt_int32 n = ttLONG(font_collection+8); if (index >= n) - return -1; + return -2; return ttULONG(font_collection+12+index*4); } } - return -1; + return -3; } static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) @@ -1365,19 +1365,28 @@ static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, in info->kern = stbtt__find_table(data, fontstart, "kern"); // not required info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required - if (!cmap || !info->head || !info->hhea || !info->hmtx) + if (!cmap || !info->head || !info->hhea || !info->hmtx) { + BOOST_LOG_TRIVIAL(info) << "Cannot find cmap/head/hhea/hmtx table"; return 0; + } if (info->glyf) { // required for truetype - if (!info->loca) return 0; + if (!info->loca) { + BOOST_LOG_TRIVIAL(info) << "Cannot find loca table"; + return 0; + } } else { // initialization for CFF / Type2 fonts (OTF) + BOOST_LOG_TRIVIAL(info) << "initialization for CFF / Type2 fonts (OTF)"; stbtt__buf b, topdict, topdictidx; stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; stbtt_uint32 cff; cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; + if (!cff) { + BOOST_LOG_TRIVIAL(info) << "Cannot find cff table"; + return 0; + } info->fontdicts = stbtt__new_buf(NULL, 0); info->fdselect = stbtt__new_buf(NULL, 0); diff --git a/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp b/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp index 14b075b19d..63ed1c2779 100644 --- a/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp @@ -261,6 +261,8 @@ inline TMultiShape merge(const TMultiShape& shapes) return Slic3r::union_ex(shapes); } +inline TMultiShape subtract(const TMultiShape &outerBinNfp, const TMultiShape &shapes) { return Slic3r::diff_ex(outerBinNfp, shapes); } + } // namespace nfp } // namespace libnest2d diff --git a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp index 70b300ef69..ab5f7678fd 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp @@ -179,6 +179,42 @@ inline TPoint referenceVertex(const RawShape& sh) return rightmostUpVertex(sh); } +template inline NfpResult nfpInnerRectBed(const RawBox &bed, const RawShape &other) +{ + using Vertex = TPoint; + using Edge = _Segment; + namespace sl = shapelike; + + auto sbox = sl::boundingBox(other); + auto sheight = sbox.height(); + auto swidth = sbox.width(); + Vertex slidingTop = rightmostUpVertex(other); + auto leftOffset = slidingTop.x() - sbox.minCorner().x(); + auto rightOffset = slidingTop.x() - sbox.maxCorner().x(); + auto topOffset = 0; + auto bottomOffset = sheight; + + + auto boxWidth = bed.width(); + auto boxHeight = bed.height(); + + auto bedMinx = bed.minCorner().x(); + auto bedMiny = bed.minCorner().y(); + auto bedMaxx = bed.maxCorner().x(); + auto bedMaxy = bed.maxCorner().y(); + + RawShape innerNfp{{bedMinx + leftOffset, bedMaxy + topOffset}, + {bedMaxx + rightOffset, bedMaxy + topOffset}, + {bedMaxx + rightOffset, bedMiny + bottomOffset}, + {bedMinx + leftOffset, bedMiny + bottomOffset}, + {bedMinx + leftOffset, bedMaxy + topOffset}}; + if (sheight > boxHeight || swidth > boxWidth) { + return {{}, {0, 0}}; + } else { + return {innerNfp, {0, 0}}; + } +} + /** * The "trivial" Cuninghame-Green implementation of NFP for convex polygons. * diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 29de288b9a..08afd130b5 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -481,7 +481,7 @@ public: auto d = bbin.center() - bb.center(); _Rectangle rect(bb.width(), bb.height()); rect.translate(bb.minCorner() + d); - return sl::isInside(rect.transformedShape(), bin) ? -1.0 : 1; + return sl::isInside(rect.transformedShape(), bin) ? -1.5 : 1; } static inline double overfit(const RawShape& chull, const RawShape& bin) { @@ -565,7 +565,7 @@ private: using Shapes = TMultiShape; - Shapes calcnfp(const Item &trsh, Lvl) + Shapes calcnfp(const Item &trsh, const Box& bed ,Lvl) { using namespace nfp; @@ -598,7 +598,8 @@ private: nfps[n] = subnfp_r.first; }); - return nfp::merge(nfps); + RawShape innerNfp = nfpInnerRectBed(bed, trsh.transformedShape()).first; + return nfp::subtract({innerNfp}, nfps); } @@ -738,7 +739,7 @@ private: // it is disjunct from the current merged pile placeOutsideOfBin(item); - nfps = calcnfp(item, Lvl()); + nfps = calcnfp(item, binbb, Lvl()); auto iv = item.referenceVertex(); @@ -907,7 +908,7 @@ private: } } - if( best_score < global_score && best_score< LARGE_COST_TO_REJECT) { + if( best_score < global_score) { auto d = (getNfpPoint(optimum) - iv) + startpos; final_tr = d; final_rot = initial_rot + rot; @@ -922,7 +923,10 @@ private: #ifdef SVGTOOLS_HPP svg::SVGWriter svgwriter; - svgwriter.setSize(binbb); + Box binbb2(binbb.width() * 2, binbb.height() * 2, binbb.center()); // expand bbox to allow object be drawed outside + svgwriter.setSize(binbb2); + svgwriter.conf_.x0 = binbb.width(); + svgwriter.conf_.y0 = -binbb.height()/2; // origin is top left corner svgwriter.writeShape(box2RawShape(binbb), "none", "black"); for (int i = 0; i < nfps.size(); i++) svgwriter.writeShape(nfps[i], "none", "blue"); @@ -1031,51 +1035,50 @@ private: if (!item.is_virt_object) bb = sl::boundingBox(item.boundingBox(), bb); - // BBS TODO assume the nonprefered regions are at the bottom left corner - Box bin_reduced = bbin; - for (const auto& region : config_.m_nonprefered_regions) - { - Box bb1 = region.boundingBox(); - if (bb1.maxCorner().y() bb.height() && bb.height()>bbin.height()-2*bb1.maxCorner().y()) { - // could use a tighter bound by moving bed center higher - bin_reduced.minCorner().y() = bb1.maxCorner().y(); - continue; - } - if (bb1.maxCorner().x() bb.width() && bb.width()>bbin.width()-2*bb1.maxCorner().x()) { - // could use a tighter bound - bin_reduced.minCorner().x() = bb1.maxCorner().x(); - continue; + // if move to center is infeasible, move to topright corner instead + auto alignment = config_.alignment; + if (!config_.m_excluded_regions.empty() && alignment== Config::Alignment::CENTER) { + Box bb2 = bb; + auto d = bbin.center() - bb2.center(); + d.x() = std::max(d.x(), 0); + d.y() = std::max(d.y(), 0); + bb2.minCorner() += d; + bb2.maxCorner() += d; + for (auto& region : config_.m_excluded_regions) { + auto region_bb = region.boundingBox(); + if (bb2.intersection(region_bb).area()>0) { + alignment = Config::Alignment::TOP_RIGHT; + break; + } } } Vertex ci, cb; - switch(config_.alignment) { + switch(alignment) { case Config::Alignment::CENTER: { ci = bb.center(); - cb = bin_reduced.center(); + cb = bbin.center(); break; } case Config::Alignment::BOTTOM_LEFT: { ci = bb.minCorner(); - cb = bin_reduced.minCorner(); + cb = bbin.minCorner(); break; } case Config::Alignment::BOTTOM_RIGHT: { ci = {getX(bb.maxCorner()), getY(bb.minCorner())}; - cb = {getX(bin_reduced.maxCorner()), getY(bin_reduced.minCorner())}; + cb = {getX(bbin.maxCorner()), getY(bbin.minCorner())}; break; } case Config::Alignment::TOP_LEFT: { ci = {getX(bb.minCorner()), getY(bb.maxCorner())}; - cb = {getX(bin_reduced.minCorner()), getY(bin_reduced.maxCorner())}; + cb = {getX(bbin.minCorner()), getY(bbin.maxCorner())}; break; } case Config::Alignment::TOP_RIGHT: { ci = bb.maxCorner(); - cb = bin_reduced.maxCorner(); + cb = bbin.maxCorner(); break; } default: ; // DONT_ALIGN diff --git a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp index 18c70468ea..4b2af5f7b6 100644 --- a/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/placers/placer_boilerplate.hpp @@ -43,7 +43,7 @@ public: public: operator bool() { return item_ptr_ != nullptr; } double overfit() const { return overfit_; } - double score_ = -1; + double score_ = -1.11; double score() { return score_; } int plate_id = 0; // BBS }; diff --git a/src/libnest2d/tools/svgtools.hpp b/src/libnest2d/tools/svgtools.hpp index d00a74227f..2bf090b329 100644 --- a/src/libnest2d/tools/svgtools.hpp +++ b/src/libnest2d/tools/svgtools.hpp @@ -35,8 +35,9 @@ public: }; -private: Config conf_; + +private: std::vector svg_layers_; bool finished_ = false; public: diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 6946964932..0fd431972c 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -185,13 +185,13 @@ void AppConfig::set_defaults() #ifdef SUPPORT_DARK_MODE if (get("dark_color_mode").empty()) - set_bool("dark_color_mode", false); + set("dark_color_mode", "0"); #endif -#ifdef SUPPORT_SYS_MENU +//#ifdef SUPPORT_SYS_MENU if (get("sys_menu_enabled").empty()) - set_bool("sys_menu_enabled", true); -#endif + set("sys_menu_enabled", "1"); +//#endif #endif // _WIN32 // BBS @@ -288,9 +288,9 @@ void AppConfig::set_defaults() if (get("backup_interval").empty()) { set("backup_interval", "10"); } - + if (get("curr_bed_type").empty()) { - set("curr_bed_type", "0"); + set("curr_bed_type", "1"); } // #if BBL_RELEASE_TO_PUBLIC @@ -458,7 +458,6 @@ std::string AppConfig::load() } else if (it.key() == "presets") { for (auto iter = it.value().begin(); iter != it.value().end(); iter++) { if (iter.key() == "filaments") { - // BBS: filament presets is now considered as project config instead of app config int idx = 0; for(auto& element: iter.value()) { if (idx == 0) @@ -480,7 +479,14 @@ std::string AppConfig::load() } else { m_storage[it.key()][iter.key()] = "false"; } - } else { + } else if (iter.key() == "filament_presets") { + m_filament_presets = iter.value().get>(); + } else if (iter.key() == "filament_colors") { + m_filament_colors = iter.value().get>(); + } else if (iter.key() == "flushing_volumes") { + m_flush_volumes_matrix = iter.value().get>(); + } + else { if (iter.value().is_string()) m_storage[it.key()][iter.key()] = iter.value().get(); else { @@ -531,7 +537,7 @@ void AppConfig::save() { // Returns "undefined" if the thread naming functionality is not supported by the operating system. std::optional current_thread_name = get_current_thread_name(); - if (current_thread_name && *current_thread_name != "bambustu_main") { + if (current_thread_name && *current_thread_name != "bambustu_main" && *current_thread_name != "main") { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<<", current_thread_name is " << *current_thread_name; throw CriticalException("Calling AppConfig::save() from a worker thread, thread name: " + *current_thread_name); } @@ -563,6 +569,18 @@ void AppConfig::save() j["app"][kvp.first] = kvp.second; } + for (const auto &filament_preset : m_filament_presets) { + j["app"]["filament_presets"].push_back(filament_preset); + } + + for (const auto &filament_color : m_filament_colors) { + j["app"]["filament_colors"].push_back(filament_color); + } + + for (double flushing_volume : m_flush_volumes_matrix) { + j["app"]["flushing_volumes"].push_back(flushing_volume); + } + // Write the other categories. for (const auto& category : m_storage) { if (category.first.empty()) @@ -577,7 +595,7 @@ void AppConfig::save() } else if (category.first == "presets") { json j_filament_array; for(const auto& kvp : category.second) { - if (boost::starts_with(kvp.first, "filament")) { + if (boost::starts_with(kvp.first, "filament") && kvp.first != "filament_colors") { j_filament_array.push_back(kvp.second); } else { j[category.first][kvp.first] = kvp.second; @@ -930,7 +948,9 @@ void AppConfig::set_recent_projects(const std::vector& recent_proje it->second.clear(); for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i) { - it->second[std::to_string(i + 1)] = recent_projects[i]; + auto n = std::to_string(i + 1); + if (n.length() == 1) n = "0" + n; + it->second[n] = recent_projects[i]; } } diff --git a/src/libslic3r/AppConfig.hpp b/src/libslic3r/AppConfig.hpp index cd415d439d..7886ad96d1 100644 --- a/src/libslic3r/AppConfig.hpp +++ b/src/libslic3r/AppConfig.hpp @@ -17,6 +17,9 @@ using namespace nlohmann; #define ENV_PRE_HOST "2" #define ENV_PRODUCT_HOST "3" +#define SUPPORT_DARK_MODE +//#define _MSW_DARK_MODE + namespace Slic3r { @@ -164,6 +167,22 @@ public: void set_vendors(VendorMap &&vendors) { m_vendors = std::move(vendors); m_dirty = true; } const VendorMap& vendors() const { return m_vendors; } + const std::vector &get_filament_presets() const { return m_filament_presets; } + void set_filament_presets(const std::vector &filament_presets){ + m_filament_presets = filament_presets; + m_dirty = true; + } + const std::vector &get_filament_colors() const { return m_filament_colors; } + void set_filament_colors(const std::vector &filament_colors){ + m_filament_colors = filament_colors; + m_dirty = true; + } + const std::vector &get_flush_volumes_matrix() const { return m_flush_volumes_matrix; } + void set_flush_volumes_matrix(const std::vector &flush_volumes_matrix){ + m_flush_volumes_matrix = flush_volumes_matrix; + m_dirty = true; + } + // return recent/last_opened_folder or recent/settings_folder or empty string. std::string get_last_dir() const; void update_config_dir(const std::string &dir); @@ -259,6 +278,10 @@ private: bool m_legacy_datadir; std::string m_loading_path; + + std::vector m_filament_presets; + std::vector m_filament_colors; + std::vector m_flush_volumes_matrix; }; } // namespace Slic3r diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 82dcf0c9a1..4aa959a61d 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -84,7 +84,7 @@ const double BIG_ITEM_TRESHOLD = 0.02; template void fill_config(PConf& pcfg, const ArrangeParams ¶ms) { - if (params.is_seq_print) { + if (params.is_seq_print || params.excluded_regions.empty()==false) { // Align the arranged pile into the center of the bin pcfg.alignment = PConf::Alignment::CENTER; // Start placing the items from the center of the print bed @@ -137,7 +137,7 @@ static double fixed_overfit(const std::tuple& result, const Box &bi } // useful for arranging big circle objects -static double fixed_overfit_topright_sliding(const std::tuple& result, const Box& binbb) +static double fixed_overfit_topright_sliding(const std::tuple &result, const Box &binbb, const std::vector &excluded_boxes) { double score = std::get<0>(result); Box pilebb = std::get<1>(result); @@ -152,6 +152,12 @@ static double fixed_overfit_topright_sliding(const std::tuple& resu auto diff = double(fullbb.area()) - binbb.area(); if (diff > 0) score += diff; + // excluded regions and nonprefered regions should not intersect the translated pilebb + for (auto &bb : excluded_boxes) { + auto area_ = pilebb.intersection(bb).area(); + if (area_ > 0) score += area_; + } + return score; } @@ -190,6 +196,7 @@ protected: Box m_pilebb; // The bounding box of the merged pile. ItemGroup m_remaining; // Remaining items ItemGroup m_items; // allready packed items + std::vector m_excluded_and_extruCali_regions; // excluded and extrusion calib regions size_t m_item_count = 0; // Number of all items to be packed ArrangeParams params; @@ -202,14 +209,20 @@ protected: // 1) Y distance of item corner to bed corner. Must be put above bed corner. (high weight) // 2) X distance of item corner to bed corner (low weight) // 3) item row occupancy (useful when rotation is enabled) + // 4)需要允许往屏蔽区域的左边或下边去一点,不然很多物体可能认为摆不进去,实际上我们最后是可以做平移的 double dist_for_BOTTOM_LEFT(Box ibb, const ClipperLib::IntPoint& origin_pack) { double dist_corner_y = ibb.minCorner().y() - origin_pack.y(); double dist_corner_x = ibb.minCorner().x() - origin_pack.x(); - if (dist_corner_y < 0 || dist_corner_x<0) - return LARGE_COST_TO_REJECT; - double bindist = norm(dist_corner_y + 1 * dist_corner_x - + 1 * double(ibb.maxCorner().y() - ibb.minCorner().y())); // occupy as few rows as possible + // occupy as few rows as possible if we have rotations + double bindist = double(ibb.maxCorner().y() - ibb.minCorner().y()); + if (dist_corner_x >= 0 && dist_corner_y >= 0) + bindist += dist_corner_y + 1 * dist_corner_x; + else { + if (dist_corner_x < 0) bindist += 10 * (-dist_corner_x); + if (dist_corner_y < 0) bindist += 10 * (-dist_corner_y); + } + bindist = norm(bindist); return bindist; } @@ -350,9 +363,10 @@ protected: score = dist_for_BOTTOM_LEFT(ibb, origin_pack); } else { - score = 0.5 * norm(pl::distance(ibb.center(), origin_pack)); if (m_pilebb.defined) - score += 0.5 * norm(pl::distance(ibb.center(), m_pilebb.center())); + score = 0.5 * norm(pl::distance(ibb.center(), m_pilebb.center())); + else + score = 0.5 * norm(pl::distance(ibb.center(), origin_pack)); } break; } @@ -411,6 +425,7 @@ protected: if (p.is_virt_object) continue; score += lambda3 * (item.bed_temp - p.vitrify_temp > 0); } + score += lambda3 * (item.bed_temp - item.vitrify_temp > 0); score += lambda4 * hasRowHeightConflict + lambda4 * hasLidHeightConflict; } else { @@ -418,12 +433,20 @@ protected: Item& p = m_items[i]; if (p.is_virt_object) { // Better not put items above wipe tower - if (p.is_wipe_tower) - score += ibb.maxCorner().y() > p.boundingBox().maxCorner().y(); + if (p.is_wipe_tower) { + if (ibb.maxCorner().y() > p.boundingBox().maxCorner().y()) + score += 1; + else if(m_pilebb.defined) + score += norm(pl::distance(ibb.center(), m_pilebb.center())); + } else continue; - } else + } else { + // 高度接近的件尽量摆到一起 + score += (1- std::abs(item.height - p.height) / params.printable_height) + * norm(pl::distance(ibb.center(), p.boundingBox().center())); score += LARGE_COST_TO_REJECT * (item.bed_temp - p.bed_temp != 0); + } } } @@ -461,6 +484,14 @@ public: m_norm = std::sqrt(m_bin_area); fill_config(m_pconf, params); this->params = params; + for (auto& region : m_pconf.m_excluded_regions) { + Box bb = region.boundingBox(); + m_excluded_and_extruCali_regions.emplace_back(bb); + } + for (auto& region : m_pconf.m_nonprefered_regions) { + Box bb = region.boundingBox(); + m_excluded_and_extruCali_regions.emplace_back(bb); + } // Set up a callback that is called just before arranging starts // This functionality is provided by the Nester class (m_pack). @@ -498,28 +529,19 @@ public: m_pconf.object_function = get_objfn(); - auto bbox2expoly = [](Box bb) { - ExPolygon bin_poly; - auto c0 = bb.minCorner(); - auto c1 = bb.maxCorner(); - bin_poly.contour.points.emplace_back(c0); - bin_poly.contour.points.emplace_back(c1.x(), c0.y()); - bin_poly.contour.points.emplace_back(c1); - bin_poly.contour.points.emplace_back(c0.x(), c1.y()); - return bin_poly; - }; - // preload fixed items (and excluded regions) on plate m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) { if (items.empty()) return; - auto bb = sl::boundingBox(m_bin); + auto binbb = sl::boundingBox(m_bin); // BBS: excluded region (virtual object but not wipe tower) should not affect final alignment bool all_is_excluded_region = std::all_of(items.begin(), items.end(), [](Item &itm) { return itm.is_virt_object && !itm.is_wipe_tower; }); if (!all_is_excluded_region) cfg.alignment = PConfig::Alignment::DONT_ALIGN; + else + cfg.alignment = PConfig::Alignment::CENTER; - auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? bb.minCorner() : bb.center(); + auto starting_point = cfg.starting_point == PConfig::Alignment::BOTTOM_LEFT ? binbb.minCorner() : binbb.center(); // if we have wipe tower, items should be arranged around wipe tower for (Item itm : items) { if (itm.is_wipe_tower) { @@ -528,12 +550,16 @@ public: } } - cfg.object_function = [this, bb, starting_point](const Item& item, const ItemGroup& packed_items) { - bool packed_are_excluded_region = std::all_of(packed_items.begin(), packed_items.end(), [](Item& itm) { return itm.is_virt_object && !itm.is_wipe_tower; }); - if(packed_are_excluded_region) - return fixed_overfit_topright_sliding(objfunc(item, starting_point), bb); - else - return fixed_overfit(objfunc(item, starting_point), bb); + cfg.object_function = [this, binbb, starting_point](const Item &item, const ItemGroup &packed_items) { + // 在我们的摆盘中,没有天然的固定对象。固定对象只有:屏蔽区域、挤出补偿区域、料塔。 + // 对于屏蔽区域,摆入的对象仍然是可以向右上滑动的; + // 对挤出料塔,摆入的对象不能滑动(必须围绕料塔) + bool pack_around_wipe_tower = std::any_of(packed_items.begin(), packed_items.end(), [](Item& itm) { return itm.is_wipe_tower; }); + //if(pack_around_wipe_tower) + return fixed_overfit(objfunc(item, starting_point), binbb); + //else { + // return fixed_overfit_topright_sliding(objfunc(item, starting_point), binbb, m_excluded_and_extruCali_regions); + //} }; }; @@ -611,16 +637,18 @@ template<> std::function AutoArranger(result); auto& fullbb = std::get<1>(result); - if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT) - { - if (!sl::isInside(fullbb, m_bin)) - score += LARGE_COST_TO_REJECT; - } - else + //if (m_pconf.starting_point == PConfig::Alignment::BOTTOM_LEFT) + //{ + // if (!sl::isInside(fullbb, m_bin)) + // score += LARGE_COST_TO_REJECT; + //} + //else { double miss = Placer::overfit(fullbb, m_bin); miss = miss > 0 ? miss : 0; score += miss * miss; + if (score > LARGE_COST_TO_REJECT) + score = 1.5 * LARGE_COST_TO_REJECT; } return score; @@ -821,7 +849,7 @@ static void process_arrangeable(const ArrangePolygon &arrpoly, item.binId(arrpoly.bed_idx); item.priority(arrpoly.priority); item.itemId(arrpoly.itemid); - item.extrude_id = arrpoly.extrude_ids.back(); + item.extrude_id = arrpoly.extrude_ids.front(); item.height = arrpoly.height; item.name = arrpoly.name; //BBS: add virtual object logic diff --git a/src/libslic3r/Arrange.hpp b/src/libslic3r/Arrange.hpp index 09b3253656..d1f905b89b 100644 --- a/src/libslic3r/Arrange.hpp +++ b/src/libslic3r/Arrange.hpp @@ -124,6 +124,7 @@ struct ArrangeParams { float clearance_height_to_rod = 0; float clearance_height_to_lid = 0; float cleareance_radius = 0; + float printable_height = 256.0; ArrangePolygons excluded_regions; // regions cant't be used ArrangePolygons nonprefered_regions; // regions can be used but not prefered diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp index 03d671db47..a60f45f11a 100644 --- a/src/libslic3r/BridgeDetector.cpp +++ b/src/libslic3r/BridgeDetector.cpp @@ -122,6 +122,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) double max_length = 0; { Lines clipped_lines = intersection_ln(lines, clip_area); + size_t archored_line_num = 0; for (size_t i = 0; i < clipped_lines.size(); ++i) { const Line &line = clipped_lines[i]; if (expolygons_contain(this->_anchor_regions, line.a) && expolygons_contain(this->_anchor_regions, line.b)) { @@ -129,8 +130,12 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) double len = line.length(); total_length += len; max_length = std::max(max_length, len); + archored_line_num++; } - } + } + if (clipped_lines.size() > 0 && archored_line_num > 0) { + candidates[i_angle].archored_percent = (double)archored_line_num / (double)clipped_lines.size(); + } } if (total_length == 0.) continue; @@ -155,7 +160,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override) // if any other direction is within extrusion width of coverage, prefer it if shorter // TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred? size_t i_best = 0; - for (size_t i = 1; i < candidates.size() && candidates[i_best].coverage - candidates[i].coverage < this->spacing; ++ i) + for (size_t i = 1; i < candidates.size() && abs(candidates[i_best].archored_percent - candidates[i].archored_percent) < EPSILON; ++ i) if (candidates[i].max_length < candidates[i_best].max_length) i_best = i; diff --git a/src/libslic3r/BridgeDetector.hpp b/src/libslic3r/BridgeDetector.hpp index e97dd45c40..d422949cd7 100644 --- a/src/libslic3r/BridgeDetector.hpp +++ b/src/libslic3r/BridgeDetector.hpp @@ -44,15 +44,16 @@ private: void initialize(); struct BridgeDirection { - BridgeDirection(double a = -1.) : angle(a), coverage(0.), max_length(0.) {} + BridgeDirection(double a = -1.) : angle(a), coverage(0.), max_length(0.), archored_percent(0.){} // the best direction is the one causing most lines to be bridged (thus most coverage) bool operator<(const BridgeDirection &other) const { // Initial sort by coverage only - comparator must obey strict weak ordering - return this->coverage > other.coverage; + return this->archored_percent > other.archored_percent; }; double angle; double coverage; double max_length; + double archored_percent; }; // Get possible briging direction candidates. diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 5fe753dcdd..a2e0373976 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -876,6 +876,8 @@ static ExPolygons outer_inner_brim_area(const Print& print, brimToWrite.insert({ objectWithExtruder.first, {true,true} }); ExPolygons objectIslands; + auto bedPoly = Model::getBedPolygon(); + auto bedExPoly = diff_ex((offset(bedPoly, scale_(30.), jtRound, SCALED_RESOLUTION)), { bedPoly }); for (unsigned int extruderNo : printExtruders) { ++extruderNo; @@ -1036,7 +1038,9 @@ static ExPolygons outer_inner_brim_area(const Print& print, } } } - for (const PrintObject* object : print.objects()) + if (!bedExPoly.empty()) + no_brim_area.push_back(bedExPoly.front()); + for (const PrintObject* object : print.objects()) if (brimAreaMap.find(object->id()) != brimAreaMap.end()) { brimAreaMap[object->id()] = diff_ex(brimAreaMap[object->id()], no_brim_area); diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 66874674a9..a10cc5aa12 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -35,6 +35,8 @@ set(lisbslic3r_sources clipper.hpp ClipperUtils.cpp ClipperUtils.hpp + Clipper2Utils.cpp + Clipper2Utils.hpp Config.cpp Config.hpp CurveAnalyzer.cpp @@ -108,6 +110,8 @@ set(lisbslic3r_sources Format/STL.hpp Format/SL1.hpp Format/SL1.cpp + Format/svg.hpp + Format/svg.cpp GCode/ThumbnailData.cpp GCode/ThumbnailData.hpp GCode/CoolingBuffer.cpp @@ -474,6 +478,7 @@ target_link_libraries(libslic3r PNG::PNG ZLIB::ZLIB ${OCCT_LIBS} + Clipper2 ) if(NOT WIN32) diff --git a/src/libslic3r/Clipper2Utils.cpp b/src/libslic3r/Clipper2Utils.cpp new file mode 100644 index 0000000000..92acd5e385 --- /dev/null +++ b/src/libslic3r/Clipper2Utils.cpp @@ -0,0 +1,60 @@ +#include "Clipper2Utils.hpp" + +namespace Slic3r { + +//BBS: FIXME +Slic3r::Polylines Paths64_to_polylines(const Clipper2Lib::Paths64& in) +{ + Slic3r::Polylines out; + out.reserve(in.size()); + for (const Clipper2Lib::Path64& path64 : in) { + Slic3r::Points points; + points.reserve(path64.size()); + for (const Clipper2Lib::Point64& point64 : path64) + points.emplace_back(std::move(Slic3r::Point(point64.x, point64.y))); + out.emplace_back(std::move(Slic3r::Polyline(points))); + } + return out; +} + +//BBS: FIXME +template +Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const std::vector& in) +{ + Clipper2Lib::Paths64 out; + out.reserve(in.size()); + for (const T item: in) { + Clipper2Lib::Path64 path; + path.reserve(item.size()); + for (const Slic3r::Point& point : item.points) + path.emplace_back(std::move(Clipper2Lib::Point64(point.x(), point.y()))); + out.emplace_back(std::move(path)); + } + return out; +} + +Polylines _clipper2_pl_open(Clipper2Lib::ClipType clipType, const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) +{ + Clipper2Lib::Clipper64 c; + c.AddOpenSubject(Slic3rPoints_to_Paths64(subject)); + c.AddClip(Slic3rPoints_to_Paths64(clip)); + + Clipper2Lib::ClipType ct = clipType; + Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero; + Clipper2Lib::Paths64 solution, solution_open; + c.Execute(ct, fr, solution, solution_open); + + Slic3r::Polylines out; + out.reserve(solution.size() + solution_open.size()); + polylines_append(out, std::move(Paths64_to_polylines(solution))); + polylines_append(out, std::move(Paths64_to_polylines(solution_open))); + + return out; +} + +Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) + { return _clipper2_pl_open(Clipper2Lib::ClipType::Intersection, subject, clip); } +Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip) + { return _clipper2_pl_open(Clipper2Lib::ClipType::Difference, subject, clip); } + +} \ No newline at end of file diff --git a/src/libslic3r/Clipper2Utils.hpp b/src/libslic3r/Clipper2Utils.hpp new file mode 100644 index 0000000000..f69421711e --- /dev/null +++ b/src/libslic3r/Clipper2Utils.hpp @@ -0,0 +1,17 @@ +#ifndef slic3r_Clipper2Utils_hpp_ +#define slic3r_Clipper2Utils_hpp_ + +#include "libslic3r.h" +#include "clipper2/clipper.h" +#include "Polygon.hpp" +#include "Polyline.hpp" + +namespace Slic3r { + +Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip); +Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip); + +} + +#endif + diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index c6e6c1797a..93ec1fd27e 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -534,7 +534,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, this->handle_legacy(opt_key, value); if (opt_key.empty()) { // Ignore the option. - //BBS: record these options, keep only one repeated opt_key + //BBS: record these options, keep only one repeated opt_key auto iter = std::find(substitutions_ctxt.unrecogized_keys.begin(), substitutions_ctxt.unrecogized_keys.end(), opt_key_src); if (iter == substitutions_ctxt.unrecogized_keys.end()) substitutions_ctxt.unrecogized_keys.push_back(opt_key_src); @@ -615,7 +615,7 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con if (! success && substitutions_ctxt.rule != ForwardCompatibilitySubstitutionRule::Disable && // Only allow substitutions of an enum value by another enum value or a boolean value with an enum value. // That means, we expect enum values being added in the future and possibly booleans being converted to enums. - (optdef->type == coEnum || optdef->type == coBool) && ConfigHelpers::looks_like_enum_value(value)) { + (optdef->type == coEnum || optdef->type == coEnums || optdef->type == coBool) /*&& ConfigHelpers::looks_like_enum_value(value)*/) { // Deserialize failed, try to substitute with a default value. //assert(substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::Enable || substitutions_ctxt.rule == ForwardCompatibilitySubstitutionRule::EnableSilent); if (optdef->type == coBool) @@ -757,6 +757,9 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex if (boost::iequals(it.key(),BBL_JSON_KEY_VERSION)) { key_values.emplace(BBL_JSON_KEY_VERSION, it.value()); } + else if (boost::iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) { + key_values.emplace(BBL_JSON_KEY_IS_CUSTOM, it.value()); + } else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) { key_values.emplace(BBL_JSON_KEY_NAME, it.value()); } @@ -1209,14 +1212,15 @@ ConfigSubstitutions ConfigBase::load_from_gcode_file(const std::string &file, Fo } //BBS: add json support -void ConfigBase::save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version) const +void ConfigBase::save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version, const std::string is_custom) const { json j; - //record the headers j[BBL_JSON_KEY_VERSION] = version; j[BBL_JSON_KEY_NAME] = name; j[BBL_JSON_KEY_FROM] = from; + if (!is_custom.empty()) + j[BBL_JSON_KEY_IS_CUSTOM] = is_custom; //record all the key-values for (const std::string &opt_key : this->keys()) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 7936546303..3c7f13092f 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -1701,12 +1701,12 @@ public: while (std::getline(is, item_str, ',')) { boost::trim(item_str); if (item_str == "nil") { - throw ConfigurationError("Deserializing nil into a non-nullable object"); + return false; } else { auto it = this->keys_map->find(item_str); if (it == this->keys_map->end()) - throw ConfigurationError(std::string("Unknown enum type: ") + item_str); + return false; this->values.push_back(it->second); } } @@ -2139,7 +2139,7 @@ public: void save(const std::string &file) const; //BBS: add json support - void save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version) const; + void save_to_json(const std::string &file, const std::string &name, const std::string &from, const std::string &version, const std::string is_custom = "") const; // Set all the nullable values to nils. void null_nullables(); diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 2d82729f22..98a9362c48 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -92,6 +92,12 @@ bool ExPolygon::contains(const Line &line) const bool ExPolygon::contains(const Polyline &polyline) const { + BoundingBox bbox1 = get_extents(*this); + BoundingBox bbox2 = get_extents(polyline); + bbox2.inflated(1); + if (!bbox1.overlap(bbox2)) + return false; + return diff_pl(polyline, *this).empty(); } diff --git a/src/libslic3r/Exception.hpp b/src/libslic3r/Exception.hpp index 1b8ad50a77..e796e3cc19 100644 --- a/src/libslic3r/Exception.hpp +++ b/src/libslic3r/Exception.hpp @@ -24,7 +24,17 @@ SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError); SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException); SLIC3R_DERIVE_EXCEPTION(PlaceholderParserError, RuntimeError); // Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications. -SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception); +//SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception); +class SlicingError : public Exception +{ +public: + using Exception::Exception; + SlicingError(std::string const &msg, size_t objectId) : Exception(msg), objectId_(objectId) {} + size_t objectId() const { return objectId_; } + +private: + size_t objectId_ = 0; +}; #undef SLIC3R_DERIVE_EXCEPTION } // namespace Slic3r diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index e08cd5ce0b..2de0dd0444 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -147,6 +147,7 @@ public: // Height of the extrusion, used for visualization purposes. float height; + ExtrusionPath() : mm3_per_mm(-1), width(-1), height(-1), m_role(erNone), m_no_extrusion(false) {} ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role), m_no_extrusion(false) {} ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height, bool no_extrusion = false) : mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role), m_no_extrusion(no_extrusion) {} ExtrusionPath(int overhang_degree, int curve_degree, ExtrusionRole role, double mm3_per_mm, float width, float height) : overhang_degree(overhang_degree), curve_degree(curve_degree), mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {} @@ -235,6 +236,8 @@ public: void simplify_by_fitting_arc(double tolerance); //BBS: bool is_force_no_extrusion() const { return m_no_extrusion; } + void set_force_no_extrusion(bool no_extrusion) { m_no_extrusion = no_extrusion; } + void set_extrusion_role(ExtrusionRole extrusion_role) { m_role = extrusion_role; } private: void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; @@ -251,7 +254,7 @@ class ExtrusionMultiPath : public ExtrusionEntity { public: ExtrusionPaths paths; - + ExtrusionMultiPath() {} ExtrusionMultiPath(const ExtrusionMultiPath &rhs) : paths(rhs.paths) {} ExtrusionMultiPath(ExtrusionMultiPath &&rhs) : paths(std::move(rhs.paths)) {} @@ -288,7 +291,7 @@ public: double min_mm3_per_mm() const override; Polyline as_polyline() const override; void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } - void collect_points(Points &dst) const override { + void collect_points(Points &dst) const override { size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); }); dst.reserve(dst.size() + n); for (const ExtrusionPath &p : this->paths) @@ -302,11 +305,11 @@ class ExtrusionLoop : public ExtrusionEntity { public: ExtrusionPaths paths; - + ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {} ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) : paths(paths), m_loop_role(role) {} ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role) {} - ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) + ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) { this->paths.push_back(path); } ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) { this->paths.emplace_back(std::move(path)); } @@ -339,6 +342,7 @@ public: bool has_overhang_point(const Point &point) const; ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionLoopRole loop_role() const { return m_loop_role; } + void set_loop_role(ExtrusionLoopRole role) { m_loop_role = role; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override; @@ -354,7 +358,7 @@ public: double min_mm3_per_mm() const override; Polyline as_polyline() const override { return this->polygon().split_at_first_point(); } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } - void collect_points(Points &dst) const override { + void collect_points(Points &dst) const override { size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); }); dst.reserve(dst.size() + n); for (const ExtrusionPath &p : this->paths) diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index d9be54a6da..c2a87e785f 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -46,6 +46,8 @@ struct SurfaceFillParams // 1000mm is roughly the maximum length line that fits into a 32bit coord_t. float anchor_length = 1000.f; float anchor_length_max = 1000.f; + //BBS + bool with_loop = false; // width, height of extrusion, nozzle diameter, is bridge // For the output, for fill generator. @@ -77,6 +79,7 @@ struct SurfaceFillParams // RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust); RETURN_COMPARE_NON_EQUAL(anchor_length); RETURN_COMPARE_NON_EQUAL(anchor_length_max); + RETURN_COMPARE_NON_EQUAL(with_loop); RETURN_COMPARE_NON_EQUAL(flow.width()); RETURN_COMPARE_NON_EQUAL(flow.height()); RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter()); @@ -97,6 +100,7 @@ struct SurfaceFillParams // this->dont_adjust == rhs.dont_adjust && this->anchor_length == rhs.anchor_length && this->anchor_length_max == rhs.anchor_length_max && + this->with_loop == rhs.with_loop && this->flow == rhs.flow && this->extrusion_role == rhs.extrusion_role; } @@ -147,6 +151,8 @@ std::vector group_fills(const Layer &layer) params.extruder = layerm.region().extruder(extrusion_role); params.pattern = region_config.sparse_infill_pattern.value; params.density = float(region_config.sparse_infill_density); + //BBS + params.with_loop = surface.surface_type == stInternalWithLoop; if (surface.is_solid()) { params.density = 100.f; @@ -363,8 +369,8 @@ std::vector group_fills(const Layer &layer) surface_fills.back().region_id = surface_fills[i].region_id; surface_fills.back().surface.surface_type = stInternalSolid; surface_fills.back().surface.thickness = surface_fills[i].surface.thickness; - surface_fills.back().region_id_group = surface_fills[i].region_id_group; - surface_fills.back().no_overlap_expolygons = surface_fills[i].no_overlap_expolygons; + surface_fills.back().region_id_group = surface_fills[i].region_id_group; + surface_fills.back().no_overlap_expolygons = surface_fills[i].no_overlap_expolygons; for (size_t j = 0; j < narrow_expolygons_index.size(); j++) { // BBS: move the narrow expolygons to new surface_fills.back(); surface_fills.back().expolygons.emplace_back(std::move(surface_fills[i].expolygons[narrow_expolygons_index[j]])); @@ -478,11 +484,12 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.extrusion_role = surface_fill.params.extrusion_role; params.using_internal_flow = using_internal_flow; params.no_extrusion_overlap = surface_fill.params.overlap; + params.with_loop = surface_fill.params.with_loop; LayerRegion* layerm = this->m_regions[surface_fill.region_id]; params.config = &layerm->region().config(); for (ExPolygon& expoly : surface_fill.expolygons) { - f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}); + f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}); // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. f->spacing = surface_fill.params.spacing; surface_fill.surface.expolygon = std::move(expoly); diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index ae4811ca87..6060090641 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -29,7 +29,7 @@ namespace Slic3r { //BBS: 0% of sparse_infill_line_width, no anchor at the start of sparse infill -float Fill::infill_anchor = 0; +float Fill::infill_anchor = 400; //BBS: 20mm float Fill::infill_anchor_max = 20; @@ -54,9 +54,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipAdaptiveCubic: return new FillAdaptive::Filler(); case ipSupportCubic: return new FillAdaptive::Filler(); case ipSupportBase: return new FillSupportBase(); -#if HAS_LIGHTNING_INFILL case ipLightning: return new FillLightning::Filler(); -#endif // HAS_LIGHTNING_INFILL // BBS: for internal solid infill only case ipConcentricInternal: return new FillConcentricInternal(); // BBS: for bottom and top surface only @@ -122,13 +120,57 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para { Polylines polylines; ThickPolylines thick_polylines; - try { - if (params.use_arachne) - thick_polylines = this->fill_surface_arachne(surface, params); - else - polylines = this->fill_surface(surface, params); + if (!params.with_loop) { + try { + if (params.use_arachne) + thick_polylines = this->fill_surface_arachne(surface, params); + else + polylines = this->fill_surface(surface, params); + } + catch (InfillFailedException&) {} + } + //BBS: add handling for infill pattern with loop + else { + Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing))); + Polylines loop_polylines = to_polylines(expp); + { + //BBS: clip the loop + size_t j = 0; + for (size_t i = 0; i < loop_polylines.size(); ++i) { + loop_polylines[i].clip_end(this->loop_clipping); + if (loop_polylines[i].is_valid()) { + if (j < i) + loop_polylines[j] = std::move(loop_polylines[i]); + ++j; + } + } + if (j < loop_polylines.size()) + loop_polylines.erase(loop_polylines.begin() + int(j), loop_polylines.end()); + } + + if (!loop_polylines.empty()) { + if (params.use_arachne) + append(thick_polylines, to_thick_polylines(std::move(loop_polylines), scaled(this->spacing))); + else + append(polylines, std::move(loop_polylines)); + expp = offset_ex(expp, float(scale_(0 - 0.5 * this->spacing))); + } else { + //BBS: the area is too narrow to place a loop, return to original expolygon + expp = { surface->expolygon }; + } + + Surface temp_surface = *surface; + for (ExPolygon& ex : expp) { + temp_surface.expolygon = ex; + try { + if (params.use_arachne) + append(thick_polylines, std::move(this->fill_surface_arachne(&temp_surface, params))); + else + append(polylines, std::move(this->fill_surface(&temp_surface, params))); + } + catch (InfillFailedException&) {} + } } - catch (InfillFailedException&) {} if (!polylines.empty() || !thick_polylines.empty()) { // calculate actual flow from spacing (which might have been adjusted by the infill diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index cffeab04dd..d9fd90775a 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -67,6 +67,8 @@ struct FillParams bool use_arachne{ false }; // Layer height for Concentric infill with Arachne. coordf_t layer_height { 0.f }; + //BBS + bool with_loop { false }; // BBS Flow flow; diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 3bcfc23b46..8595b1ec31 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -5,6 +5,7 @@ #include "Arachne/WallToolPaths.hpp" #include "FillConcentric.hpp" +#include namespace Slic3r { @@ -133,6 +134,8 @@ void FillConcentric::_fill_surface_single(const FillParams& params, } if (j < thick_polylines_out.size()) thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end()); + + reorder_by_shortest_traverse(thick_polylines_out); } else { Polylines polylines; diff --git a/src/libslic3r/Fill/FillConcentricInternal.cpp b/src/libslic3r/Fill/FillConcentricInternal.cpp index 8b3e90930f..d565992ea1 100644 --- a/src/libslic3r/Fill/FillConcentricInternal.cpp +++ b/src/libslic3r/Fill/FillConcentricInternal.cpp @@ -5,6 +5,7 @@ #include "Arachne/WallToolPaths.hpp" #include "FillConcentricInternal.hpp" +#include namespace Slic3r { @@ -22,7 +23,7 @@ void FillConcentricInternal::fill_surface_extrusion(const Surface* surface, cons coord_t min_spacing = params.flow.scaled_spacing(); coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1; - Polygons polygons = offset(expolygon, 0); + Polygons polygons = to_polygons(expolygon); double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end()); Arachne::WallToolPathsParams input_params; @@ -76,6 +77,8 @@ void FillConcentricInternal::fill_surface_extrusion(const Surface* surface, cons } if (j < thick_polylines_out.size()) thick_polylines_out.erase(thick_polylines_out.begin() + int(j), thick_polylines_out.end()); + + reorder_by_shortest_traverse(thick_polylines_out); } ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection(); diff --git a/src/libslic3r/Fill/FillLightning.cpp b/src/libslic3r/Fill/FillLightning.cpp index b50694e95b..dd2189e6b9 100644 --- a/src/libslic3r/Fill/FillLightning.cpp +++ b/src/libslic3r/Fill/FillLightning.cpp @@ -26,9 +26,9 @@ void GeneratorDeleter::operator()(Generator *p) { delete p; } -GeneratorPtr build_generator(const PrintObject &print_object) +GeneratorPtr build_generator(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { - return GeneratorPtr(new Generator(print_object)); + return GeneratorPtr(new Generator(print_object, throw_on_cancel_callback)); } } // namespace Slic3r::FillAdaptive diff --git a/src/libslic3r/Fill/FillLightning.hpp b/src/libslic3r/Fill/FillLightning.hpp index 9c36e01577..6e672783a1 100644 --- a/src/libslic3r/Fill/FillLightning.hpp +++ b/src/libslic3r/Fill/FillLightning.hpp @@ -3,13 +3,6 @@ #include "FillBase.hpp" -/* -* A few modifications based on dba1179(2022.06.10) from Prusa, mainly in Generator.hpp and .cpp: -* 1. delete the second parameter(a throw back function) of Generator(), since I didnt find corresponding throw back function in BBS code -* 2. those codes that call the functions above -* 3. add codes of generating lightning in TreeSupport.cpp -*/ - namespace Slic3r { class PrintObject; @@ -21,7 +14,7 @@ class Generator; struct GeneratorDeleter { void operator()(Generator *p); }; using GeneratorPtr = std::unique_ptr; -GeneratorPtr build_generator(const PrintObject &print_object); +GeneratorPtr build_generator(const PrintObject &print_object, const std::function &throw_on_cancel_callback); class Filler : public Slic3r::Fill { diff --git a/src/libslic3r/Fill/Lightning/DistanceField.cpp b/src/libslic3r/Fill/Lightning/DistanceField.cpp index 7c7eae448f..65da94b839 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.cpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.cpp @@ -43,7 +43,8 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl m_supporting_radius2 = Slic3r::sqr(int64_t(radius)); // Sample source polygons with a regular grid sampling pattern. const BoundingBox overhang_bbox = get_extents(current_overhang); - for (const ExPolygon &expoly : union_ex(current_overhang)) { + ExPolygons expolys = offset2_ex(union_ex(current_overhang), -m_cell_size / 2, m_cell_size / 2); // remove dangling lines which causes sample_grid_pattern crash (fails the OUTER_LOW assertions) + for (const ExPolygon &expoly : expolys) { const Points sampled_points = sample_grid_pattern(expoly, m_cell_size, overhang_bbox); const size_t unsupported_points_prev_size = m_unsupported_points.size(); m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size()); @@ -94,10 +95,6 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl void DistanceField::update(const Point& to_node, const Point& added_leaf) { - std::ofstream out1("z:/misc/lightning.txt", std::ios::app); - out1 << m_unsupported_points.size() << std::endl; - out1.close(); - Vec2d v = (added_leaf - to_node).cast(); auto l2 = v.squaredNorm(); Vec2d extent = Vec2d(-v.y(), v.x()) * m_supporting_radius / sqrt(l2); diff --git a/src/libslic3r/Fill/Lightning/Generator.cpp b/src/libslic3r/Fill/Lightning/Generator.cpp index 5cdf7f37f4..fb00cbe6e2 100644 --- a/src/libslic3r/Fill/Lightning/Generator.cpp +++ b/src/libslic3r/Fill/Lightning/Generator.cpp @@ -63,7 +63,7 @@ Slic3r::SVG draw_two_overhangs_to_svg(size_t ts_layer, const ExPolygons& overhan namespace Slic3r::FillLightning { -Generator::Generator(const PrintObject &print_object) +Generator::Generator(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { const PrintConfig &print_config = print_object.print()->config(); const PrintObjectConfig &object_config = print_object.config(); @@ -87,11 +87,11 @@ Generator::Generator(const PrintObject &print_object) m_prune_length = coord_t(layer_thickness * std::tan(lightning_infill_prune_angle)); m_straightening_max_distance = coord_t(layer_thickness * std::tan(lightning_infill_straightening_angle)); - generateInitialInternalOverhangs(print_object); - generateTrees(print_object); + generateInitialInternalOverhangs(print_object, throw_on_cancel_callback); + generateTrees(print_object, throw_on_cancel_callback); } -Generator::Generator(PrintObject* m_object, std::vector& contours, std::vector& overhangs, float density) +Generator::Generator(PrintObject* m_object, std::vector& contours, std::vector& overhangs, const std::function &throw_on_cancel_callback, float density) { const PrintConfig &print_config = m_object->print()->config(); const PrintObjectConfig &object_config = m_object->config(); @@ -120,7 +120,7 @@ Generator::Generator(PrintObject* m_object, std::vector& contours, std m_overhang_per_layer = overhangs; - generateTreesforSupport(contours); + generateTreesforSupport(contours, throw_on_cancel_callback); //for (size_t i = 0; i < overhangs.size(); i++) //{ @@ -130,13 +130,14 @@ Generator::Generator(PrintObject* m_object, std::vector& contours, std //} } -void Generator::generateInitialInternalOverhangs(const PrintObject &print_object) +void Generator::generateInitialInternalOverhangs(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { m_overhang_per_layer.resize(print_object.layers().size()); Polygons infill_area_above; //Iterate from top to bottom, to subtract the overhang areas above from the overhang areas on the layer below, to get only overhang in the top layer where it is overhanging. for (int layer_nr = int(print_object.layers().size()) - 1; layer_nr >= 0; --layer_nr) { + throw_on_cancel_callback(); Polygons infill_area_here; for (const LayerRegion* layerm : print_object.get_layer(layer_nr)->regions()) for (const Surface& surface : layerm->fill_surfaces.surfaces) @@ -157,7 +158,7 @@ const Layer& Generator::getTreesForLayer(const size_t& layer_id) const return m_lightning_layers[layer_id]; } -void Generator::generateTrees(const PrintObject &print_object) +void Generator::generateTrees(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { m_lightning_layers.resize(print_object.layers().size()); bboxs.resize(print_object.layers().size()); @@ -165,6 +166,7 @@ void Generator::generateTrees(const PrintObject &print_object) // For-each layer from top to bottom: for (int layer_id = int(print_object.layers().size()) - 1; layer_id >= 0; layer_id--) { + throw_on_cancel_callback(); for (const LayerRegion *layerm : print_object.get_layer(layer_id)->regions()) for (const Surface &surface : layerm->fill_surfaces.surfaces) if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) @@ -178,6 +180,7 @@ void Generator::generateTrees(const PrintObject &print_object) // For-each layer from top to bottom: for (int layer_id = int(top_layer_id); layer_id >= 0; layer_id--) { + throw_on_cancel_callback(); Layer ¤t_lightning_layer = m_lightning_layers[layer_id]; const Polygons ¤t_outlines = infill_outlines[layer_id]; const BoundingBox ¤t_outlines_bbox = get_extents(current_outlines); @@ -187,7 +190,7 @@ void Generator::generateTrees(const PrintObject &print_object) // register all trees propagated from the previous layer as to-be-reconnected std::vector to_be_reconnected_tree_roots = current_lightning_layer.tree_roots; - current_lightning_layer.generateNewTrees(m_overhang_per_layer[layer_id], current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius); + current_lightning_layer.generateNewTrees(m_overhang_per_layer[layer_id], current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius, throw_on_cancel_callback); current_lightning_layer.reconnectRoots(to_be_reconnected_tree_roots, current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius); // Initialize trees for next lower layer from the current one. @@ -211,8 +214,10 @@ void Generator::generateTrees(const PrintObject &print_object) } } -void Generator::generateTreesforSupport(std::vector& contours) +void Generator::generateTreesforSupport(std::vector& contours, const std::function &throw_on_cancel_callback) { + if (contours.empty()) return; + m_lightning_layers.resize(contours.size()); bboxs.resize(contours.size()); @@ -223,6 +228,7 @@ void Generator::generateTreesforSupport(std::vector& contours) // For-each layer from top to bottom: for (int layer_id = int(top_layer_id); layer_id >= 0; layer_id--) { + throw_on_cancel_callback(); Layer& current_lightning_layer = m_lightning_layers[layer_id]; const Polygons& current_outlines = contours[layer_id]; const BoundingBox& current_outlines_bbox = get_extents(current_outlines); @@ -232,7 +238,7 @@ void Generator::generateTreesforSupport(std::vector& contours) // register all trees propagated from the previous layer as to-be-reconnected std::vector to_be_reconnected_tree_roots = current_lightning_layer.tree_roots; - current_lightning_layer.generateNewTrees(m_overhang_per_layer[layer_id], current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius); + current_lightning_layer.generateNewTrees(m_overhang_per_layer[layer_id], current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius, throw_on_cancel_callback); current_lightning_layer.reconnectRoots(to_be_reconnected_tree_roots, current_outlines, current_outlines_bbox, outlines_locator, m_supporting_radius, m_wall_supporting_radius); // Initialize trees for next lower layer from the current one. diff --git a/src/libslic3r/Fill/Lightning/Generator.hpp b/src/libslic3r/Fill/Lightning/Generator.hpp index 0b25fd513c..79110fb8dd 100644 --- a/src/libslic3r/Fill/Lightning/Generator.hpp +++ b/src/libslic3r/Fill/Lightning/Generator.hpp @@ -44,7 +44,7 @@ public: * Lightning Infill for the infill areas in that mesh. The infill areas must * already be calculated at this point. */ - explicit Generator(const PrintObject &print_object); + explicit Generator(const PrintObject &print_object, const std::function &throw_on_cancel_callback); /*! * Get a tree of paths generated for a certain layer of the mesh. @@ -61,7 +61,7 @@ public: float infilll_extrusion_width() const { return m_infill_extrusion_width; } - Generator(PrintObject* m_object, std::vector& contours, std::vector& overhangs, float density = 0.15); + Generator(PrintObject* m_object, std::vector& contours, std::vector& overhangs, const std::function &throw_on_cancel_callback, float density = 0.15); protected: /*! @@ -72,13 +72,13 @@ protected: * only when support is generated. For this pattern, we also need to * generate overhang areas for the inside of the model. */ - void generateInitialInternalOverhangs(const PrintObject &print_object); + void generateInitialInternalOverhangs(const PrintObject &print_object, const std::function &throw_on_cancel_callback); /*! * Calculate the tree structure of all layers. */ - void generateTrees(const PrintObject &print_object); - void generateTreesforSupport(std::vector& contours); + void generateTrees(const PrintObject &print_object, const std::function &throw_on_cancel_callback); + void generateTreesforSupport(std::vector& contours, const std::function &throw_on_cancel_callback); float m_infill_extrusion_width; diff --git a/src/libslic3r/Fill/Lightning/Layer.cpp b/src/libslic3r/Fill/Lightning/Layer.cpp index 5aa217d8f2..354623e519 100644 --- a/src/libslic3r/Fill/Lightning/Layer.cpp +++ b/src/libslic3r/Fill/Lightning/Layer.cpp @@ -48,10 +48,12 @@ void Layer::generateNewTrees const BoundingBox& current_outlines_bbox, const EdgeGrid::Grid& outlines_locator, const coord_t supporting_radius, - const coord_t wall_supporting_radius + const coord_t wall_supporting_radius, + const std::function &throw_on_cancel_callback ) { DistanceField distance_field(supporting_radius, current_outlines, current_outlines_bbox, current_overhang); + throw_on_cancel_callback(); SparseNodeGrid tree_node_locator; fillLocator(tree_node_locator, current_outlines_bbox); @@ -61,6 +63,7 @@ void Layer::generateNewTrees size_t unsupported_cell_idx = 0; Point unsupported_location; while (distance_field.tryGetNextPoint(&unsupported_location, &unsupported_cell_idx, unsupported_cell_idx)) { + throw_on_cancel_callback(); GroundingLocation grounding_loc = getBestGroundingLocation( unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator); diff --git a/src/libslic3r/Fill/Lightning/Layer.hpp b/src/libslic3r/Fill/Lightning/Layer.hpp index c0b91ad1f8..e8c0a38b4d 100644 --- a/src/libslic3r/Fill/Lightning/Layer.hpp +++ b/src/libslic3r/Fill/Lightning/Layer.hpp @@ -44,7 +44,8 @@ public: const BoundingBox& current_outlines_bbox, const EdgeGrid::Grid& outline_locator, coord_t supporting_radius, - coord_t wall_supporting_radius + coord_t wall_supporting_radius, + const std::function &throw_on_cancel_callback ); /*! Determine & connect to connection point in tree/outline. diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 4fd3096549..b96988fb91 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -661,7 +661,7 @@ ModelVolumeType type_from_string(const std::string &s) : m_version(0) , m_check_version(false) , m_xml_parser(nullptr) - , m_model(nullptr) + , m_model(nullptr) , m_unit_factor(1.0f) , m_curr_metadata_name("") , m_curr_characters("") @@ -934,6 +934,18 @@ ModelVolumeType type_from_string(const std::string &s) ++object_idx; } + //BBS: copy object isteadof instance + int object_size = model.objects.size(); + for (int obj_index = 0; obj_index < object_size; obj_index ++) { + ModelObject* object = model.objects[obj_index]; + while (object->instances.size() > 1) { + ModelObject* new_model_object = model.add_object(*object); + new_model_object->clear_instances(); + new_model_object->add_instance(*object->instances.back()); + object->delete_last_instance(); + } + } + // // fixes the min z of the model if negative // model.adjust_min_z(); @@ -1005,8 +1017,8 @@ ModelVolumeType type_from_string(const std::string &s) } void _3MF_Importer::_extract_print_config_from_archive( - mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, - DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, + mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, + DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, const std::string& archive_filename) { if (stat.m_uncomp_size > 0) { @@ -1227,7 +1239,7 @@ ModelVolumeType type_from_string(const std::string &s) } } } - + void _3MF_Importer::_extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) { if (stat.m_uncomp_size > 0) { @@ -1237,13 +1249,13 @@ ModelVolumeType type_from_string(const std::string &s) add_error("Error while reading sla support points data to buffer"); return; } - + if (buffer.back() == '\n') buffer.pop_back(); - + std::vector objects; boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off); - + // Info on format versioning - see 3mf.hpp int version = 0; std::string key("drain_holes_format_version="); @@ -1252,38 +1264,38 @@ ModelVolumeType type_from_string(const std::string &s) version = std::stoi(objects[0]); objects.erase(objects.begin()); // pop the header } - + for (const std::string& object : objects) { std::vector object_data; boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off); - + if (object_data.size() != 2) { add_error("Error while reading object data"); continue; } - + std::vector object_data_id; boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off); if (object_data_id.size() != 2) { add_error("Error while reading object id"); continue; } - + int object_id = std::atoi(object_data_id[1].c_str()); if (object_id == 0) { add_error("Found invalid object id"); continue; } - + IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id); if (object_item != m_sla_drain_holes.end()) { add_error("Found duplicated SLA drain holes"); continue; } - + std::vector object_data_points; boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off); - + sla::DrainHoles sla_drain_holes; if (version == 1) { @@ -1306,7 +1318,7 @@ ModelVolumeType type_from_string(const std::string &s) hole.pos += hole.normal.normalized(); hole.height -= 1.f; } - + if (!sla_drain_holes.empty()) m_sla_drain_holes.insert({ object_id, sla_drain_holes }); } @@ -1394,11 +1406,11 @@ ModelVolumeType type_from_string(const std::string &s) pt::ptree attr_tree = tree.find("")->second; if (attr_tree.find("type") == attr_tree.not_found()) { // It means that data was saved in old version (2.2.0 and older) of PrusaSlicer - // read old data ... + // read old data ... std::string gcode = tree.get (".gcode"); // ... and interpret them to the new data - type = gcode == "M600" ? CustomGCode::ColorChange : - gcode == "M601" ? CustomGCode::PausePrint : + type = gcode == "M600" ? CustomGCode::ColorChange : + gcode == "M601" ? CustomGCode::PausePrint : gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom; extra = type == CustomGCode::PausePrint ? color : type == CustomGCode::Custom ? gcode : ""; @@ -2113,7 +2125,7 @@ ModelVolumeType type_from_string(const std::string &s) tri_id -= min_id; } - if (m_prusaslicer_generator_version && + if (m_prusaslicer_generator_version && *m_prusaslicer_generator_version >= *Semver::parse("2.4.0-alpha1") && *m_prusaslicer_generator_version < *Semver::parse("2.4.0-alpha3")) // PrusaSlicer 2.4.0-alpha2 contained a bug, where all vertices of a single object were saved for each volume the object contained. @@ -2227,7 +2239,7 @@ ModelVolumeType type_from_string(const std::string &s) if (importer != nullptr) importer->_handle_start_config_xml_element(name, attributes); } - + void XMLCALL _3MF_Importer::_handle_end_config_xml_element(void* userData, const char* name) { _3MF_Importer* importer = (_3MF_Importer*)userData; @@ -2340,7 +2352,7 @@ ModelVolumeType type_from_string(const std::string &s) } } - // Adds relationships file ("_rels/.rels"). + // Adds relationships file ("_rels/.rels"). // The content of this file is the same for each PrusaSlicer 3mf. // The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA. if (!_add_relationships_file_to_archive(archive)) { @@ -2384,13 +2396,13 @@ ModelVolumeType type_from_string(const std::string &s) boost::filesystem::remove(filename); return false; } - + if (!_add_sla_drain_holes_file_to_archive(archive, model)) { close_zip_writer(&archive); boost::filesystem::remove(filename); return false; } - + // Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"). // All custom gcode per height of whole Model are stored here @@ -2502,11 +2514,11 @@ ModelVolumeType type_from_string(const std::string &s) bool _3MF_Exporter::_add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, IdToObjectDataMap& objects_data) { mz_zip_writer_staged_context context; - if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(), - m_zip64 ? + if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(), + m_zip64 ? // Maximum expected and allowed 3MF file size is 16GiB. // This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records. - (uint64_t(1) << 30) * 16 : + (uint64_t(1) << 30) * 16 : // Maximum expected 3MF file size is 4GB-1. This is a workaround for interoperability with Windows 10 3D model fixing API, see // GH issue #6193. (uint64_t(1) << 32) - 1, @@ -2589,7 +2601,7 @@ ModelVolumeType type_from_string(const std::string &s) } stream << "\n"; - + std::string buf = stream.str(); if ((! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) || @@ -2877,7 +2889,7 @@ ModelVolumeType type_from_string(const std::string &s) sprintf(buffer, (i == 0) ? "%f" : ";%f", layer_height_profile[i]); out += buffer; } - + out += "\n"; } } @@ -2936,8 +2948,8 @@ ModelVolumeType type_from_string(const std::string &s) boost::replace_all(out, ">\n ", ">\n "); boost::replace_all(out, ">", ">\n "); - // OR just - boost::replace_all(out, "><", ">\n<"); + // OR just + boost::replace_all(out, "><", ">\n<"); } if (!out.empty()) { @@ -2984,13 +2996,13 @@ ModelVolumeType type_from_string(const std::string &s) } return true; } - + bool _3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model) { assert(is_decimal_separator_point()); const char *const fmt = "object_id=%d|"; std::string out; - + unsigned int count = 0; for (const ModelObject* object : model.objects) { ++count; @@ -3007,7 +3019,7 @@ ModelVolumeType type_from_string(const std::string &s) if (!drain_holes.empty()) { out += string_printf(fmt, count); - + // Store the layer height profile as a single space separated list. for (size_t i = 0; i < drain_holes.size(); ++i) out += string_printf((i == 0 ? "%f %f %f %f %f %f %f %f" : " %f %f %f %f %f %f %f %f"), @@ -3019,15 +3031,15 @@ ModelVolumeType type_from_string(const std::string &s) drain_holes[i].normal(2), drain_holes[i].radius, drain_holes[i].height); - + out += "\n"; } } - + if (!out.empty()) { // Adds version header at the beginning: out = std::string("drain_holes_format_version=") + std::to_string(drain_holes_format_version) + std::string("\n") + out; - + if (!mz_zip_writer_add_mem(&archive, SLA_DRAIN_HOLES_FILE.c_str(), static_cast(out.data()), out.length(), mz_uint(MZ_DEFAULT_COMPRESSION))) { add_error("Unable to add sla support points file to archive"); return false; @@ -3099,7 +3111,7 @@ ModelVolumeType type_from_string(const std::string &s) if (volume->is_modifier()) stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n"; // stores volume's type (overrides the modifier field above) - stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " << + stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " << VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n"; // stores volume's local matrix @@ -3137,7 +3149,7 @@ ModelVolumeType type_from_string(const std::string &s) for (const std::string& key : volume->config.keys()) { stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n"; } - + // stores mesh's statistics const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; stream << " <" << MESH_TAG << " "; @@ -3190,12 +3202,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv std::string gcode = //code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") : code.type == CustomGCode::PausePrint ? config->opt_string("machine_pause_gcode") : code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") : - code.type == CustomGCode::ToolChange ? "tool_change" : code.extra; + code.type == CustomGCode::ToolChange ? "tool_change" : code.extra; code_tree.put(".gcode" , gcode ); } pt::ptree& mode_tree = main_tree.add("mode", ""); - // store mode of a custom_gcode_per_print_z + // store mode of a custom_gcode_per_print_z mode_tree.put(".value", model.custom_gcode_per_print_z.mode == CustomGCode::Mode::SingleExtruder ? CustomGCode::SingleExtruderMode : model.custom_gcode_per_print_z.mode == CustomGCode::Mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode : CustomGCode::MultiExtruderMode); @@ -3208,7 +3220,7 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv // Post processing("beautification") of the output string boost::replace_all(out, "><", ">\n<"); } - } + } if (!out.empty()) { if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 3a7d35b72d..61f854e491 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -116,6 +116,9 @@ const std::string BBL_DESCRIPTION_TAG = "Description"; const std::string BBL_COPYRIGHT_TAG = "CopyRight"; const std::string BBL_LICENSE_TAG = "License"; const std::string BBL_REGION_TAG = "Region"; +const std::string BBL_MODIFICATION_TAG = "ModificationDate"; +const std::string BBL_CREATION_DATE_TAG = "CreationDate"; +const std::string BBL_APPLICATION_TAG = "Application"; const std::string MODEL_FOLDER = "3D/"; const std::string MODEL_EXTENSION = ".model"; @@ -142,8 +145,8 @@ const std::string BBS_PROJECT_CONFIG_FILE = "Metadata/project_settings.config"; const std::string BBS_MODEL_CONFIG_FILE = "Metadata/model_settings.config"; const std::string BBS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.config.rels"; const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config"; -/*const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt"; -const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; +const std::string BBS_LAYER_HEIGHTS_PROFILE_FILE = "Metadata/layer_heights_profile.txt"; +/*const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml"; const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt"; const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";*/ const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/custom_gcode_per_layer.xml"; @@ -227,7 +230,7 @@ static constexpr const char* CUSTOM_SUPPORTS_ATTR = "paint_supports"; static constexpr const char* CUSTOM_SEAM_ATTR = "paint_seam"; static constexpr const char* MMU_SEGMENTATION_ATTR = "paint_color"; // BBS -static constexpr const char* FACE_PROPERTY_ATTR = "bbs:face_property"; +static constexpr const char* FACE_PROPERTY_ATTR = "face_property"; static constexpr const char* KEY_ATTR = "key"; static constexpr const char* VALUE_ATTR = "value"; @@ -235,17 +238,21 @@ static constexpr const char* FIRST_TRIANGLE_ID_ATTR = "firstid"; static constexpr const char* LAST_TRIANGLE_ID_ATTR = "lastid"; static constexpr const char* SUBTYPE_ATTR = "subtype"; static constexpr const char* LOCK_ATTR = "locked"; +static constexpr const char* BED_TYPE_ATTR = "bed_type"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; static constexpr const char* PATTERN_FILE_ATTR = "pattern_file"; static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file"; static constexpr const char* OBJECT_ID_ATTR = "object_id"; static constexpr const char* INSTANCEID_ATTR = "instance_id"; +static constexpr const char* ARRANGE_ORDER_ATTR = "arrange_order"; static constexpr const char* PLATERID_ATTR = "plater_id"; static constexpr const char* PLATE_IDX_ATTR = "index"; static constexpr const char* SLICE_PREDICTION_ATTR = "prediction"; static constexpr const char* SLICE_WEIGHT_ATTR = "weight"; static constexpr const char* OUTSIDE_ATTR = "outside"; +static constexpr const char* SUPPORT_USED_ATTR = "support_used"; + static constexpr const char* OBJECT_TYPE = "object"; static constexpr const char* VOLUME_TYPE = "volume"; @@ -598,6 +605,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { int object_id; int instance_id; + int arrange_order; }; struct Instance @@ -670,11 +678,152 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) typedef std::vector InstancesList; typedef std::map IdToMetadataMap; //typedef std::map IdToGeometryMap; - /*typedef std::map> IdToLayerHeightsProfileMap; - typedef std::map IdToLayerConfigRangesMap; + typedef std::map> IdToLayerHeightsProfileMap; + /*typedef std::map IdToLayerConfigRangesMap; typedef std::map> IdToSlaSupportPointsMap; typedef std::map> IdToSlaDrainHolesMap;*/ + struct ObjectImporter + { + IdToCurrentObjectMap object_list; + CurrentObject *current_object{nullptr}; + std::string object_path; + std::string zip_path; + _BBS_3MF_Importer *top_importer{nullptr}; + XML_Parser object_xml_parser; + bool obj_parse_error { false }; + std::string obj_parse_error_message; + + //local parsed datas + std::string obj_curr_metadata_name; + std::string obj_curr_characters; + float object_unit_factor; + int object_current_color_group{-1}; + std::map object_group_id_to_color; + bool is_bbl_3mf { false }; + + ObjectImporter(_BBS_3MF_Importer *importer, std::string file_path, std::string obj_path) + { + top_importer = importer; + object_path = obj_path; + zip_path = file_path; + } + + ~ObjectImporter() + { + _destroy_object_xml_parser(); + } + + void _destroy_object_xml_parser() + { + if (object_xml_parser != nullptr) { + XML_ParserFree(object_xml_parser); + object_xml_parser = nullptr; + } + } + + void _stop_object_xml_parser(const std::string& msg = std::string()) + { + assert(! obj_parse_error); + assert(obj_parse_error_message.empty()); + assert(object_xml_parser != nullptr); + obj_parse_error = true; + obj_parse_error_message = msg; + XML_StopParser(object_xml_parser, false); + } + + bool object_parse_error() const { return obj_parse_error; } + const char* object_parse_error_message() const { + return obj_parse_error ? + // The error was signalled by the user code, not the expat parser. + (obj_parse_error_message.empty() ? "Invalid 3MF format" : obj_parse_error_message.c_str()) : + // The error was signalled by the expat parser. + XML_ErrorString(XML_GetErrorCode(object_xml_parser)); + } + + bool _extract_object_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat); + + bool extract_object_model() + { + mz_zip_archive archive; + mz_zip_archive_file_stat stat; + mz_zip_zero_struct(&archive); + + if (!open_zip_reader(&archive, zip_path)) { + top_importer->add_error("Unable to open the zipfile "+ zip_path); + return false; + } + + if (!top_importer->_extract_from_archive(archive, object_path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) { + return _extract_object_from_archive(archive, stat); + }, top_importer->m_load_restore)) { + std::string error_msg = std::string("Archive does not contain a valid model for ") + object_path; + top_importer->add_error(error_msg); + + close_zip_reader(&archive); + return false; + } + + close_zip_reader(&archive); + + if (obj_parse_error) { + //already add_error inside + //top_importer->add_error(object_parse_error_message()); + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Found error while extrace object %1%\n")%object_path; + return false; + } + return true; + } + + bool _handle_object_start_model(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_model(); + + bool _handle_object_start_resources(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_resources(); + + bool _handle_object_start_object(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_object(); + + bool _handle_object_start_color_group(const char **attributes, unsigned int num_attributes); + bool _handle_object_end_color_group(); + + bool _handle_object_start_color(const char **attributes, unsigned int num_attributes); + bool _handle_object_end_color(); + + bool _handle_object_start_mesh(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_mesh(); + + bool _handle_object_start_vertices(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_vertices(); + + bool _handle_object_start_vertex(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_vertex(); + + bool _handle_object_start_triangles(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_triangles(); + + bool _handle_object_start_triangle(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_triangle(); + + bool _handle_object_start_components(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_components(); + + bool _handle_object_start_component(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_component(); + + bool _handle_object_start_metadata(const char** attributes, unsigned int num_attributes); + bool _handle_object_end_metadata(); + + void _handle_object_start_model_xml_element(const char* name, const char** attributes); + void _handle_object_end_model_xml_element(const char* name); + void _handle_object_xml_characters(const XML_Char* s, int len); + + // callbacks to parse the .model file of an object + static void XMLCALL _handle_object_start_model_xml_element(void* userData, const char* name, const char** attributes); + static void XMLCALL _handle_object_end_model_xml_element(void* userData, const char* name); + static void XMLCALL _handle_object_xml_characters(void* userData, const XML_Char* s, int len); + }; + // Version of the 3mf file unsigned int m_version; bool m_check_version; @@ -714,8 +863,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //IdToGeometryMap m_orig_geometries; // backup & restore CurrentConfig m_curr_config; IdToMetadataMap m_objects_metadata; - /*IdToLayerHeightsProfileMap m_layer_heights_profiles; - IdToLayerConfigRangesMap m_layer_config_ranges; + IdToLayerHeightsProfileMap m_layer_heights_profiles; + /*IdToLayerConfigRangesMap m_layer_config_ranges; IdToSlaSupportPointsMap m_sla_support_points; IdToSlaDrainHolesMap m_sla_drain_holes;*/ std::string m_curr_metadata_name; @@ -726,6 +875,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string m_start_part_path; std::string m_thumbnail_path; std::vector m_sub_model_paths; + std::vector m_object_importers; std::map m_shared_meshes; @@ -745,7 +895,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: add plate data related logic // add backup & restore logic - bool load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn = nullptr, BBLProject *project = nullptr); + bool load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector& project_presets, DynamicPrintConfig& config, + ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn = nullptr, BBLProject *project = nullptr, int plate_id = 0); bool get_thumbnail(const std::string &filename, std::string &data); unsigned int version() const { return m_version; } @@ -765,7 +916,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: add plate data related logic // add backup & restore logic bool _load_model_from_file(std::string filename, Model& model, PlateDataPtrs& plate_data_list, std::vector& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Import3mfProgressFn proFn = nullptr, - BBLProject* project = nullptr); + BBLProject* project = nullptr, int plate_id = 0); bool _extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function, bool restore = false); bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler); @@ -886,7 +1037,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _handle_start_relationship(const char** attributes, unsigned int num_attributes); - void _generate_current_object_list(std::vector &sub_objects, Id object_id, IdToCurrentObjectMap current_objects); + void _generate_current_object_list(std::vector &sub_objects, Id object_id, IdToCurrentObjectMap& current_objects); bool _generate_volumes_new(ModelObject& object, const std::vector &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions); bool _generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions); @@ -941,7 +1092,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //BBS: add plate data related logic // add backup & restore logic - bool _BBS_3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn, BBLProject *project) + bool _BBS_3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PlateDataPtrs& plate_data_list, std::vector& project_presets, DynamicPrintConfig& config, + ConfigSubstitutionContext& config_substitutions, LoadStrategy strategy, bool& is_bbl_3mf, Semver& file_version, Import3mfProgressFn proFn, BBLProject *project, int plate_id) { m_version = 0; m_fdm_supports_painting_version = 0; @@ -964,7 +1116,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_curr_config.object_id = -1; m_curr_config.volume_id = -1; m_objects_metadata.clear(); - //m_layer_heights_profiles.clear(); + m_layer_heights_profiles.clear(); //m_layer_config_ranges.clear(); //m_sla_support_points.clear(); m_curr_metadata_name.clear(); @@ -973,6 +1125,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_plater_data.clear(); m_curr_instance.object_id = -1; m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; clear_errors(); // restore @@ -990,7 +1143,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) else { m_backup_path = model.get_backup_path(); } - bool result = _load_model_from_file(filename, model, plate_data_list, project_presets, config, config_substitutions, proFn, project); + bool result = _load_model_from_file(filename, model, plate_data_list, project_presets, config, config_substitutions, proFn, project, plate_id); is_bbl_3mf = m_is_bbl_3mf; if (m_bambuslicer_generator_version) file_version = *m_bambuslicer_generator_version; @@ -1022,7 +1175,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } lock{&archive}; if (!open_zip_reader(&archive, filename)) { - add_error("Unable to open the file"); + add_error("Unable to open the file"+filename); return false; } @@ -1068,7 +1221,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Import3mfProgressFn proFn, - BBLProject *project) + BBLProject *project, + int plate_id) { bool cb_cancel = false; //BBS progress point @@ -1083,7 +1237,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } //BBS progress point - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_OPEN\n"); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_OPEN, m_load_restore=%1%\n")%m_load_restore; if (proFn) { proFn(IMPORT_STAGE_OPEN, 0, 1, cb_cancel); if (cb_cancel) @@ -1108,7 +1262,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } lock{ &archive }; if (!open_zip_reader(&archive, filename)) { - add_error("Unable to open the file"); + add_error("Unable to open the file"+filename); return false; } @@ -1145,13 +1299,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) _extract_xml_from_archive(archive, sub_rels, _handle_start_relationships_element, _handle_end_relationships_element); int index = 0; +#if 0 for (auto path : m_sub_model_paths) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_READ_FILES\n"); if (proFn) { proFn(IMPORT_STAGE_READ_FILES, ++index, 3 + m_sub_model_paths.size(), cb_cancel); if (cb_cancel) return false; } + else + ++index; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", read %1%th sub model file %2%\n")%index %path; m_sub_model_path = path; if (!_extract_from_archive(archive, path, [this] (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) { return _extract_model_from_archive(archive, stat); @@ -1161,6 +1318,43 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } m_sub_model_path.clear(); } +#else + for (auto path : m_sub_model_paths) { + ObjectImporter *object_importer = new ObjectImporter(this, filename, path); + m_object_importers.push_back(object_importer); + } + + bool object_load_result = true; + boost::mutex mutex; + tbb::parallel_for( + tbb::blocked_range(0, m_object_importers.size()), + [this, &mutex, &object_load_result](const tbb::blocked_range& importer_range) { + for (size_t object_index = importer_range.begin(); object_index < importer_range.end(); ++ object_index) { + bool result = m_object_importers[object_index]->extract_object_model(); + { + boost::unique_lock l(mutex); + object_load_result &= result; + } + } + } + ); + + if (!object_load_result) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", loading sub-objects error\n"); + return false; + } + + //merge these objects into one + for (auto obj_importer : m_object_importers) { + for (const IdToCurrentObjectMap::value_type& obj : obj_importer->object_list) + m_current_objects.insert({ std::move(obj.first), std::move(obj.second)}); + for (auto group_color : obj_importer->object_group_id_to_color) + m_group_id_to_color.insert(std::move(group_color)); + + delete obj_importer; + } + m_object_importers.clear(); +#endif // BBS: load root model if (proFn) { proFn(IMPORT_STAGE_READ_FILES, 2, 3, cb_cancel); @@ -1219,15 +1413,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string name(stat.m_filename); std::replace(name.begin(), name.end(), '\\', '/'); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract file %1%\n")%name; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract %1%th file %2%, total=%3%\n")%(i+1)%name%num_entries; - //BBS: disable adaptive layer height related file in 3MF - /* if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE)) { + if (boost::algorithm::iequals(name, BBS_LAYER_HEIGHTS_PROFILE_FILE)) { // extract slic3r layer heights profile file _extract_layer_heights_profile_config_from_archive(archive, stat); } else - if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) { + /*if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) { // extract slic3r layer config ranges file _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions); }*/ @@ -1305,9 +1498,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) lock.close(); - if (m_version == 0) { + if (!m_is_bbl_3mf) { // if the 3mf was not produced by BambuStudio and there is more than one instance, // split the object in as many objects as instances + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", found 3mf from other vendor, split as instance"); for (const IdToModelObjectMap::value_type& object : m_objects) { if (object.second >= int(m_model->objects.size())) { add_error("3rd 3mf, invalid object, id: "+std::to_string(object.first.second)); @@ -1349,6 +1543,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", process group colors, size %1%\n")%m_group_id_to_color.size(); std::map color_group_id_to_extruder_id_map; std::map color_to_extruder_id_map; int extruder_id = 0; @@ -1363,11 +1558,28 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", begin to assemble objects, size %1%\n")%m_objects.size(); + //only load objects in plate_id + PlateData* current_plate_data = nullptr; + if ((plate_id > 0) && (plate_id <= m_plater_data.size())) { + std::map::iterator it =m_plater_data.find(plate_id); + if (it != m_plater_data.end()) { + current_plate_data = it->second; + } + } for (const IdToModelObjectMap::value_type& object : m_objects) { if (object.second >= int(m_model->objects.size())) { add_error("invalid object, id: "+std::to_string(object.first.second)); return false; } + if (current_plate_data) { + std::map>::iterator it = current_plate_data->obj_inst_map.find(object.first.second); + if (it == current_plate_data->obj_inst_map.end()) { + //not in current plate, skip + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", could not find object %1% in plate %2%, skip it\n")%object.first.second %plate_id; + continue; + } + } ModelObject* model_object = m_model->objects[object.second]; /*IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first); if (obj_geometry == m_geometries.end()) { @@ -1376,12 +1588,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) }*/ // m_layer_heights_profiles are indexed by a 1 based model object index. - /*IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1); + IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1); if (obj_layer_heights_profile != m_layer_heights_profiles.end()) model_object->layer_height_profile.set(std::move(obj_layer_heights_profile->second)); // m_layer_config_ranges are indexed by a 1 based model object index. - IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1); + /*IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1); if (obj_layer_config_ranges != m_layer_config_ranges.end()) model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second); @@ -1435,7 +1647,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) IdToCurrentObjectMap::const_iterator current_object = m_current_objects.find(object.first); if (current_object != m_current_objects.end()) { // get name - model_object->name = current_object->second.name; + if (!current_object->second.name.empty()) + model_object->name = current_object->second.name; + else + model_object->name = "Object_"+std::to_string(object.second+1); // get color auto extruder_itor = color_group_id_to_extruder_id_map.find(current_object->second.pid); @@ -1452,6 +1667,29 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } + // If instances contain a single volume, the volume offset should be 0,0,0 + // This equals to say that instance world position and volume world position should match + // Correct all instances/volumes for which this does not hold + for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) { + ModelObject *o = model.objects[obj_id]; + if (o->volumes.size() == 1) { + ModelVolume * v = o->volumes.front(); + const Slic3r::Geometry::Transformation &first_inst_trafo = o->instances.front()->get_transformation(); + const Vec3d world_vol_offset = (first_inst_trafo * v->get_transformation()).get_offset(); + const Vec3d world_inst_offset = first_inst_trafo.get_offset(); + + if (!world_vol_offset.isApprox(world_inst_offset)) { + const Slic3r::Geometry::Transformation &vol_trafo = v->get_transformation(); + for (int inst_id = 0; inst_id < int(o->instances.size()); ++inst_id) { + ModelInstance * i = o->instances[inst_id]; + const Slic3r::Geometry::Transformation &inst_trafo = i->get_transformation(); + i->set_offset((inst_trafo * vol_trafo).get_offset()); + } + v->set_offset(Vec3d::Zero()); + } + } + } + int object_idx = 0; for (ModelObject* o : model.objects) { int volume_idx = 0; @@ -1500,7 +1738,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // model.adjust_min_z(); //BBS progress point - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_LOADING_PLATES, m_plater_data size %1%\n")%m_plater_data.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("import 3mf IMPORT_STAGE_LOADING_PLATES, m_plater_data size %1%, m_backup_path %2%\n")%m_plater_data.size() %m_backup_path; if (proFn) { proFn(IMPORT_STAGE_LOADING_PLATES, 0, 1, cb_cancel); if (cb_cancel) @@ -1525,17 +1763,73 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } plate_data_list[it->first-1]->locked = it->second->locked; plate_data_list[it->first-1]->plate_index = it->second->plate_index-1; - plate_data_list[it->first-1]->objects_and_instances = it->second->objects_and_instances; + plate_data_list[it->first-1]->obj_inst_map = it->second->obj_inst_map; plate_data_list[it->first-1]->gcode_file = (m_load_restore || it->second->gcode_file.empty()) ? it->second->gcode_file : m_backup_path + "/" + it->second->gcode_file; plate_data_list[it->first-1]->gcode_prediction = it->second->gcode_prediction; plate_data_list[it->first-1]->gcode_weight = it->second->gcode_weight; plate_data_list[it->first-1]->toolpath_outside = it->second->toolpath_outside; + plate_data_list[it->first-1]->is_support_used = it->second->is_support_used; plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info; plate_data_list[it->first-1]->warnings = it->second->warnings; plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file; plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file; plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file; + plate_data_list[it->first-1]->config = it->second->config; + current_plate_data = plate_data_list[it->first - 1]; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate_data_list[it->first-1]->thumbnail_file; it++; + + //update the arrange order + std::map>::iterator map_it = current_plate_data->obj_inst_map.begin(); + while (map_it != current_plate_data->obj_inst_map.end()) { + int obj_index, obj_id = map_it->first, inst_index = map_it->second.first; + IndexToPathMap::iterator index_iter = m_index_paths.find(obj_id); + if (index_iter == m_index_paths.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ + << boost::format(", can not find object from plate's obj_map, id=%1%, skip this object")%obj_id; + map_it++; + continue; + } + Id temp_id = std::make_pair(index_iter->second, index_iter->first); + IdToModelObjectMap::iterator object_item = m_objects.find(temp_id); + if (object_item == m_objects.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ + << boost::format(", can not find object from plate's obj_map, ID <%1%, %2%>, skip this object")%index_iter->second %index_iter->first; + map_it++; + continue; + } + obj_index = object_item->second; + + if (obj_index >= m_model->objects.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_index; + map_it++; + continue; + } + ModelObject* obj = m_model->objects[obj_index]; + if (inst_index >= obj->instances.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_index; + map_it++; + continue; + } + ModelInstance* inst = obj->instances[inst_index]; + inst->arrange_order = map_it->second.second; + map_it++; + } + } + + if ((plate_id > 0) && (plate_id <= m_plater_data.size())) { + //remove the no need objects + std::vector delete_ids; + for (int index = 0; index < m_model->objects.size(); index++) { + ModelObject* obj = m_model->objects[index]; + if (obj->volumes.size() == 0) { + //remove this model objects + delete_ids.push_back(index); + } + } + + for (int index = delete_ids.size() - 1; index >= 0; index--) + m_model->delete_object(delete_ids[index]); } //BBS progress point @@ -1915,7 +2209,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return; } - /*void _BBS_3MF_Importer::_extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) + void _BBS_3MF_Importer::_extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) { if (stat.m_uncomp_size > 0) { std::string buffer((size_t)stat.m_uncomp_size, 0); @@ -1976,7 +2270,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } } - + /* void _BBS_3MF_Importer::_extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions) { if (stat.m_uncomp_size > 0) { @@ -2451,7 +2745,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_index_paths.insert({ object.first.second, object.first.first}); } - if (m_version == 0) { + if (!m_is_bbl_3mf) { // if the 3mf was not produced by BambuStudio and there is only one object, // set the object name to match the filename if (m_model->objects.size() == 1) @@ -2840,11 +3134,13 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); throw version_error(msg); }*/ - } else if (m_curr_metadata_name == "Application") { + } else if (m_curr_metadata_name == BBL_APPLICATION_TAG) { // Generator application of the 3MF. // SLIC3R_APP_KEY - SLIC3R_VERSION - if (boost::starts_with(m_curr_characters, "BambuStudio-")) + if (boost::starts_with(m_curr_characters, "BambuStudio-")) { + m_is_bbl_3mf = true; m_bambuslicer_generator_version = Semver::parse(m_curr_characters.substr(12)); + } //TODO: currently use version 0, no need to load&&save this string /*} else if (m_curr_metadata_name == BBS_FDM_SUPPORTS_PAINTING_VERSION) { m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); @@ -2884,6 +3180,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } else if (m_curr_metadata_name == BBL_REGION_TAG) { BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters; m_contry_code = xml_unescape(m_curr_characters); + } else if (m_curr_metadata_name == BBL_CREATION_DATE_TAG) { + ; + } else if (m_curr_metadata_name == BBL_MODIFICATION_TAG) { + ; + } else { + ; + } + if (!m_curr_metadata_name.empty()) { + BOOST_LOG_TRIVIAL(info) << "load_3mf found metadata key = " << m_curr_metadata_name << ", value = " << xml_unescape(m_curr_characters); + model_info.metadata_items[m_curr_metadata_name] = xml_unescape(m_curr_characters); } return true; @@ -3131,6 +3437,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { std::istringstream(value) >> std::boolalpha >> m_curr_plater->locked; } + else if (key == BED_TYPE_ATTR) + { + BedType bed_type = BedType::btPC; + ConfigOptionEnum::from_string(value, bed_type); + m_curr_plater->config.set_key_value("curr_bed_type", new ConfigOptionEnum(bed_type)); + } else if (key == GCODE_FILE_ATTR) { m_curr_plater->gcode_file = value; @@ -3151,9 +3463,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { m_curr_instance.instance_id = atoi(value.c_str()); } + else if (key == ARRANGE_ORDER_ATTR) + { + m_curr_instance.arrange_order = atoi(value.c_str()); + } else if (key == OBJECT_ID_ATTR) { - int obj_id = atoi(value.c_str()); + m_curr_instance.object_id = atoi(value.c_str()); + /*int obj_id = atoi(value.c_str()); m_curr_instance.object_id = -1; IndexToPathMap::iterator index_iter = m_index_paths.find(obj_id); if (index_iter == m_index_paths.end()) { @@ -3168,7 +3485,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) << boost::format(", can not find object for plate's item, ID <%1%, %2%>, skip this object")%index_iter->second %index_iter->first; return true; } - m_curr_instance.object_id = object_item->second; + m_curr_instance.object_id = object_item->second;*/ } else if (key == PLATE_IDX_ATTR) { @@ -3192,6 +3509,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (m_curr_plater) std::istringstream(value) >> std::boolalpha >> m_curr_plater->toolpath_outside; } + else if (key == SUPPORT_USED_ATTR) + { + if (m_curr_plater) + std::istringstream(value) >> std::boolalpha >> m_curr_plater->is_support_used; + } } return true; @@ -3298,11 +3620,13 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //add_error("invalid object id/instance id"); //skip this instance m_curr_instance.object_id = m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; return true; } - m_curr_plater->objects_and_instances.emplace_back(m_curr_instance.object_id, m_curr_instance.instance_id); + m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, std::make_pair(m_curr_instance.instance_id, m_curr_instance.arrange_order)); m_curr_instance.object_id = m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; return true; } @@ -3405,28 +3729,28 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - void _BBS_3MF_Importer::_generate_current_object_list(std::vector &sub_objects, Id object_id, IdToCurrentObjectMap current_objects) + void _BBS_3MF_Importer::_generate_current_object_list(std::vector &sub_objects, Id object_id, IdToCurrentObjectMap ¤t_objects) { - std::list id_list; - id_list.push_back({ object_id, Transform3d::Identity() }); + std::list> id_list; + id_list.push_back(std::make_pair(Component(object_id, Transform3d::Identity()), Transform3d::Identity())); while (!id_list.empty()) { - Component current_id = id_list.front(); + auto current_item = id_list.front(); + Component current_id = current_item.first; id_list.pop_front(); IdToCurrentObjectMap::iterator current_object = current_objects.find(current_id.object_id); if (current_object != current_objects.end()) { //found one if (!current_object->second.components.empty()) { - for (const Component& comp: current_object->second.components) - { - id_list.push_back(comp); + for (const Component &comp : current_object->second.components) { + id_list.push_back(std::pair(comp, current_item.second * comp.transform)); } } else if (!(current_object->second.geometry.empty())) { //CurrentObject* ptr = &(current_objects[current_id]); //CurrentObject* ptr2 = &(current_object->second); - sub_objects.push_back({ current_object->first, current_id.transform }); + sub_objects.push_back({ current_object->first, current_item.second}); } } } @@ -3534,7 +3858,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) TriangleMesh triangle_mesh(std::move(its), volume_data->mesh_stats); - if (m_version == 0) { + if (!m_is_bbl_3mf) { // if the 3mf was not produced by BambuStudio and there is only one instance, // bake the transformation into the geometry to allow the reload from disk command // to work properly @@ -3563,7 +3887,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //set transform from 3mf Slic3r::Geometry::Transformation comp_transformatino(sub_comp.transform); - volume->set_transformation(volume->get_transformation() * comp_transformatino); + volume->set_transformation(comp_transformatino * volume->get_transformation()); if (shared_volume) { const TriangleMesh& trangle_mesh = volume->mesh(); Vec3d shift = trangle_mesh.get_init_shift(); @@ -3703,7 +4027,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) TriangleMesh triangle_mesh(std::move(its), volume_data.mesh_stats); - if (m_version == 0) { + if (!m_is_bbl_3mf) { // if the 3mf was not produced by BambuStudio and there is only one instance, // bake the transformation into the geometry to allow the reload from disk command // to work properly @@ -3821,6 +4145,468 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } + /* functions of ObjectImporter */ + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model(const char** attributes, unsigned int num_attributes) + { + object_unit_factor = bbs_get_unit_factor(bbs_get_attribute_value_string(attributes, num_attributes, UNIT_ATTR)); + + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_resources(const char** attributes, unsigned int num_attributes) + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_resources() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_object(const char** attributes, unsigned int num_attributes) + { + // reset current object data + if (current_object) { + delete current_object; + current_object = nullptr; + } + + std::string object_type = bbs_get_attribute_value_string(attributes, num_attributes, TYPE_ATTR); + + if (bbs_is_valid_object_type(object_type)) { + if (!current_object) { + current_object = new CurrentObject(); + } + + current_object->id = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR); + current_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR); + + current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR); + current_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR); + } + + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_object() + { + if (!current_object || (current_object->id == -1)) { + top_importer->add_error("Found invalid object for "+ object_path); + return false; + } + else { + if (is_bbl_3mf && boost::ends_with(current_object->uuid, OBJECT_UUID_SUFFIX) && top_importer->m_load_restore) { + std::istringstream iss(current_object->uuid); + int backup_id; + bool need_replace = false; + if (iss >> std::hex >> backup_id) { + need_replace = (current_object->id != backup_id); + current_object->id = backup_id; + } + //if (need_replace) + { + for (int index = 0; index < current_object->components.size(); index++) + { + int temp_id = (index + 1) << 16 | backup_id; + Component& component = current_object->components[index]; + std::string new_path = component.object_id.first; + Id new_id = std::make_pair(new_path, temp_id); + IdToCurrentObjectMap::iterator object_it = object_list.find(component.object_id); + if (object_it != object_list.end()) { + CurrentObject new_object; + new_object.geometry = std::move(object_it->second.geometry); + new_object.id = temp_id; + new_object.model_object_idx = object_it->second.model_object_idx; + new_object.name = object_it->second.name; + new_object.uuid = object_it->second.uuid; + + object_list.erase(object_it); + object_list.insert({ new_id, std::move(new_object) }); + } + else { + top_importer->add_error("can not find object for component, id=" + std::to_string(component.object_id.second)); + delete current_object; + current_object = nullptr; + return false; + } + + component.object_id.second = temp_id; + } + } + } + Id id = std::make_pair(object_path, current_object->id); + if (object_list.find(id) == object_list.end()) { + object_list.insert({ id, std::move(*current_object) }); + delete current_object; + current_object = nullptr; + } + else { + top_importer->add_error("Found object with duplicate id for "+object_path); + delete current_object; + current_object = nullptr; + return false; + } + } + + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_color_group(const char **attributes, unsigned int num_attributes) + { + object_current_color_group = bbs_get_attribute_value_int(attributes, num_attributes, ID_ATTR); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_color_group() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_color(const char **attributes, unsigned int num_attributes) + { + std::string color = bbs_get_attribute_value_string(attributes, num_attributes, COLOR_ATTR); + object_group_id_to_color[object_current_color_group] = color; + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_color() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_mesh(const char** attributes, unsigned int num_attributes) + { + // reset current geometry + if (current_object) + current_object->geometry.reset(); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_mesh() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_vertices(const char** attributes, unsigned int num_attributes) + { + // reset current vertices + if (current_object) + current_object->geometry.vertices.clear(); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_vertices() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_vertex(const char** attributes, unsigned int num_attributes) + { + // appends the vertex coordinates + // missing values are set equal to ZERO + if (current_object) + current_object->geometry.vertices.emplace_back( + object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, X_ATTR), + object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Y_ATTR), + object_unit_factor * bbs_get_attribute_value_float(attributes, num_attributes, Z_ATTR)); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_vertex() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_triangles(const char** attributes, unsigned int num_attributes) + { + // reset current triangles + if (current_object) + current_object->geometry.triangles.clear(); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_triangles() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_triangle(const char** attributes, unsigned int num_attributes) + { + // we are ignoring the following attributes: + // p1 + // p2 + // p3 + // pid + // see specifications + + // appends the triangle's vertices indices + // missing values are set equal to ZERO + if (current_object) { + current_object->geometry.triangles.emplace_back( + bbs_get_attribute_value_int(attributes, num_attributes, V1_ATTR), + bbs_get_attribute_value_int(attributes, num_attributes, V2_ATTR), + bbs_get_attribute_value_int(attributes, num_attributes, V3_ATTR)); + + current_object->geometry.custom_supports.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR)); + current_object->geometry.custom_seam.push_back(bbs_get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR)); + current_object->geometry.mmu_segmentation.push_back(bbs_get_attribute_value_string(attributes, num_attributes, MMU_SEGMENTATION_ATTR)); + // BBS + current_object->geometry.face_properties.push_back(bbs_get_attribute_value_string(attributes, num_attributes, FACE_PROPERTY_ATTR)); + } + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_triangle() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_components(const char** attributes, unsigned int num_attributes) + { + // reset current components + if (current_object) + current_object->components.clear(); + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_components() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_component(const char** attributes, unsigned int num_attributes) + { + int object_id = bbs_get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); + Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); + + /*Id id = std::make_pair(m_sub_model_path, object_id); + IdToModelObjectMap::iterator object_item = m_objects.find(id); + if (object_item == m_objects.end()) { + IdToAliasesMap::iterator alias_item = m_objects_aliases.find(id); + if (alias_item == m_objects_aliases.end()) { + add_error("Found component with invalid object id"); + return false; + } + }*/ + + if (current_object) { + Id id = std::make_pair(object_path, object_id); + current_object->components.emplace_back(id, transform); + } + + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_component() + { + // do nothing + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_start_metadata(const char** attributes, unsigned int num_attributes) + { + obj_curr_metadata_name.clear(); + + std::string name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR); + if (!name.empty()) { + obj_curr_metadata_name = name; + } + + return true; + } + + bool _BBS_3MF_Importer::ObjectImporter::_handle_object_end_metadata() + { + if ((obj_curr_metadata_name == BBS_3MF_VERSION)||(obj_curr_metadata_name == BBS_3MF_VERSION1)) { + is_bbl_3mf = true; + } + return true; + } + void _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element(const char* name, const char** attributes) + { + if (object_xml_parser == nullptr) + return; + + bool res = true; + unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(object_xml_parser); + + if (::strcmp(MODEL_TAG, name) == 0) + res = _handle_object_start_model(attributes, num_attributes); + else if (::strcmp(RESOURCES_TAG, name) == 0) + res = _handle_object_start_resources(attributes, num_attributes); + else if (::strcmp(OBJECT_TAG, name) == 0) + res = _handle_object_start_object(attributes, num_attributes); + else if (::strcmp(COLOR_GROUP_TAG, name) == 0) + res = _handle_object_start_color_group(attributes, num_attributes); + else if (::strcmp(COLOR_TAG, name) == 0) + res = _handle_object_start_color(attributes, num_attributes); + else if (::strcmp(MESH_TAG, name) == 0) + res = _handle_object_start_mesh(attributes, num_attributes); + else if (::strcmp(VERTICES_TAG, name) == 0) + res = _handle_object_start_vertices(attributes, num_attributes); + else if (::strcmp(VERTEX_TAG, name) == 0) + res = _handle_object_start_vertex(attributes, num_attributes); + else if (::strcmp(TRIANGLES_TAG, name) == 0) + res = _handle_object_start_triangles(attributes, num_attributes); + else if (::strcmp(TRIANGLE_TAG, name) == 0) + res = _handle_object_start_triangle(attributes, num_attributes); + else if (::strcmp(COMPONENTS_TAG, name) == 0) + res = _handle_object_start_components(attributes, num_attributes); + else if (::strcmp(COMPONENT_TAG, name) == 0) + res = _handle_object_start_component(attributes, num_attributes); + else if (::strcmp(METADATA_TAG, name) == 0) + res = _handle_object_start_metadata(attributes, num_attributes); + + if (!res) + _stop_object_xml_parser(); + } + + void _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element(const char* name) + { + if (object_xml_parser == nullptr) + return; + + bool res = true; + + if (::strcmp(MODEL_TAG, name) == 0) + res = _handle_object_end_model(); + else if (::strcmp(RESOURCES_TAG, name) == 0) + res = _handle_object_end_resources(); + else if (::strcmp(OBJECT_TAG, name) == 0) + res = _handle_object_end_object(); + else if (::strcmp(COLOR_GROUP_TAG, name) == 0) + res = _handle_object_end_color_group(); + else if (::strcmp(COLOR_TAG, name) == 0) + res = _handle_object_end_color(); + else if (::strcmp(MESH_TAG, name) == 0) + res = _handle_object_end_mesh(); + else if (::strcmp(VERTICES_TAG, name) == 0) + res = _handle_object_end_vertices(); + else if (::strcmp(VERTEX_TAG, name) == 0) + res = _handle_object_end_vertex(); + else if (::strcmp(TRIANGLES_TAG, name) == 0) + res = _handle_object_end_triangles(); + else if (::strcmp(TRIANGLE_TAG, name) == 0) + res = _handle_object_end_triangle(); + else if (::strcmp(COMPONENTS_TAG, name) == 0) + res = _handle_object_end_components(); + else if (::strcmp(COMPONENT_TAG, name) == 0) + res = _handle_object_end_component(); + else if (::strcmp(METADATA_TAG, name) == 0) + res = _handle_object_end_metadata(); + + if (!res) + _stop_object_xml_parser(); + } + + void _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters(const XML_Char* s, int len) + { + obj_curr_characters.append(s, len); + } + + void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element(void* userData, const char* name, const char** attributes) + { + ObjectImporter* importer = (ObjectImporter*)userData; + if (importer != nullptr) + importer->_handle_object_start_model_xml_element(name, attributes); + } + + void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element(void* userData, const char* name) + { + ObjectImporter* importer = (ObjectImporter*)userData; + if (importer != nullptr) + importer->_handle_object_end_model_xml_element(name); + } + + void XMLCALL _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters(void* userData, const XML_Char* s, int len) + { + ObjectImporter* importer = (ObjectImporter*)userData; + if (importer != nullptr) + importer->_handle_object_xml_characters(s, len); + } + + bool _BBS_3MF_Importer::ObjectImporter::_extract_object_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) + { + if (stat.m_uncomp_size == 0) { + top_importer->add_error("Found invalid size for "+object_path); + return false; + } + + object_xml_parser = XML_ParserCreate(nullptr); + if (object_xml_parser == nullptr) { + top_importer->add_error("Unable to create parser for "+object_path); + return false; + } + + XML_SetUserData(object_xml_parser, (void*)this); + XML_SetElementHandler(object_xml_parser, _BBS_3MF_Importer::ObjectImporter::_handle_object_start_model_xml_element, _BBS_3MF_Importer::ObjectImporter::_handle_object_end_model_xml_element); + XML_SetCharacterDataHandler(object_xml_parser, _BBS_3MF_Importer::ObjectImporter::_handle_object_xml_characters); + + struct CallbackData + { + XML_Parser& parser; + _BBS_3MF_Importer::ObjectImporter& importer; + const mz_zip_archive_file_stat& stat; + + CallbackData(XML_Parser& parser, _BBS_3MF_Importer::ObjectImporter& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {} + }; + + CallbackData data(object_xml_parser, *this, stat); + + mz_bool res = 0; + + try + { + mz_file_write_func callback = [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t { + CallbackData* data = (CallbackData*)pOpaque; + if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.object_parse_error()) { + char error_buf[1024]; + ::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.object_parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser)); + throw Slic3r::FileIOError(error_buf); + } + return n; + }; + void* opaque = &data; + res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, callback, opaque, 0); + } + catch (const version_error& e) + { + // rethrow the exception + std::string error_message = std::string(e.what()) + " for " + object_path; + throw Slic3r::FileIOError(error_message); + } + catch (std::exception& e) + { + std::string error_message = std::string(e.what()) + " for " + object_path; + top_importer->add_error(error_message); + return false; + } + + if (res == 0) { + top_importer->add_error("Error while extracting model data from zip archive for "+object_path); + return false; + } + + return true; + } + + class _BBS_3MF_Exporter : public _BBS_3MF_Base { struct BuildItem @@ -3969,6 +4755,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) store_params.thumbnail_data, store_params.proFn, store_params.calibration_thumbnail_data, store_params.id_bboxes, store_params.project, store_params.export_plate_idx); if (result) { boost::filesystem::rename(filename + ".tmp", filename, ec); + if (ec) { + add_error("Failed to rename file: " + ec.message()); + boost::filesystem::remove(filename + ".tmp", ec); + return false; + } if (!(store_params.strategy & SaveStrategy::Silence)) boost::filesystem::save_string_file(store_params.model->get_backup_path() + "/origin.txt", filename); } @@ -3991,7 +4782,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) boost::system::error_code ec; boost::filesystem::remove(filepath_tmp, ec); if (!open_zip_writer(&archive, filepath_tmp)) { - add_error("Unable to open the file"); + add_error("Unable to open the file"+filepath_tmp); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to open the file\n"); return false; } @@ -4051,7 +4842,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } if (!open_zip_writer(&archive, filename)) { - add_error("Unable to open the file"); + add_error("Unable to open the file"+filename); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to open the file\n"); return false; } @@ -4103,9 +4894,26 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } } } + else if (!m_skip_static && plate_data_list.size() > 0) { + for (int i = 0; i < plate_data_list.size(); i++) { + PlateData *plate_data = plate_data_list[i]; + if (proFn) { + proFn(EXPORT_STAGE_ADD_THUMBNAILS, i, plate_data_list.size(), cb_cancel); + if (cb_cancel) + return false; + } + if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){ + std::string dst_in_3mf = (boost::format("Metadata/plate_%1%.png") % (i + 1)).str(); + if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->thumbnail_file)) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add thumbnail %1% from file %2% failed\n") % (i+1) %plate_data->thumbnail_file; + return false; + } + } + } + } - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before add calibration data, count %1%\n")%calibration_data.size(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before add calibration thumbnails, count %1%\n")%calibration_data.size(); //BBS add calibration thumbnail for each plate if (!m_skip_static && calibration_data.size() > 0) { // Adds the file Metadata/calibration_p[X].png. @@ -4125,7 +4933,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } } + } + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",before add calibration boundingbox, count %1%\n")%id_bboxes.size(); + if (!m_skip_static && id_bboxes.size() > 0) { + // Adds the file Metadata/calibration_p[X].png. + for (unsigned int index = 0; index < id_bboxes.size(); index++) + { // BBS: save bounding box to json if (id_bboxes[index]->is_valid()) { if (!_add_bbox_file_to_archive(archive, *id_bboxes[index], index)) { @@ -4155,11 +4970,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) // Adds layer height profile file ("Metadata/Slic3r_PE_layer_heights_profile.txt"). // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model. // The index differes from the index of an object ID of an object instance of a 3MF file! - // BBS: don't need to save layer_height_profile because we calculate when slicing every time. - /* if (!_add_layer_height_profile_file_to_archive(archive, model)) { + close_zip_writer(&archive); + boost::filesystem::remove(filename); return false; - }*/ + } // BBS progress point /*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_LAYER_RANGE\n"); @@ -4565,17 +5380,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (m_production_ext) stream << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\""; stream << ">\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBS_3MF_VERSION << "\">" << VERSION_BBS_3MF << "\n"; - - //TODO: currently use version 0, no need to load&&save this string - /*if (model.is_fdm_support_painted()) - stream << " <" << METADATA_TAG << " name=\"" << BBS_FDM_SUPPORTS_PAINTING_VERSION << "\">" << FDM_SUPPORTS_PAINTING_VERSION << "\n"; - - if (model.is_seam_painted()) - stream << " <" << METADATA_TAG << " name=\"" << BBS_SEAM_PAINTING_VERSION << "\">" << SEAM_PAINTING_VERSION << "\n"; - - if (model.is_mm_painted()) - stream << " <" << METADATA_TAG << " name=\"" << BBS_MM_PAINTING_VERSION << "\">" << MM_PAINTING_VERSION << "\n";*/ std::string name; std::string user_name; @@ -4594,6 +5398,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_user_id = " << user_id; } + if (project) { + model_id = project->project_model_id; + region_code = project->project_country_code; + } + if (model.model_info) { design_cover = model.model_info->cover_file; license = model.model_info->license; @@ -4602,32 +5411,42 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) name = model.model_info->model_name; BOOST_LOG_TRIVIAL(trace) << "design_info, save_3mf found designer_cover = " << design_cover; } - - if (project) { - model_id = project->project_model_id; - region_code = project->project_country_code; - } + // remember to use metadata_item_map to store metadata info + std::map metadata_item_map; if (!sub_model) { - stream << " <" << METADATA_TAG << " name=\"" << BBL_MODEL_NAME_TAG << "\">" << xml_escape(name) << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_DESIGNER_TAG << "\">" << xml_escape(user_name) << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_DESIGNER_USER_ID_TAG << "\">" << user_id << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_DESIGNER_COVER_FILE_TAG << "\">" << xml_escape(design_cover) << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_DESCRIPTION_TAG << "\">" << xml_escape(description) << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_COPYRIGHT_TAG << "\">" << xml_escape(copyright) << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_LICENSE_TAG << "\">" << xml_escape(license) << "\n"; + // update metadat_items + if (model.model_info && model.model_info.get()) { + metadata_item_map = model.model_info.get()->metadata_items; + } + + metadata_item_map[BBL_MODEL_NAME_TAG] = xml_escape(name); + metadata_item_map[BBL_DESIGNER_TAG] = xml_escape(user_name); + metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id; + metadata_item_map[BBL_DESIGNER_COVER_FILE_TAG] = xml_escape(design_cover); + metadata_item_map[BBL_DESCRIPTION_TAG] = xml_escape(description); + metadata_item_map[BBL_COPYRIGHT_TAG] = xml_escape(copyright); + metadata_item_map[BBL_LICENSE_TAG] = xml_escape(license); /* save model info */ if (!model_id.empty()) { - stream << " <" << METADATA_TAG << " name=\"" << BBL_MODEL_ID_TAG << "\">" << model_id << "\n"; - stream << " <" << METADATA_TAG << " name=\"" << BBL_REGION_TAG << "\">" << region_code << "\n"; + metadata_item_map[BBL_MODEL_ID_TAG] = model_id; + metadata_item_map[BBL_REGION_TAG] = region_code; } std::string date = Slic3r::Utils::utc_timestamp(Slic3r::Utils::get_current_time_utc()); // keep only the date part of the string date = date.substr(0, 10); - stream << " <" << METADATA_TAG << " name=\"CreationDate\">" << date << "\n"; - stream << " <" << METADATA_TAG << " name=\"ModificationDate\">" << date << "\n"; - stream << " <" << METADATA_TAG << " name=\"Application\">" << SLIC3R_APP_KEY << "-" << SLIC3R_VERSION << "\n"; + metadata_item_map[BBL_CREATION_DATE_TAG] = date; + metadata_item_map[BBL_MODIFICATION_TAG] = date; + metadata_item_map[BBL_APPLICATION_TAG] = (boost::format("%1%-%2%") % SLIC3R_APP_KEY % SLIC3R_VERSION).str(); + } + metadata_item_map[BBS_3MF_VERSION] = std::to_string(VERSION_BBS_3MF); + + // store metadata info + for (auto item : metadata_item_map) { + BOOST_LOG_TRIVIAL(info) << "bbs_3mf: save key= " << item.first << ", value = " << item.second; + stream << " <" << METADATA_TAG << " name=\"" << item.first << "\">" + << xml_escape(item.second) << "\n"; } stream << " <" << RESOURCES_TAG << ">\n"; @@ -5171,7 +5990,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - /*bool _BBS_3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model) + bool _BBS_3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model) { assert(is_decimal_separator_point()); std::string out = ""; @@ -5196,7 +6015,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } if (!out.empty()) { - if (!mz_zip_writer_add_mem(&archive, LAYER_HEIGHTS_PROFILE_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { + if (!mz_zip_writer_add_mem(&archive, BBS_LAYER_HEIGHTS_PROFILE_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { add_error("Unable to add layer heights profile file to archive"); BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format("Unable to add layer heights profile file to archive\n"); return false; @@ -5205,7 +6024,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } - + /* bool _BBS_3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model) { std::string out = ""; @@ -5563,6 +6382,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //plate index stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PLATERID_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->plate_index + 1 << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LOCK_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->locked<< "\"/>\n"; + ConfigOption* bed_type_opt = plate_data->config.option("curr_bed_type"); + t_config_enum_names bed_type_names = ConfigOptionEnum::get_enum_names(); + if (bed_type_opt != nullptr && bed_type_names.size() > bed_type_opt->getInt()) + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << BED_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << bed_type_names[bed_type_opt->getInt()] << "\"/>\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()) { @@ -5572,6 +6396,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) std::string thumbnail_file_in_3mf = (boost::format(THUMBNAIL_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n"; } + else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file))){ + std::string thumbnail_file_in_3mf = (boost::format(THUMBNAIL_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n"; + } if (!plate_data->pattern_file.empty()) { std::string pattern_file_in_3mf = (boost::format(PATTERN_FILE_FORMAT) % (plate_data->plate_index + 1)).str(); @@ -5589,14 +6417,32 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << INSTANCE_TAG << ">\n"; int obj_id = plate_data->objects_and_instances[j].first; int inst_id = plate_data->objects_and_instances[j].second; - if (m_skip_static) { - obj_id = model.objects[obj_id]->get_backup_id(); + int arrange_o = 0; + ModelObject* obj = NULL; + ModelInstance* inst = NULL; + if (obj_id >= model.objects.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_id; + } + else + obj = model.objects[obj_id]; + + if (obj && (inst_id >= obj->instances.size())) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_id; + } + else if (obj){ + inst = obj->instances[inst_id]; + arrange_o = inst->arrange_order; + } + if (m_skip_static && obj) { + obj_id = obj->get_backup_id(); } else { //inst_id = convert_instance_id_to_resource_id(model, obj_id, inst_id); obj_id = convert_instance_id_to_resource_id(model, obj_id, 0); } + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OBJECT_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << obj_id << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << INSTANCEID_ATTR << "\" " << VALUE_ATTR << "=\"" << inst_id << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ARRANGE_ORDER_ATTR << "\" " << VALUE_ATTR << "=\"" << arrange_o << "\"/>\n"; stream << " \n"; } } @@ -5632,7 +6478,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << "\" "; stream << OFFSET_ATTR << "=\""; - Vec3d ofs2ass = obj->instances[instance_idx]->get_offset_to_assembly(); + const Vec3d ofs2ass = obj->instances[instance_idx]->get_offset_to_assembly(); stream << ofs2ass(0) << " " << ofs2ass(1) << " " << ofs2ass(2); stream << "\" />\n"; } @@ -5681,6 +6527,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_PREDICTION_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_prediction_str() << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_WEIGHT_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_weight_str() << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SUPPORT_USED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_support_used << "\"/>\n"; for (auto it = plate_data->slice_filaments_info.begin(); it != plate_data->slice_filaments_info.end(); it++) { @@ -5692,7 +6539,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) } for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) { - stream << " <" << SLICE_WARNING_TAG << " " << "msg=\"" << it->msg << "\" " << "level=\"" << std::to_string(it->level) << "\" />\n"; + stream << " <" << SLICE_WARNING_TAG << " msg=\"" << it->msg << "\" level=\"" << std::to_string(it->level) << "\" error_code =\"" << it->error_code << "\" />\n"; } stream << " \n"; } @@ -6264,7 +7111,8 @@ private: //BBS: add plate data list related logic -bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector* project_presets, bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn, LoadStrategy strategy, BBLProject *project) +bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector* project_presets, + bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn, LoadStrategy strategy, BBLProject *project, int plate_id) { if (path == nullptr || config == nullptr || model == nullptr) return false; @@ -6272,7 +7120,7 @@ bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstituti // All import should use "C" locales for number formatting. CNumericLocalesSetter locales_setter; _BBS_3MF_Importer importer; - bool res = importer.load_model_from_file(path, *model, *plate_data_list, *project_presets, *config, *config_substitutions, strategy, *is_bbl_3mf, *file_version, proFn, project); + bool res = importer.load_model_from_file(path, *model, *plate_data_list, *project_presets, *config, *config_substitutions, strategy, *is_bbl_3mf, *file_version, proFn, project, plate_id); importer.log_errors(); //BBS: remove legacy project logic currently //handle_legacy_project_loaded(importer.version(), *config); diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index 07d55f8976..3652709116 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -57,6 +57,7 @@ struct PlateData int plate_index; std::vector> objects_and_instances; + std::map> obj_inst_map; std::string gcode_file; std::string gcode_file_md5; std::string thumbnail_file; @@ -67,6 +68,8 @@ struct PlateData std::string gcode_prediction; std::string gcode_weight; std::vector slice_filaments_info; + DynamicPrintConfig config; + bool is_support_used {false}; bool is_sliced_valid = false; bool toolpath_outside {false}; @@ -202,7 +205,8 @@ struct StoreParams //BBS: add plate data list related logic // add restore logic // Load the content of a 3mf file into the given model and preset bundle. -extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector* project_presets, bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn = nullptr, LoadStrategy strategy = LoadStrategy::Default, BBLProject *project = nullptr); +extern bool load_bbs_3mf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, PlateDataPtrs* plate_data_list, std::vector* project_presets, + bool* is_bbl_3mf, Semver* file_version, Import3mfProgressFn proFn = nullptr, LoadStrategy strategy = LoadStrategy::Default, BBLProject *project = nullptr, int plate_id = 0); extern std::string bbs_3mf_get_thumbnail(const char * path); diff --git a/src/libslic3r/Format/svg.cpp b/src/libslic3r/Format/svg.cpp new file mode 100644 index 0000000000..bf2f3cf492 --- /dev/null +++ b/src/libslic3r/Format/svg.cpp @@ -0,0 +1,341 @@ +#include "../libslic3r.h" +#include "../Model.hpp" +#include "../TriangleMesh.hpp" + +#include "svg.hpp" +#include "nanosvg/nanosvg.h" + +#include + +#include + +#include "BRepBuilderAPI_MakeWire.hxx" +#include "BRepBuilderAPI_MakeEdge.hxx" +#include "BRepBuilderAPI_MakeFace.hxx" +#include "BRepPrimAPI_MakePrism.hxx" +#include "BRepBuilderAPI_Transform.hxx" +#include "BRepMesh_IncrementalMesh.hxx" +#include "TopoDS_Face.hxx" +#include "TopExp_Explorer.hxx" +#include "TopoDS.hxx" +#include "BRepExtrema_SelfIntersection.hxx" + +namespace Slic3r { +const double STEP_TRANS_CHORD_ERROR = 0.005; +const double STEP_TRANS_ANGLE_RES = 1; + +struct Element_Info +{ + std::string name; + unsigned int color; + TopoDS_Shape shape; +}; + +bool is_same_points(gp_Pnt pt1, gp_Pnt pt2) { + return abs(pt1.X() - pt2.X()) < 0.001 + && abs(pt1.Y() - pt2.Y()) < 0.001 + && abs(pt1.Z() - pt2.Z()) < 0.001; +} + +struct Point_2D +{ + Point_2D(float in_x, float in_y) : x(in_x), y(in_y) {} + float x; + float y; +}; + +void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t) +{ + const float s = 1.0f - t; + + r[0] = s * a[0] + t * b[0]; + r[1] = s * a[1] + t * b[1]; +} + +void interp_v2_v2v2v2v2_cubic(float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2], const float u) +{ + float q0[2], q1[2], q2[2], r0[2], r1[2]; + + interp_v2_v2v2(q0, v1, v2, u); + interp_v2_v2v2(q1, v2, v3, u); + interp_v2_v2v2(q2, v3, v4, u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + interp_v2_v2v2(p, r0, r1, u); +} + +bool is_two_lines_interaction(gp_Pnt pL1, gp_Pnt pL2, gp_Pnt pR1, gp_Pnt pR2) { + Vec3d point1(pL1.X(), pL1.Y(), 0); + Vec3d point2(pL2.X(), pL2.Y(), 0); + Vec3d point3(pR1.X(), pR1.Y(), 0); + Vec3d point4(pR2.X(), pR2.Y(), 0); + + Vec3d line1 = point2 - point1; + Vec3d line2 = point4 - point3; + + Vec3d line_pos1 = point1 - point3; + Vec3d line_pos2 = point2 - point3; + + Vec3d line_pos3 = point3 - point1; + Vec3d line_pos4 = point4 - point1; + + Vec3d cross_1 = line2.cross(line_pos1); + Vec3d cross_2 = line2.cross(line_pos2); + + Vec3d cross_3 = line1.cross(line_pos3); + Vec3d cross_4 = line1.cross(line_pos4); + + return (cross_1.dot(cross_2) < 0) && (cross_3.dot(cross_4) < 0); +} + +bool is_profile_self_interaction(std::vector> profile_line_points) +{ + for (int i = 0; i < profile_line_points.size(); ++i) { + for (int j = i + 2; j < profile_line_points.size(); ++j) + if (is_two_lines_interaction(profile_line_points[i].first, profile_line_points[i].second, profile_line_points[j].first, profile_line_points[j].second)) + return true; + } + + return false; +} + +double get_profile_area(std::vector> profile_line_points) +{ + double min_x = 0; + for (auto line_points : profile_line_points) { + if (line_points.first.X() < min_x) min_x = line_points.first.X(); + } + + double area = 0; + for (auto line_points : profile_line_points) { + bool flag = true; + if (line_points.second.Y() < line_points.first.Y()) flag = false; + + area += (line_points.second.X() + line_points.first.X() - 2 * min_x) * (line_points.second.Y() - line_points.first.Y()) / 2; + } + + return abs(area); +} + +bool get_svg_profile(const char *path, std::vector &element_infos, std::string& message) +{ + NSVGimage *svg_data = nullptr; + svg_data = nsvgParseFromFile(path, "mm", 96.0f); + if (svg_data == nullptr) { + message = "import svg failed: could not open svg."; + return false; + } + if (svg_data->shapes == nullptr) { + message = "import svg failed: could not parse imported svg data."; + return false; + } + + int name_index = 1; + for (NSVGshape *shape = svg_data->shapes; shape; shape = shape->next) { + char * id = shape->id; + + int interpolation_precision = 10; // Number of interpolation points + float step = 1.0f / float(interpolation_precision - 1); + + // get the path point + std::vector>> all_path_points; // paths>> + for (NSVGpath *path = shape->paths; path; path = path->next) { + std::vector> profile_points; + int index = 0; + for (int i = 0; i < path->npts - 1; i += 3) { + float * p = &path->pts[i * 2]; + float a = 0.0f; + std::vector curve_points; // points on a curve + for (int v = 0; v < interpolation_precision; v++) { + float pt[2]; + + // get interpolation points of Bezier curve + interp_v2_v2v2v2v2_cubic(pt, &p[0], &p[2], &p[4], &p[6], a); + + Point_2D point(pt[0], -pt[1]); + curve_points.push_back(point); + a += step; + } + + profile_points.push_back(curve_points); + + // keep the adjacent curves end-to-end + if (profile_points.size() > 1) { + profile_points[index - 1].back() = profile_points[index].front(); + } + + index++; + } + + if (!profile_points.empty()) + all_path_points.push_back(profile_points); + } + + // remove duplicate points and ensure the profile is closed + std::vector>> path_line_points; + for (auto profile_points : all_path_points) { + std::vector> profile_line_points; + for (int i = 0; i < profile_points.size(); ++i) { + for (int j = 0; j + 1 < profile_points[i].size(); j++) { + gp_Pnt pt1(profile_points[i][j].x, profile_points[i][j].y, 0); + gp_Pnt pt2(profile_points[i][j + 1].x, profile_points[i][j + 1].y, 0); + if (is_same_points(pt1, pt2)) + continue; + + profile_line_points.push_back({pt1, pt2}); + } + } + // keep the start and end points of profile connected + profile_line_points.back().second = profile_line_points[0].first; + + if (is_profile_self_interaction(profile_line_points)) + BOOST_LOG_TRIVIAL(warning) << "the profile is self interaction."; + + path_line_points.push_back(profile_line_points); + } + + // generate all profile curves + std::vector wires; + int index = 0; + double max_area = 0; + for (int i = 0; i < path_line_points.size(); ++i) { + BRepBuilderAPI_MakeWire wire_build; + for (auto point_item : path_line_points[i]) { + TopoDS_Edge edge_build = BRepBuilderAPI_MakeEdge(point_item.first, point_item.second); + wire_build.Add(edge_build); + } + TopoDS_Wire wire = wire_build.Wire(); + double profile_area = get_profile_area(path_line_points[i]); + if (profile_area > max_area) { + max_area = profile_area; + index = i; + } + wires.emplace_back(wire); + } + + gp_Vec dir(0, 0, 10); + BRepBuilderAPI_MakeFace face_make(wires[index]); + for (int i = 0; i < wires.size(); ++i) { + if (index == i) + continue; + face_make.Add(wires[i]); + } + + TopoDS_Face face = face_make.Face(); + TopoDS_Shape element_shape = BRepPrimAPI_MakePrism(face, dir, false, false).Shape(); + + Element_Info element_info; + element_info.name = "part_" + std::to_string(name_index); + element_info.color = shape->fill.color; + element_info.shape = element_shape; + element_infos.push_back(element_info); + + name_index++; + } + + nsvgDelete(svg_data); + return true; +} + +bool load_svg(const char *path, Model *model, std::string &message) +{ + std::vector namedSolids; + if (!get_svg_profile(path, namedSolids, message)) + return false; + + std::vector stl; + stl.resize(namedSolids.size()); + // todo: zhimin, Can be accelerated in parallel with tbb + for (size_t i = 0 ; i < namedSolids.size(); i++) { + BRepMesh_IncrementalMesh mesh(namedSolids[i].shape, STEP_TRANS_CHORD_ERROR, false, STEP_TRANS_ANGLE_RES, true); + // BBS: calculate total number of the nodes and triangles + int aNbNodes = 0; + int aNbTriangles = 0; + for (TopExp_Explorer anExpSF(namedSolids[i].shape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) { + TopLoc_Location aLoc; + Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(TopoDS::Face(anExpSF.Current()), aLoc); + if (!aTriangulation.IsNull()) { + aNbNodes += aTriangulation->NbNodes(); + aNbTriangles += aTriangulation->NbTriangles(); + } + } + + if (aNbTriangles == 0 || aNbNodes == 0) + // BBS: No triangulation on the shape. + continue; + + stl[i].stats.type = inmemory; + stl[i].stats.number_of_facets = (uint32_t) aNbTriangles; + stl[i].stats.original_num_facets = stl[i].stats.number_of_facets; + stl_allocate(&stl[i]); + + std::vector points; + points.reserve(aNbNodes); + // BBS: count faces missing triangulation + Standard_Integer aNbFacesNoTri = 0; + // BBS: fill temporary triangulation + Standard_Integer aNodeOffset = 0; + Standard_Integer aTriangleOffet = 0; + for (TopExp_Explorer anExpSF(namedSolids[i].shape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) { + const TopoDS_Shape &aFace = anExpSF.Current(); + TopLoc_Location aLoc; + Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(TopoDS::Face(aFace), aLoc); + if (aTriangulation.IsNull()) { + ++aNbFacesNoTri; + continue; + } + // BBS: copy nodes + gp_Trsf aTrsf = aLoc.Transformation(); + for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) { + gp_Pnt aPnt = aTriangulation->Node(aNodeIter); + aPnt.Transform(aTrsf); + points.emplace_back(std::move(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()))); + } + // BBS: copy triangles + const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation(); + Standard_Integer anId[3]; + for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) { + Poly_Triangle aTri = aTriangulation->Triangle(aTriIter); + + aTri.Get(anId[0], anId[1], anId[2]); + if (anOrientation == TopAbs_REVERSED) std::swap(anId[1], anId[2]); + // BBS: save triangles facets + stl_facet facet; + facet.vertex[0] = points[anId[0] + aNodeOffset - 1].cast(); + facet.vertex[1] = points[anId[1] + aNodeOffset - 1].cast(); + facet.vertex[2] = points[anId[2] + aNodeOffset - 1].cast(); + facet.extra[0] = 0; + facet.extra[1] = 0; + stl_normal normal; + stl_calculate_normal(normal, &facet); + stl_normalize_vector(normal); + facet.normal = normal; + stl[i].facet_start[aTriangleOffet + aTriIter - 1] = facet; + } + + aNodeOffset += aTriangulation->NbNodes(); + aTriangleOffet += aTriangulation->NbTriangles(); + } + } + + ModelObject *new_object = model->add_object(); + // new_object->name ? + new_object->input_file = path; + auto stage_unit3 = stl.size() / LOAD_STEP_STAGE_UNIT_NUM + 1; + for (size_t i = 0; i < stl.size(); i++) { + // BBS: maybe mesh is empty from step file. Don't add + if (stl[i].stats.number_of_facets > 0) { + TriangleMesh triangle_mesh; + triangle_mesh.from_stl(stl[i]); + ModelVolume *new_volume = new_object->add_volume(std::move(triangle_mesh)); + new_volume->name = namedSolids[i].name; + new_volume->source.input_file = path; + new_volume->source.object_idx = (int) model->objects.size() - 1; + new_volume->source.volume_idx = (int) new_object->volumes.size() - 1; + } + } + return true; +} +} // namespace Slic3r diff --git a/src/libslic3r/Format/svg.hpp b/src/libslic3r/Format/svg.hpp new file mode 100644 index 0000000000..095251c32a --- /dev/null +++ b/src/libslic3r/Format/svg.hpp @@ -0,0 +1,7 @@ +#pragma once +namespace Slic3r { +class Model; + +extern bool load_svg(const char *path, Model *model, std::string &message); + +}; // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 78c1b17ae9..63853d48af 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -682,8 +682,7 @@ std::vector GCode::collect_layers_to_print(const PrintObjec // first layer may result in skirt/brim in the air and maybe other issues. if (layers_to_print.size() == 1u) { if (!has_extrusions) - throw Slic3r::SlicingError(_(L("One object has empty initial layer and can't be printed. Please Cut the bottom or enable supports.")) + "\n" + - _(L("Object")) + ": " + object.model_object()->name); + throw Slic3r::SlicingError(_(L("One object has empty initial layer and can't be printed. Please Cut the bottom or enable supports.")), object.id().id); } // In case there are extrusions on this layer, check there is a layer to lay it on. @@ -1379,10 +1378,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write(full_config); // SoftFever: write compatiple image - std::vector temps_per_bed; - int first_layer_bed_temperature = 0; - get_bed_temperature(0, true, temps_per_bed, - first_layer_bed_temperature); + int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); file.write_format( @@ -1501,12 +1497,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Emit machine envelope limits for the Marlin firmware. this->print_machine_envelope(file, print); - //BBS: emit printing accelerate if has non-zero value - if (m_config.default_acceleration.value > 0) { - float acceleration = m_config.default_acceleration.value; - file.write(m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5))); - } - // Disable fan. if (m_config.auxiliary_fan.value && print.config().close_fan_the_first_x_layers.get_at(initial_extruder_id)) { file.write(m_writer.set_fan(0)); @@ -1874,9 +1864,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write(full_config); // SoftFever: write compatiple info - std::vector temps_per_bed; - int first_layer_bed_temperature = 0; - get_bed_temperature(0, true, temps_per_bed, first_layer_bed_temperature); + int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type); file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature); file.write_format( @@ -1885,7 +1873,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato file.write_format( "; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value); - file.write_format("; variable_layer_height = %d\n", m_config.adaptive_layer_height ? 1 : 0); + + //SF TODO +// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0); file.write("; CONFIG_BLOCK_END\n\n"); @@ -2135,17 +2125,11 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) } // BBS -void GCode::get_bed_temperature(const int extruder_id, const bool is_first_layer, std::vector& temps_per_bed, int& default_temp) const +int GCode::get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const { - temps_per_bed.resize((int)BedType::btCount, 0); - for (int bed_type = 0; bed_type < BedType::btCount; bed_type++) { - std::string bed_temp_key = is_first_layer ? get_bed_temp_1st_layer_key((BedType)bed_type) : get_bed_temp_key((BedType)bed_type); - const ConfigOptionInts* bed_temp_opt = m_config.option(bed_temp_key); - - temps_per_bed[bed_type] = bed_temp_opt->get_at(extruder_id); - if (bed_type == m_config.curr_bed_type) - default_temp = temps_per_bed[bed_type]; - } + std::string bed_temp_key = is_first_layer ? get_bed_temp_1st_layer_key(bed_type) : get_bed_temp_key(bed_type); + const ConfigOptionInts* bed_temp_opt = m_config.option(bed_temp_key); + return bed_temp_opt->get_at(extruder_id); } // Write 1st layer bed temperatures into the G-code. @@ -2157,8 +2141,7 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p // Initial bed temperature based on the first extruder. // BBS std::vector temps_per_bed; - int default_temp = 0; - get_bed_temperature(first_printing_extruder_id, true, temps_per_bed, default_temp); + int bed_temp = get_bed_temperature(first_printing_extruder_id, true, print.config().curr_bed_type); // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; @@ -2171,7 +2154,7 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if // the custom start G-code emited these. - std::string set_temp_gcode = m_writer.set_bed_temperature(temps_per_bed, default_temp, wait); + std::string set_temp_gcode = m_writer.set_bed_temperature(bed_temp, wait); if (! temp_set_by_gcode) file.write(set_temp_gcode); } @@ -2639,10 +2622,8 @@ GCode::LayerResult GCode::process_layer( } // BBS - std::vector temps_per_bed; - int default_temp = 0; - get_bed_temperature(first_extruder_id, false, temps_per_bed, default_temp); - gcode += m_writer.set_bed_temperature(temps_per_bed, default_temp); + int bed_temp = get_bed_temperature(first_extruder_id, false, print.config().curr_bed_type); + gcode += m_writer.set_bed_temperature(bed_temp); // Mark the temperature transition from 1st to 2nd layer to be finished. m_second_layer_things_done = true; } @@ -3297,11 +3278,8 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation - //BBS: extrude contour of wall ccw, hole of wall cw, except spiral mode - bool was_clockwise = loop.is_clockwise(); - if (m_config.spiral_mode || !is_perimeter(loop.role())) - loop.make_counter_clockwise(); - bool current_clockwise = loop.is_clockwise(); + // extrude all loops ccw + bool was_clockwise = loop.make_counter_clockwise(); // find the point of the loop that is closest to the current extruder position // or randomize if requested @@ -3371,7 +3349,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). Point a = paths.front().polyline.points[1]; // second point Point b = *(paths.back().polyline.points.end()-3); // second to last point - if (was_clockwise != current_clockwise) { + if (was_clockwise) { // swap points Point c = a; a = b; b = c; } @@ -3379,7 +3357,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou double angle = paths.front().first_point().ccw_angle(a, b) / 3; // turn left if contour, turn right if hole - if (was_clockwise != current_clockwise) angle *= -1; + if (was_clockwise) angle *= -1; // create the destination point along the first segment and rotate it // we make sure we don't exceed the segment length because we don't know @@ -3391,7 +3369,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou double l2 = v.squaredNorm(); // Shift by no more than a nozzle diameter. //FIXME Hiding the seams will not work nicely for very densely discretized contours! - Point pt = ((nd * nd >= l2) ? p2 : (p1 + v * (nd / sqrt(l2)))).cast(); + //BBS. shorten the travel distant before the wipe path + double threshold = 0.2; + Point pt = (p1 + v * threshold).cast(); + if (nd * nd < l2) + pt = (p1 + threshold * v * (nd / sqrt(l2))).cast(); + //Point pt = ((nd * nd >= l2) ? (p1+v*0.4): (p1 + 0.2 * v * (nd / sqrt(l2)))).cast(); pt.rotate(angle, paths.front().polyline.points.front()); // generate the travel move gcode += m_writer.travel_to_xy(this->point_to_gcode(pt), "move inwards before travel"); @@ -3654,8 +3637,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, acceleration = m_config.first_layer_acceleration_over_raft.value; } else if (m_config.bridge_acceleration.value > 0 && is_bridge(path.role())) { acceleration = m_config.bridge_acceleration.value; - } else if (m_config.perimeter_acceleration.value > 0 && is_perimeter(path.role())) { - acceleration = m_config.perimeter_acceleration.value; #endif } else if (m_config.outer_wall_acceleration.value > 0 && is_external_perimeter(path.role())) { acceleration = m_config.outer_wall_acceleration.value; @@ -3807,11 +3788,21 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, std::string comment; if (m_enable_cooling_markers) { - if (EXTRUDER_CONFIG(enable_overhang_bridge_fan) && - (path.get_overhang_degree() > EXTRUDER_CONFIG(overhang_fan_threshold) || is_bridge(path.role()))) - gcode += ";_OVERHANG_FAN_START\n"; - else + if (EXTRUDER_CONFIG(enable_overhang_bridge_fan)) { + //BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external perimeter + int overhang_threshold = EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none ? + Overhang_threshold_none : EXTRUDER_CONFIG(overhang_fan_threshold) - 1; + if ((EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none && path.role() == erExternalPerimeter) || + path.get_overhang_degree() > overhang_threshold || + is_bridge(path.role())) + gcode += ";_OVERHANG_FAN_START\n"; + else + comment = ";_EXTRUDE_SET_SPEED"; + } + else { comment = ";_EXTRUDE_SET_SPEED"; + } + if (path.role() == erExternalPerimeter) comment += ";_EXTERNAL_PERIMETER"; } @@ -3875,10 +3866,22 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, } } } - if (m_enable_cooling_markers) - gcode += (EXTRUDER_CONFIG(enable_overhang_bridge_fan) && - (is_bridge(path.role()) || path.get_overhang_degree() > EXTRUDER_CONFIG(overhang_fan_threshold))) ? - ";_OVERHANG_FAN_END\n" : ";_EXTRUDE_END\n"; + if (m_enable_cooling_markers) { + if (EXTRUDER_CONFIG(enable_overhang_bridge_fan)) { + //BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external perimeter + int overhang_threshold = EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none ? + Overhang_threshold_none : EXTRUDER_CONFIG(overhang_fan_threshold) - 1; + if ((EXTRUDER_CONFIG(overhang_fan_threshold) == Overhang_threshold_none && path.role() == erExternalPerimeter) || + path.get_overhang_degree() > overhang_threshold || + is_bridge(path.role())) + gcode += ";_OVERHANG_FAN_END\n"; + else + gcode += ";_EXTRUDE_END\n"; + } + else { + gcode += ";_EXTRUDE_END\n"; + } + } this->set_last_pos(path.last_point()); return gcode; @@ -4122,13 +4125,13 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) std::vector flush_matrix(cast(m_config.flush_volumes_matrix.values)); const unsigned int number_of_extruders = (unsigned int)(sqrt(flush_matrix.size()) + EPSILON); assert(m_writer.extruder()->id() < number_of_extruders); - assert(new_retract_length < number_of_extruders); int previous_extruder_id = m_writer.extruder()->id(); old_retract_length = m_config.retraction_length.get_at(previous_extruder_id); old_retract_length_toolchange = m_config.retract_length_toolchange.get_at(previous_extruder_id); old_filament_temp = this->on_first_layer()? m_config.nozzle_temperature_initial_layer.get_at(previous_extruder_id) : m_config.nozzle_temperature.get_at(previous_extruder_id); wipe_volume = flush_matrix[previous_extruder_id * number_of_extruders + extruder_id]; + wipe_volume *= m_config.flush_multiplier; old_filament_e_feedrate = (int)(60.0 * m_config.filament_max_volumetric_speed.get_at(previous_extruder_id) / filament_area); old_filament_e_feedrate = old_filament_e_feedrate == 0 ? 100 : old_filament_e_feedrate; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index e3c1aec259..ccf254c571 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -492,7 +492,7 @@ private: static bool gcode_label_objects; // BBS - void get_bed_temperature(const int extruder_id, const bool is_first_layer, std::vector& temps_per_bed, int& default_temp) const; + int get_bed_temperature(const int extruder_id, const bool is_first_layer, const BedType bed_type) const; std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1); void print_machine_envelope(GCodeOutputStream &file, Print &print); diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index dfdd19f031..6bfe742db4 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -722,7 +722,7 @@ std::string CoolingBuffer::apply_layer_cooldown( new_gcode.reserve(gcode.size() * 2); bool overhang_fan_control= false; int overhang_fan_speed = 0; - auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &overhang_fan_control, &overhang_fan_speed]() { + auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &overhang_fan_control, &overhang_fan_speed](bool immediately_apply) { #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder) int fan_min_speed = EXTRUDER_CONFIG(fan_min_speed); int fan_speed_new = EXTRUDER_CONFIG(reduce_fan_stop_start_freq) ? fan_min_speed : 0; @@ -771,18 +771,20 @@ std::string CoolingBuffer::apply_layer_cooldown( m_fan_speed = fan_speed_new; //BBS m_current_fan_speed = fan_speed_new; - new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed); + if (immediately_apply) + new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed); } //BBS if (additional_fan_speed_new != m_additional_fan_speed && m_config.auxiliary_fan.value) { m_additional_fan_speed = additional_fan_speed_new; - new_gcode += GCodeWriter::set_additional_fan(m_additional_fan_speed); + if (immediately_apply) + new_gcode += GCodeWriter::set_additional_fan(m_additional_fan_speed); } }; const char *pos = gcode.c_str(); int current_feedrate = 0; - change_extruder_set_fan(); + change_extruder_set_fan(true); for (const CoolingLine *line : lines) { const char *line_start = gcode.c_str() + line->line_start; const char *line_end = gcode.c_str() + line->line_end; @@ -792,7 +794,7 @@ std::string CoolingBuffer::apply_layer_cooldown( unsigned int new_extruder = (unsigned int)atoi(line_start + m_toolchange_prefix.size()); if (new_extruder != m_current_extruder) { m_current_extruder = new_extruder; - change_extruder_set_fan(); + change_extruder_set_fan(false); //BBS: will force to resume fan speed when filament change is finished } new_gcode.append(line_start, line_end - line_start); } else if (line->type & CoolingLine::TYPE_OVERHANG_FAN_START) { diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index a1bd906b6d..80d77be068 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -36,6 +36,7 @@ static const float DEFAULT_TRAVEL_ACCELERATION = 1250.0f; 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 int DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE = 0; static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero(); @@ -472,7 +473,16 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st PrintEstimatedStatistics::ETimeMode mode = static_cast(i); if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) { char buf[128]; - sprintf(buf, "; estimated printing time: %s\n", get_time_dhms(machine.time).c_str()); + if(!s_IsBBLPrinter) + sprintf(buf, "; estimated printing time: %s\n", get_time_dhms(machine.time).c_str()); + else { + //sprintf(buf, "; estimated printing time (%s mode) = %s\n", + // (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent", + // get_time_dhms(machine.time).c_str()); + sprintf(buf, "; model printing time: %s; total estimated time: %s\n", + get_time_dhms(machine.time - machine.roles_time[ExtrusionRole::erCustom]).c_str(), + get_time_dhms(machine.time).c_str()); + } ret += buf; } } @@ -794,6 +804,7 @@ void GCodeProcessorResult::reset() { extruders_count = 0; extruder_colors = std::vector(); 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); custom_gcode_per_print_z = std::vector(); warnings.clear(); @@ -899,14 +910,17 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_extruder_offsets.resize(extruders_count); m_extruder_colors.resize(extruders_count); m_result.filament_diameters.resize(extruders_count); + m_result.required_nozzle_HRC.resize(extruders_count); m_result.filament_densities.resize(extruders_count); m_result.filament_vitrification_temperature.resize(extruders_count); m_extruder_temps.resize(extruders_count); + m_result.nozzle_hrc = static_cast(config.nozzle_hrc.getInt()); for (size_t i = 0; i < extruders_count; ++ i) { m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast().eval(), 0.f); m_extruder_colors[i] = static_cast(i); m_result.filament_diameters[i] = static_cast(config.filament_diameter.get_at(i)); + 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)); } @@ -958,6 +972,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (nozzle_volume != nullptr) m_nozzle_volume = nozzle_volume->value; + const ConfigOptionInt *nozzle_HRC = config.option("nozzle_hrc"); + if (nozzle_HRC != nullptr) m_result.nozzle_hrc = nozzle_HRC->value; + const ConfigOptionEnum* gcode_flavor = config.option>("gcode_flavor"); if (gcode_flavor != nullptr) m_flavor = gcode_flavor->value; @@ -1001,6 +1018,18 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) } } + const ConfigOptionInts *filament_HRC = config.option("required_nozzle_HRC"); + if (filament_HRC != nullptr) { + m_result.required_nozzle_HRC.clear(); + m_result.required_nozzle_HRC.resize(filament_HRC->values.size()); + for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast(filament_HRC->values[i]); } + } + + if (m_result.required_nozzle_HRC.size() < m_result.extruders_count) { + for (size_t i = m_result.required_nozzle_HRC.size(); i < m_result.extruders_count; ++i) { m_result.required_nozzle_HRC.emplace_back(DEFAULT_FILAMENT_HRC); + } + } + const ConfigOptionFloats* filament_densities = config.option("filament_density"); if (filament_densities != nullptr) { m_result.filament_densities.clear(); @@ -2720,10 +2749,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) get_retract_acceleration(static_cast(i)) : get_acceleration(static_cast(i))); + //BBS for (unsigned char a = X; a <= E; ++a) { float axis_max_acceleration = get_axis_max_acceleration(static_cast(i), static_cast(a)); if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration) - acceleration = axis_max_acceleration; + acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance); } block.acceleration = acceleration; @@ -2752,23 +2782,30 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) float v_factor = 1.0f; bool limited = false; - //BBS: currently jerk in x,y,z axis are combined to one value and be limited together in MC side - //So we only need to handle Z axis for (unsigned char a = X; a <= E; ++a) { // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. - //BBS - float jerk = 0; if (a == X) { Vec3f exit_v = prev.feedrate * (prev.exit_direction); - exit_v(2, 0) = 0; if (prev_speed_larger) exit_v *= smaller_speed_factor; Vec3f entry_v = block.feedrate_profile.cruise * (curr.enter_direction); Vec3f jerk_v = entry_v - exit_v; - jerk = jerk_v.norm(); - } else if (a == Y || a == Z) { + jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z())); + Vec3f max_xyz_jerk_v = get_xyz_max_jerk(static_cast(i)); + + for (size_t i = 0; i < 3; i++) + { + if (jerk_v[i] > max_xyz_jerk_v[i]) { + v_factor *= max_xyz_jerk_v[i] / jerk_v[i]; + jerk_v *= v_factor; + limited = true; + } + } + } + else if (a == Y || a == Z) { continue; - } else { + } + else { float v_exit = prev.axis_feedrate[a]; float v_entry = curr.axis_feedrate[a]; @@ -2781,7 +2818,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) } // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction. - jerk = + float jerk = (v_exit > v_entry) ? (((v_entry > 0.0f) || (v_exit < 0.0f)) ? // coasting @@ -2794,12 +2831,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) (v_entry - v_exit) : // axis reversal std::max(-v_exit, v_entry)); - } - float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); - if (jerk > axis_max_jerk) { - v_factor *= axis_max_jerk / jerk; - limited = true; + + float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); + if (jerk > axis_max_jerk) { + v_factor *= axis_max_jerk / jerk; + limited = true; + } } } @@ -2866,7 +2904,8 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) } else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { m_seams_detector.activate(true); - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); + Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f}; + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); } // store move @@ -3147,22 +3186,30 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) float v_factor = 1.0f; bool limited = false; - //BBS: currently jerk in x,y,z axis are combined to one value and be limited together in MC side - //So we only need to handle Z axis for (unsigned char a = X; a <= E; ++a) { //BBS: Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. - float jerk = 0; if (a == X) { Vec3f exit_v = prev.feedrate * (prev.exit_direction); - exit_v(2, 0) = 0; if (prev_speed_larger) exit_v *= smaller_speed_factor; Vec3f entry_v = block.feedrate_profile.cruise * (curr.enter_direction); Vec3f jerk_v = entry_v - exit_v; - jerk = jerk_v.norm(); - } else if (a == Y || a == Z) { + jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z())); + Vec3f max_xyz_jerk_v = get_xyz_max_jerk(static_cast(i)); + + for (size_t i = 0; i < 3; i++) + { + if (jerk_v[i] > max_xyz_jerk_v[i]) { + v_factor *= max_xyz_jerk_v[i] / jerk_v[i]; + jerk_v *= v_factor; + limited = true; + } + } + } + else if (a == Y || a == Z) { continue; - } else { + } + else { float v_exit = prev.axis_feedrate[a]; float v_entry = curr.axis_feedrate[a]; @@ -3175,7 +3222,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) } //BBS: Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction. - jerk = + float jerk = (v_exit > v_entry) ? (((v_entry > 0.0f) || (v_exit < 0.0f)) ? //BBS: coasting @@ -3187,12 +3234,13 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) (v_entry - v_exit) : //BBS: axis reversal std::max(-v_exit, v_entry)); - } - float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); - if (jerk > axis_max_jerk) { - v_factor *= axis_max_jerk / jerk; - limited = true; + + float axis_max_jerk = get_axis_max_jerk(static_cast(i), static_cast(a)); + if (jerk > axis_max_jerk) { + v_factor *= axis_max_jerk / jerk; + limited = true; + } } } @@ -3229,18 +3277,20 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) } //BBS: seam detector + Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f}; + if (m_seams_detector.is_active()) { //BBS: check for seam starting vertex - if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); + if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) { + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); + } //BBS: check for seam ending vertex and store the resulting move else if ((type != EMoveType::Extrude || (m_extrusion_role != erExternalPerimeter && m_extrusion_role != erOverhangPerimeter)) && m_seams_detector.has_first_vertex()) { auto set_end_position = [this](const Vec3f& pos) { m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z(); }; - const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]); - const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id]; + const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset; const std::optional first_vertex = m_seams_detector.get_first_vertex(); //BBS: the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later @@ -3255,7 +3305,7 @@ void GCodeProcessor::process_G2_G3(const GCodeReader::GCodeLine& line) } else if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter) { m_seams_detector.activate(true); - m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]); + m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id] - plate_offset); } //BBS: store move store_move_vertex(type, m_move_path_type); @@ -3821,7 +3871,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type) m_interpolation_points[i] = Vec3f(m_interpolation_points[i].x() + m_x_offset, m_interpolation_points[i].y() + m_y_offset, - m_processing_start_custom_gcode ? m_zero_layer_height : m_interpolation_points[i].z()) + + m_processing_start_custom_gcode ? m_first_layer_height : m_interpolation_points[i].z()) + m_extruder_offsets[m_extruder_id]; } @@ -3832,7 +3882,7 @@ void GCodeProcessor::store_move_vertex(EMoveType type, EMovePathType path_type) m_extruder_id, m_cp_color.current, //BBS: add plate's offset to the rendering vertices - Vec3f(m_end_position[X] + m_x_offset, m_end_position[Y] + m_y_offset, m_processing_start_custom_gcode ? m_zero_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id], + Vec3f(m_end_position[X] + m_x_offset, m_end_position[Y] + m_y_offset, m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id], static_cast(m_end_position[E] - m_start_position[E]), m_feedrate, m_width, @@ -3917,6 +3967,13 @@ float GCodeProcessor::get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode } } +Vec3f GCodeProcessor::get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const +{ + return Vec3f(get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, static_cast(mode)), + get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, static_cast(mode)), + get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, static_cast(mode))); +} + float GCodeProcessor::get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const { size_t id = static_cast(mode); @@ -4074,7 +4131,27 @@ void GCodeProcessor::update_slice_warnings() } if (!warning.params.empty()) { - warning.msg = BED_TEMP_TOO_HIGH_THAN_FILAMENT; + warning.msg = BED_TEMP_TOO_HIGH_THAN_FILAMENT; + warning.error_code = "1000C001"; + m_result.warnings.push_back(warning); + } + + //bbs:HRC checker + warning.params.clear(); + warning.level=1; + if (m_result.nozzle_hrc!=0) { + for (size_t i = 0; i < used_extruders.size(); i++) { + int HRC=0; + if (used_extruders[i] < m_result.required_nozzle_HRC.size()) + HRC = m_result.required_nozzle_HRC[used_extruders[i]]; + if (HRC != 0 && (m_result.nozzle_hrc params; // extra msg info }; @@ -152,12 +155,14 @@ namespace Slic3r { size_t extruders_count; std::vector extruder_colors; std::vector filament_diameters; + std::vector required_nozzle_HRC; std::vector filament_densities; std::vector filament_vitrification_temperature; PrintEstimatedStatistics print_statistics; std::vector custom_gcode_per_print_z; //BBS std::vector warnings; + int nozzle_hrc; #if ENABLE_GCODE_VIEWER_STATISTICS int64_t time{ 0 }; @@ -578,7 +583,6 @@ namespace Slic3r { std::vector m_extruder_offsets; GCodeFlavor m_flavor; float m_nozzle_volume; - AxisCoords m_start_position; // mm AxisCoords m_end_position; // mm AxisCoords m_origin; // mm @@ -829,6 +833,7 @@ namespace Slic3r { float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const; float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const; float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const; + Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const; float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; void set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value); float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const; @@ -838,7 +843,6 @@ namespace Slic3r { float get_filament_load_time(size_t extruder_id); float get_filament_unload_time(size_t extruder_id); int get_filament_vitrification_temperature(size_t extrude_id); - void process_custom_gcode_time(CustomGCode::Type code); void process_filaments(CustomGCode::Type code); diff --git a/src/libslic3r/GCode/ThumbnailData.cpp b/src/libslic3r/GCode/ThumbnailData.cpp index a5941bff16..d895c0d95f 100644 --- a/src/libslic3r/GCode/ThumbnailData.cpp +++ b/src/libslic3r/GCode/ThumbnailData.cpp @@ -12,6 +12,7 @@ void ThumbnailData::set(unsigned int w, unsigned int h) width = w; height = h; // defaults to white texture + pixels.clear(); pixels = std::vector(width * height * 4, 255); } } diff --git a/src/libslic3r/GCode/ThumbnailData.hpp b/src/libslic3r/GCode/ThumbnailData.hpp index 8e19598e93..fef480704d 100644 --- a/src/libslic3r/GCode/ThumbnailData.hpp +++ b/src/libslic3r/GCode/ThumbnailData.hpp @@ -76,6 +76,7 @@ struct PlateBBoxData bool is_seq_print = false; int first_extruder = 0; float nozzle_diameter = 0.4; + std::string bed_type; // version 1: use view type ColorPrint (filament color) // version 2: use view type FilamentId (filament id) int version = 2; @@ -88,6 +89,7 @@ struct PlateBBoxData j["first_extruder"] = first_extruder; j["nozzle_diameter"] = nozzle_diameter; j["version"] = version; + j["bed_type"] = bed_type; for (const auto& bbox : bbox_objs) { nlohmann::json j_bbox; bbox.to_json(j_bbox); @@ -102,6 +104,7 @@ struct PlateBBoxData j.at("first_extruder").get_to(first_extruder); j.at("nozzle_diameter").get_to(nozzle_diameter); j.at("version").get_to(version); + j.at("bed_type").get_to(bed_type); for (auto& bbox_j : j.at("bbox_objects")) { BBoxData bbox_data; bbox_data.from_json(bbox_j); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index cbdca7e928..4467cf51a8 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -244,6 +244,45 @@ public: return (*this); } + WipeTowerWriter &rectangle_fill_box(const WipeTower* wipe_tower, const Vec2f &ld, float width, float height, const float f = 0.f) + { + bool need_change_flow = wipe_tower->need_thick_bridge_flow(ld.y()); + + Vec2f corners[4]; + corners[0] = ld; + corners[1] = ld + Vec2f(width, 0.f); + corners[2] = ld + Vec2f(width, height); + corners[3] = ld + Vec2f(0.f, height); + int index_of_closest = 0; + if (x() - ld.x() > ld.x() + width - x()) // closer to the right + index_of_closest = 1; + if (y() - ld.y() > ld.y() + height - y()) // closer to the top + index_of_closest = (index_of_closest == 0 ? 3 : 2); + + travel(corners[index_of_closest].x(), y()); // travel to the closest corner + travel(x(), corners[index_of_closest].y()); + + int i = index_of_closest; + bool flow_changed = false; + do { + ++i; + if (i == 4) i = 0; + if (need_change_flow) { + if (i == 1) { + // using bridge flow in bridge area, and add notes for gcode-check when flow changed + set_extrusion_flow(wipe_tower->extrusion_flow(0.2)); + append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(0.2) + "\n"); + flow_changed = true; + } else if (i == 2 && flow_changed) { + set_extrusion_flow(wipe_tower->get_extrusion_flow()); + append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); + } + } + extrude(corners[i], f); + } while (i != index_of_closest); + return (*this); + } + WipeTowerWriter& rectangle(const WipeTower::box_coordinates& box, const float f = 0.f) { rectangle(Vec2f(box.ld.x(), box.ld.y()), @@ -664,7 +703,7 @@ std::vector WipeTower::prime( return std::vector(); } -WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter) +WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter, bool first_toolchange_to_nonsoluble) { size_t old_tool = m_current_tool; @@ -733,6 +772,12 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per writer.rectangle(wt_box); writer.travel(initial_position); } + + if (first_toolchange_to_nonsoluble) { + 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. ++ m_num_tool_changes; } else @@ -974,6 +1019,12 @@ void WipeTower::toolchange_Wipe( // Increase flow on first layer, slow down print. writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.15f : 1.f)) .append("; CP TOOLCHANGE WIPE\n"); + + // BBS: add the note for gcode-check, when the flow changed, the width should follow the change + if (is_first_layer()) { + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(1.15 * m_perimeter_width) + "\n"); + } + const float& xl = cleaning_box.ld.x(); const float& xr = cleaning_box.rd.x(); @@ -1005,6 +1056,7 @@ void WipeTower::toolchange_Wipe( writer.travel(xl, writer.y() + dy); #endif + bool need_change_flow = false; // now the wiping itself: for (int i = 0; true; ++i) { if (i!=0) { @@ -1014,11 +1066,24 @@ void WipeTower::toolchange_Wipe( else wipe_speed = std::min(target_speed, wipe_speed + 50.f); } + // BBS: check the bridging area and use the bridge flow + if (need_change_flow || need_thick_bridge_flow(writer.y())) { + writer.set_extrusion_flow(extrusion_flow(0.2)); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(0.2) + "\n"); + need_change_flow = true; + } + if (m_left_to_right) writer.extrude(xr + 0.25f * m_perimeter_width, writer.y(), wipe_speed); else writer.extrude(xl - 0.25f * m_perimeter_width, writer.y(), wipe_speed); + // BBS: recover the flow in non-bridging area + if (need_change_flow) { + writer.set_extrusion_flow(m_extrusion_flow); + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n"); + } + if (writer.y() - float(EPSILON) > cleaning_box.lu.y()) break; // in case next line would not fit @@ -1044,6 +1109,10 @@ void WipeTower::toolchange_Wipe( m_left_to_right = !m_left_to_right; writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. + // BBS: add the note for gcode-check when the flow changed + if (is_first_layer()) { + writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) + std::to_string(m_perimeter_width) + "\n"); + } } @@ -1099,7 +1168,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool // inner perimeter of the sparse section, if there is space for it: if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON) - writer.rectangle(fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate); + writer.rectangle_fill_box(this, fill_box.ld, fill_box.rd.x() - fill_box.ld.x(), fill_box.ru.y() - fill_box.rd.y(), feedrate); // we are in one of the corners, travel to ld along the perimeter: if (writer.x() > fill_box.ld.x() + EPSILON) writer.travel(fill_box.ld.x(), writer.y()); @@ -1241,6 +1310,10 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in float depth = 0.f; float width = m_wipe_tower_width - 2 * m_perimeter_width; + // BBS: if the wipe tower width is too small, the depth will be infinity + if (width <= EPSILON) + return; + // BBS: remove old filament ramming and first line #if 0 float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), @@ -1518,7 +1591,11 @@ void WipeTower::generate(std::vector> & finish_layer_tcr = finish_layer(false, layer.extruder_fill); } else { - layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool)); + if (idx == -1 && i == 0) { + layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool, false, true)); + } else { + layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool)); + } } } @@ -1585,4 +1662,30 @@ WipeTower::ToolChangeResult WipeTower::only_generate_out_wall() return construct_tcr(writer, false, old_tool, true, 0.f); } +bool WipeTower::get_floating_area(float &start_pos_y, float &end_pos_y) const { + if (m_layer_info == m_plan.begin() || (m_layer_info - 1) == m_plan.begin()) + return false; + + float last_layer_fill_box_y = (m_layer_info - 1)->toolchanges_depth() + m_perimeter_width; + float last_layer_wipe_depth = (m_layer_info - 1)->depth; + if (last_layer_wipe_depth - last_layer_fill_box_y <= 2 * m_perimeter_width) + return false; + + start_pos_y = last_layer_fill_box_y + m_perimeter_width; + end_pos_y = last_layer_wipe_depth - m_perimeter_width; + + return true; +} + +bool WipeTower::need_thick_bridge_flow(float pos_y) const { + if (m_extrusion_flow >= extrusion_flow(0.2)) + return false; + + float y_min = 0., y_max = 0.; + if (get_floating_area(y_min, y_max)) { + return pos_y > y_min && pos_y < y_max; + } + return false; +} + } // namespace Slic3r diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index de84a604a5..0c4175cc6b 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -217,12 +217,23 @@ public: // Returns gcode for a toolchange and a final print head position. // On the first layer, extrude a brim around the future wipe tower first. // BBS - ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false); + ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false, bool first_toolchange_to_nonsoluble = false); // Fill the unfilled space with a sparse infill. // Call this method only if layer_finished() is false. ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true); + // Calculates extrusion flow needed to produce required line width for given layer height + float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow + { + if (layer_height < 0) return m_extrusion_flow; + return layer_height * (m_perimeter_width - layer_height * (1.f - float(M_PI) / 4.f)) / filament_area(); + } + + bool get_floating_area(float& start_pos_y, float& end_pos_y) const; + bool need_thick_bridge_flow(float pos_y) const; + float get_extrusion_flow() const { return m_extrusion_flow; } + // Is the current layer finished? bool layer_finished() const { return m_current_layer_finished; @@ -336,14 +347,6 @@ private: bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } - // Calculates extrusion flow needed to produce required line width for given layer height - float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow - { - if ( layer_height < 0 ) - return m_extrusion_flow; - return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area(); - } - // Calculates length of extrusion line to extrude given volume float volume_to_length(float volume, float line_width, float layer_height) const { return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)))); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index e281f38b03..d02e5ae170 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -125,13 +125,12 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in } // BBS -std::string GCodeWriter::set_bed_temperature(std::vector temps_per_bed, int default_temp, bool wait) +std::string GCodeWriter::set_bed_temperature(int temperature, bool wait) { - if (temps_per_bed == m_last_bed_temperature && (! wait || m_last_bed_temperature_reached)) + if (temperature == m_last_bed_temperature && (! wait || m_last_bed_temperature_reached)) return std::string(); - bool target_temp_changed = (temps_per_bed != m_last_bed_temperature); - m_last_bed_temperature = temps_per_bed; + m_last_bed_temperature = temperature; m_last_bed_temperature_reached = wait; std::string code, comment; @@ -146,7 +145,7 @@ std::string GCodeWriter::set_bed_temperature(std::vector temps_per_bed, int comment = "set bed temperature"; } - gcode << code << " S" << default_temp << " ; " << comment << "\n"; + gcode << code << " S" << temperature << " ; " << comment << "\n"; return gcode.str(); } diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 2e2d1bc1f3..4509f1a992 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -43,8 +43,7 @@ public: std::string preamble(); std::string postamble() const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; - // BBS - std::string set_bed_temperature(std::vector temps_per_bed, int default_temp, bool wait = false); + std::string set_bed_temperature(int temperature, bool wait = false); std::string set_acceleration(unsigned int acceleration); std::string set_jerk_xy(unsigned int jerk); std::string set_pressure_advance(double pa) const; @@ -114,8 +113,7 @@ private: //BBS unsigned int m_last_additional_fan_speed; - // BBS - std::vector m_last_bed_temperature; + int m_last_bed_temperature; bool m_last_bed_temperature_reached; double m_lifted; diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 0c2193330e..a72e6e10cb 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -65,7 +65,7 @@ public: // ordered collection of extrusion paths to fill surfaces // (this collection contains only ExtrusionEntityCollection objects) ExtrusionEntityCollection fills; - + Flow flow(FlowRole role) const; Flow flow(FlowRole role, double layer_height) const; Flow bridging_flow(FlowRole role, bool thick_bridge = false) const; @@ -110,7 +110,7 @@ private: const PrintRegion *m_region; }; -class Layer +class Layer { public: // Sequential index of this layer in PrintObject::m_layers, offsetted by the number of raft layers. @@ -132,7 +132,7 @@ public: mutable ExPolygons cantilevers; mutable std::map sharp_tails_height; - // Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry + // Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry // (with possibly differing extruder ID and slicing parameters) and merged. // For the first layer, if the Elephant foot compensation is applied, this lslice is uncompensated, therefore // it includes the Elephant foot effect, thus it corresponds to the shape of the printed 1st layer. @@ -149,7 +149,7 @@ public: LayerRegion* add_region(const PrintRegion *print_region); const LayerRegionPtrs& regions() const { return m_regions; } // Test whether whether there are any slices assigned to this layer. - bool empty() const; + bool empty() const; void make_slices(); // Backup and restore raw sliced regions if needed. //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. @@ -209,7 +209,7 @@ private: LayerRegionPtrs m_regions; }; -class SupportLayer : public Layer +class SupportLayer : public Layer { public: // Polygons covered by the supports: base, interface and contact areas. @@ -248,14 +248,22 @@ public: ExPolygons roof_1st_layer; // the layer just below roof. When working with PolySupport, this layer should be printed with regular material ExPolygons floor_areas; ExPolygons base_areas; + ExPolygons roof_gap_areas; // the areas in the gap between support roof and overhang - enum AreaType { + enum AreaType { BaseType=0, RoofType=1, FloorType=2, Roof1stLayer=3 }; - std::vector> area_groups; + struct AreaGroup + { + ExPolygon *area; + int type; + int dist_to_top; + AreaGroup(ExPolygon *a, int t, int d) : area(a), type(t), dist_to_top(d) {} + }; + std::vector area_groups; enum OverhangType { Detected=0, diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 4ab0be7d76..a02d3e42c1 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -105,8 +105,11 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec g.ext_perimeter_flow = this->flow(frExternalPerimeter); g.overhang_flow = this->bridging_flow(frPerimeter, object_config.thick_bridges); g.solid_infill_flow = this->flow(frSolidInfill); - - g.process(); + + if (this->layer()->object()->config().wall_generator.value == PerimeterGeneratorType::Arachne && !spiral_mode) + g.process_arachne(); + else + g.process_classic(); } //#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. @@ -225,7 +228,9 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly break; } // Grown by 3mm. - Polygons polys = offset(bridges[i].expolygon, bridge_margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS); + //BBS: eliminate too narrow area to avoid generating bridge on top layer when wall loop is 1 + //Polygons polys = offset(bridges[i].expolygon, bridge_margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS); + Polygons polys = offset2({ bridges[i].expolygon }, -scale_(nozzle_diameter * 0.1), bridge_margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS); if (idx_island == -1) { BOOST_LOG_TRIVIAL(trace) << "Bridge did not fall into the source region!"; } else { diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 33549b1acb..47e8c50f51 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -14,6 +14,7 @@ #include "Format/OBJ.hpp" #include "Format/STL.hpp" #include "Format/STEP.hpp" +#include "Format/svg.hpp" // BBS #include "FaceDetector.hpp" @@ -137,7 +138,7 @@ Model::~Model() // Loading model from a file, it may be a simple geometry file as STL or OBJ, however it may be a project file as well. Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, LoadStrategy options, PlateDataPtrs* plate_data, std::vector* project_presets, bool *is_xxx, Semver* file_version, Import3mfProgressFn proFn, - ImportstlProgressFn stlFn, ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project) + ImportstlProgressFn stlFn, ImportStepProgressFn stepFn, StepIsUtf8Fn stepIsUtf8Fn, BBLProject* project, int plate_id) { Model model; @@ -159,6 +160,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c file_version = &temp_version; bool result = false; + std::string message; if (boost::algorithm::iends_with(input_file, ".stp") || boost::algorithm::iends_with(input_file, ".step")) result = load_step(input_file.c_str(), &model, stepFn, stepIsUtf8Fn); @@ -166,6 +168,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c result = load_stl(input_file.c_str(), &model, nullptr, stlFn); else if (boost::algorithm::iends_with(input_file, ".obj")) result = load_obj(input_file.c_str(), &model); + else if (boost::algorithm::iends_with(input_file, ".svg")) + result = load_svg(input_file.c_str(), &model, message); //BBS: remove the old .amf.xml files //else if (boost::algorithm::iends_with(input_file, ".amf") || boost::algorithm::iends_with(input_file, ".amf.xml")) else if (boost::algorithm::iends_with(input_file, ".amf")) @@ -176,12 +180,16 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c // BBS: backup & restore //FIXME options & LoadStrategy::CheckVersion ? //BBS: is_xxx is used for is_bbs_3mf when load 3mf - result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, is_xxx, file_version, proFn, options, project); + result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, is_xxx, file_version, proFn, options, project, plate_id); else throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .amf(.xml) extension."); - if (! result) - throw Slic3r::RuntimeError("Loading of a model file failed."); + if (!result) { + if (message.empty()) + throw Slic3r::RuntimeError("Loading of a model file failed."); + else + throw Slic3r::RuntimeError(message); + } if (model.objects.empty()) throw Slic3r::RuntimeError("The supplied file couldn't be read because it's empty"); @@ -203,7 +211,8 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c //BBS: add part plate related logic // BBS: backup & restore // Loading model from a file (3MF or AMF), not from a simple geometry file (STL or OBJ). -Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, En3mfType& out_file_type, LoadStrategy options, PlateDataPtrs* plate_data, std::vector* project_presets, Semver* file_version, Import3mfProgressFn proFn, BBLProject *project) +Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, En3mfType& out_file_type, LoadStrategy options, + PlateDataPtrs* plate_data, std::vector* project_presets, Semver* file_version, Import3mfProgressFn proFn, BBLProject *project) { assert(config != nullptr); assert(config_substitutions != nullptr); @@ -2911,13 +2920,14 @@ double getTemperatureFromExtruder(const ModelVolumePtrs objectVolumes) { double ModelInstance::get_auto_brim_width() const { + return 0.; double adhcoeff = getadhesionCoeff(object->volumes); double DeltaT = getTemperatureFromExtruder(object->volumes); // get auto brim width (Note even if the global brim_type=btOuterBrim, we can still go into this branch) return get_auto_brim_width(DeltaT, adhcoeff); } -void ModelInstance::get_arrange_polygon(void* ap) const +void ModelInstance::get_arrange_polygon(void *ap, const Slic3r::DynamicPrintConfig &config_global) const { // static const double SIMPLIFY_TOLERANCE_MM = 0.1; @@ -2956,6 +2966,16 @@ void ModelInstance::get_arrange_polygon(void* ap) const ret.extrude_ids = volume->get_extruders(); if (ret.extrude_ids.empty()) //the default extruder ret.extrude_ids.push_back(1); + + // get per-object support extruders + auto op = object->get_config_value(config_global, "enable_support"); + bool is_support_enabled = op && op->getBool(); + if (is_support_enabled) { + auto op1 = object->get_config_value(config_global, "support_filament"); + auto op2 = object->get_config_value(config_global, "support_interface_filament"); + if (op1) ret.extrude_ids.push_back(op1->getInt()); + if (op2) ret.extrude_ids.push_back(op2->getInt()); + } } indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d661f208e6..f8b88ae0b9 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -1050,7 +1050,7 @@ public: // BBS void set_offset_to_assembly(const Vec3d& offset) { m_offset_to_assembly = offset; } - Vec3d get_offset_to_assembly() { return m_offset_to_assembly; } + Vec3d get_offset_to_assembly() const { return m_offset_to_assembly; } const Vec3d& get_offset() const { return m_transformation.get_offset(); } double get_offset(Axis axis) const { return m_transformation.get_offset(axis); } @@ -1111,7 +1111,7 @@ public: // Getting the input polygon for arrange // We use void* as input type to avoid including Arrange.hpp in Model.hpp. - void get_arrange_polygon(void* arrange_polygon) const; + void get_arrange_polygon(void *arrange_polygon, const Slic3r::DynamicPrintConfig &config = Slic3r::DynamicPrintConfig()) const; // Apply the arrange result on the ModelInstance void apply_arrange_result(const Vec2d& offs, double rotation) @@ -1213,6 +1213,7 @@ struct GlobalSpeedMap double supportSpeed; double smallPerimeterSpeed; double maxSpeed; + Polygon bed_poly; }; /* info in ModelDesignInfo can not changed after initialization */ @@ -1234,12 +1235,15 @@ public: std::string copyright; // utf8 format std::string model_name; // utf8 format + std::map metadata_items; // other meta data items + void load(ModelInfo &info) { this->cover_file = info.cover_file; this->license = info.license; this->description = info.description; this->copyright = info.copyright; this->model_name = info.model_name; + this->metadata_items = info.metadata_items; } }; @@ -1300,11 +1304,12 @@ public: DynamicPrintConfig* config = nullptr, ConfigSubstitutionContext* config_substitutions = nullptr, LoadStrategy options = LoadStrategy::AddDefaultInstances, PlateDataPtrs* plate_data = nullptr, std::vector* project_presets = nullptr, bool* is_xxx = nullptr, Semver* file_version = nullptr, Import3mfProgressFn proFn = nullptr, - ImportstlProgressFn stlFn = nullptr, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr); + ImportstlProgressFn stlFn = nullptr, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn stepIsUtf8Fn = nullptr, BBLProject* project = nullptr, int plate_id = 0); // BBS static double findMaxSpeed(const ModelObject* object); static double getThermalLength(const ModelVolume* modelVolumePtr); static double getThermalLength(const std::vector modelVolumePtrs); + static Polygon getBedPolygon() { return Model::printSpeedMap.bed_poly; } // BBS: backup static Model read_from_archive( diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index a1c43cd39e..5acdb6fb96 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -88,9 +88,9 @@ void duplicate_objects(Model &model, size_t copies_num) // Set up arrange polygon for a ModelInstance and Wipe tower template -arrangement::ArrangePolygon get_arrange_poly(T obj) +arrangement::ArrangePolygon get_arrange_poly(T obj, const Slic3r::DynamicPrintConfig& config) { - ArrangePolygon ap = obj.get_arrange_polygon(); + ArrangePolygon ap = obj.get_arrange_polygon(config); //BBS: always set bed_idx to 0 to use original transforms with no bed_idx //if this object is not arranged, it can keep the original transforms //ap.bed_idx = ap.translation.x() / bed_stride_x(plater); @@ -110,14 +110,14 @@ arrangement::ArrangePolygon get_arrange_poly(T obj) } template<> -arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst) +arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst, const Slic3r::DynamicPrintConfig& config) { - return get_arrange_poly(PtrWrapper{ inst }); + return get_arrange_poly(PtrWrapper{ inst },config); } ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::DynamicPrintConfig& config) { - ArrangePolygon ap = get_arrange_poly(PtrWrapper{ instance }); + ArrangePolygon ap = get_arrange_poly(PtrWrapper{ instance }, config); //BBS: add temperature information if (config.has("curr_bed_type")) { @@ -127,24 +127,25 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r:: const ConfigOptionInts* bed_opt = config.option(get_bed_temp_key(curr_bed_type)); if (bed_opt != nullptr) - ap.bed_temp = bed_opt->get_at(ap.extrude_ids.back()-1); + ap.bed_temp = bed_opt->get_at(ap.extrude_ids.front()-1); const ConfigOptionInts* bed_opt_1st_layer = config.option(get_bed_temp_1st_layer_key(curr_bed_type)); if (bed_opt_1st_layer != nullptr) - ap.first_bed_temp = bed_opt_1st_layer->get_at(ap.extrude_ids.back()-1); + ap.first_bed_temp = bed_opt_1st_layer->get_at(ap.extrude_ids.front()-1); } if (config.has("nozzle_temperature")) //get the print temperature - ap.print_temp = config.opt_int("nozzle_temperature", ap.extrude_ids.back() - 1); + ap.print_temp = config.opt_int("nozzle_temperature", ap.extrude_ids.front() - 1); if (config.has("nozzle_temperature_initial_layer")) //get the nozzle_temperature_initial_layer - ap.first_print_temp = config.opt_int("nozzle_temperature_initial_layer", ap.extrude_ids.back() - 1); + ap.first_print_temp = config.opt_int("nozzle_temperature_initial_layer", ap.extrude_ids.front() - 1); if (config.has("temperature_vitrification")) { - ap.vitrify_temp = config.opt_int("temperature_vitrification", ap.extrude_ids.back() - 1); + ap.vitrify_temp = config.opt_int("temperature_vitrification", ap.extrude_ids.front() - 1); } // get brim width auto obj = instance->get_object(); +#if 0 ap.brim_width = instance->get_auto_brim_width(); auto brim_type_ptr = obj->get_config_value>(config, "brim_type"); if (brim_type_ptr) { @@ -154,7 +155,9 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r:: else if (brim_type == btNoBrim) ap.brim_width = 0; } - +#else + ap.brim_width = 0; +#endif ap.height = obj->bounding_box().size().z(); ap.name = obj->name; diff --git a/src/libslic3r/ModelArrange.hpp b/src/libslic3r/ModelArrange.hpp index ab85fafdc7..b6e661f150 100644 --- a/src/libslic3r/ModelArrange.hpp +++ b/src/libslic3r/ModelArrange.hpp @@ -71,10 +71,10 @@ template struct PtrWrapper explicit PtrWrapper(T* p) : ptr{ p } {} - arrangement::ArrangePolygon get_arrange_polygon() const + arrangement::ArrangePolygon get_arrange_polygon(const Slic3r::DynamicPrintConfig &config = Slic3r::DynamicPrintConfig()) const { arrangement::ArrangePolygon ap; - ptr->get_arrange_polygon(&ap); + ptr->get_arrange_polygon(&ap, config); return ap; } @@ -86,12 +86,12 @@ template struct PtrWrapper }; template -arrangement::ArrangePolygon get_arrange_poly(T obj); +arrangement::ArrangePolygon get_arrange_poly(T obj, const DynamicPrintConfig &config = DynamicPrintConfig()); template<> -arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst); +arrangement::ArrangePolygon get_arrange_poly(ModelInstance* inst, const DynamicPrintConfig& config); -ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::DynamicPrintConfig& config); +ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const DynamicPrintConfig& config); } #endif // MODELARRANGE_HPP diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 46e31970f4..29fae2ce3d 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1100,8 +1100,12 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vector &lines) +static inline Polygon to_polygon(const std::vector> &id_to_lines) { + std::vector lines; + for (auto id_to_line : id_to_lines) + lines.emplace_back(id_to_line.second); + Polygon poly_out; poly_out.points.reserve(lines.size()); for (const Linef &line : lines) @@ -1109,6 +1113,112 @@ static inline Polygon to_polygon(const std::vector &lines) return poly_out; } + +static std::vector> get_all_next_arcs( + const MMU_Graph &graph, + std::vector &used_arcs, + const Linef &process_line, + const MMU_Graph::Arc &original_arc, + const int color) +{ + std::vector> all_next_arcs; + for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) { + std::vector next_continue_arc; + + const MMU_Graph::Arc & arc = graph.arcs[arc_idx]; + if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) + continue; + + if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color) + continue; + + if (arc.type == MMU_Graph::ARC_TYPE::BORDER && arc.color != color) + continue; + + Vec2d arc_line = graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point; + if (arc_line.norm() < 5) { // two points whose distance is less than 5 are considered as one point + Linef process_line_1(graph.nodes[arc.from_idx].point, graph.nodes[arc.to_idx].point); + std::vector> next_arcs = get_all_next_arcs(graph, used_arcs, process_line_1, arc, color); + if (next_arcs.empty()) + continue; + + for (std::vector &next_arc : next_arcs) { + next_continue_arc.emplace_back(&arc); + next_continue_arc.insert(next_continue_arc.end(), next_arc.begin(), next_arc.end()); + all_next_arcs.emplace_back(next_continue_arc); + } + } else { + next_continue_arc.emplace_back(&arc); + all_next_arcs.emplace_back(next_continue_arc); + } + } + return all_next_arcs; +} + +// two points that are very close are considered as one point +// std::vector contain the close points +static std::vector get_next_arc( + const MMU_Graph &graph, + std::vector &used_arcs, + const Linef &process_line, + const MMU_Graph::Arc &original_arc, + const int color) +{ + std::vector res; + + std::vector> all_next_arcs = get_all_next_arcs(graph, used_arcs, process_line, original_arc, color); + if (all_next_arcs.empty()) { + res.emplace_back(&original_arc); + return res; + } + + std::vector, double>> sorted_arcs; + for (auto next_arc : all_next_arcs) { + if (next_arc.empty()) + continue; + + Vec2d process_line_vec_n = (process_line.a - process_line.b).normalized(); + Vec2d neighbour_line_vec_n = (graph.nodes[next_arc.back()->to_idx].point - graph.nodes[next_arc.back()->from_idx].point).normalized(); + + double angle = ::acos(std::clamp(neighbour_line_vec_n.dot(process_line_vec_n), -1.0, 1.0)); + if (Slic3r::cross2(neighbour_line_vec_n, process_line_vec_n) < 0.0) + angle = 2.0 * (double) PI - angle; + + sorted_arcs.emplace_back(next_arc, angle); + } + + std::sort(sorted_arcs.begin(), sorted_arcs.end(), + [](std::pair, double> &l, std::pair, double> &r) -> bool { + return l.second < r.second; + }); + + // Try to return left most edge witch is unused + for (auto &sorted_arc : sorted_arcs) { + if (size_t arc_idx = sorted_arc.first.back() - &graph.arcs.front(); !used_arcs[arc_idx]) + return sorted_arc.first; + } + + if (sorted_arcs.empty()) { + res.emplace_back(&original_arc); + return res; + } + + return sorted_arcs.front().first; +} + +static bool is_profile_self_interaction(Polygon poly) +{ + auto lines = poly.lines(); + Point intersection; + for (int i = 0; i < lines.size(); ++i) { + for (int j = i + 2; j < std::min(lines.size(), lines.size() + i - 1); ++j) { + if (lines[i].intersection(lines[j], &intersection)) + return true; + } + } + return false; +} + // Returns list of polygons and assigned colors. // It iterates through all nodes on the border between two different colors, and from this point, // start selection always left most edges for every node to construct CCW polygons. @@ -1116,43 +1226,7 @@ static inline Polygon to_polygon(const std::vector &lines) static std::vector extract_colored_segments(const MMU_Graph &graph, const size_t num_extruders) { std::vector used_arcs(graph.arcs.size(), false); - // When there is no next arc, then is returned original_arc or edge with is marked as used - auto get_next = [&graph, &used_arcs](const Linef &process_line, const MMU_Graph::Arc &original_arc, const int color) -> const MMU_Graph::Arc & { - std::vector> sorted_arcs; - for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) { - const MMU_Graph::Arc &arc = graph.arcs[arc_idx]; - if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) - continue; - - // BBS - if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color) - continue; - - assert(original_arc.to_idx == arc.from_idx); - Vec2d process_line_vec_n = (process_line.a - process_line.b).normalized(); - Vec2d neighbour_line_vec_n = (graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point).normalized(); - - double angle = ::acos(std::clamp(neighbour_line_vec_n.dot(process_line_vec_n), -1.0, 1.0)); - if (Slic3r::cross2(neighbour_line_vec_n, process_line_vec_n) < 0.0) - angle = 2.0 * (double) PI - angle; - - sorted_arcs.emplace_back(&arc, angle); - } - - std::sort(sorted_arcs.begin(), sorted_arcs.end(), - [](std::pair &l, std::pair &r) -> bool { return l.second < r.second; }); - - // Try to return left most edge witch is unused - for (auto &sorted_arc : sorted_arcs) - if (size_t arc_idx = sorted_arc.first - &graph.arcs.front(); !used_arcs[arc_idx]) - return *sorted_arc.first; - - if (sorted_arcs.empty()) - return original_arc; - - return *(sorted_arcs.front().first); - }; - + auto all_arc_used = [&used_arcs](const MMU_Graph::Node &node) -> bool { return std::all_of(node.arc_idxs.cbegin(), node.arc_idxs.cend(), [&used_arcs](const size_t &arc_idx) -> bool { return used_arcs[arc_idx]; }); }; @@ -1166,29 +1240,58 @@ static std::vector extract_colored_segments(const MMU_Graph &graph, if (arc.type == MMU_Graph::ARC_TYPE::NON_BORDER || used_arcs[arc_idx]) continue; - Linef process_line(node.point, graph.nodes[arc.to_idx].point); + Linef process_line(graph.nodes[arc.from_idx].point, graph.nodes[arc.to_idx].point); used_arcs[arc_idx] = true; - std::vector face_lines; - face_lines.emplace_back(process_line); + std::vector> arc_id_to_face_lines; + arc_id_to_face_lines.emplace_back(std::make_pair(arc_idx, process_line)); Vec2d start_p = process_line.a; Linef p_vec = process_line; const MMU_Graph::Arc *p_arc = &arc; + bool flag = false; do { - const MMU_Graph::Arc& next = get_next(p_vec, *p_arc, arc.color); - size_t next_arc_idx = &next - &graph.arcs.front(); - face_lines.emplace_back(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); - if (used_arcs[next_arc_idx]) + std::vector nexts = get_next_arc(graph, used_arcs, p_vec, *p_arc, arc.color); + for (auto next : nexts) { + size_t next_arc_idx = next - &graph.arcs.front(); + if (used_arcs[next_arc_idx]) { + flag = true; + break; + } + } + + if (flag) break; - used_arcs[next_arc_idx] = true; - p_vec = Linef(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); - p_arc = &next; + for (auto next : nexts) { + size_t next_arc_idx = next - &graph.arcs.front(); + arc_id_to_face_lines.emplace_back(std::make_pair(next_arc_idx, Linef(graph.nodes[next->from_idx].point, graph.nodes[next->to_idx].point))); + used_arcs[next_arc_idx] = true; + } + + p_vec = Linef(graph.nodes[nexts.back()->from_idx].point, graph.nodes[nexts.back()->to_idx].point); + p_arc = nexts.back(); + } while (graph.nodes[p_arc->to_idx].point != start_p || !all_arc_used(graph.nodes[p_arc->to_idx])); - if (Polygon poly = to_polygon(face_lines); poly.is_counter_clockwise() && poly.is_valid()) + if (Polygon poly = to_polygon(arc_id_to_face_lines); poly.is_counter_clockwise() && poly.is_valid()) { expolygons_segments[arc.color].emplace_back(std::move(poly)); + } else{ + while (arc_id_to_face_lines.size() > 1) + { + auto id_to_line = arc_id_to_face_lines.back(); + used_arcs[id_to_line.first] = false; + arc_id_to_face_lines.pop_back(); + Linef add_line(arc_id_to_face_lines.back().second.b, arc_id_to_face_lines.front().second.a); + arc_id_to_face_lines.emplace_back(std::make_pair(-1, add_line)); + Polygon poly = to_polygon(arc_id_to_face_lines); + if (!is_profile_self_interaction(poly) && poly.is_counter_clockwise() && poly.is_valid()) { + expolygons_segments[arc.color].emplace_back(std::move(poly)); + break; + } + arc_id_to_face_lines.pop_back(); + } + } } } return expolygons_segments; diff --git a/src/libslic3r/Orient.cpp b/src/libslic3r/Orient.cpp index a1285daf1f..b7a6d619e6 100644 --- a/src/libslic3r/Orient.cpp +++ b/src/libslic3r/Orient.cpp @@ -57,16 +57,19 @@ namespace orientation { // management and spatial index structures for acceleration. class AutoOrienter { public: + int face_count_hull; OrientMesh *orient_mesh = NULL; TriangleMesh* mesh; TriangleMesh mesh_convex_hull; - Eigen::MatrixXf normals, normals_hull; + Eigen::MatrixXf normals, normals_quantize, normals_hull, normals_hull_quantize; Eigen::VectorXf areas, areas_hull; Eigen::VectorXf is_apperance; // whether a facet is outer apperance Eigen::MatrixXf z_projected; Eigen::VectorXf z_max, z_max_hull; // max of projected z Eigen::VectorXf z_median; // median of projected z Eigen::VectorXf z_mean; // mean of projected z + std::vector face_normals; + std::vector face_normals_hull; OrientParams params; @@ -111,9 +114,9 @@ public: { orientations = { { 0,0,-1 } }; // original orientation - area_cumulation(normals, areas); + area_cumulation_accurate(face_normals, normals_quantize, areas, 10); - area_cumulation(normals_hull, areas_hull, 10); + area_cumulation_accurate(face_normals_hull, normals_hull_quantize, areas_hull, 10); add_supplements(); @@ -152,8 +155,23 @@ public: if (progressind) progressind(80); + //To avoid flipping, we need to verify if there are orientations with same unprintability. + Vec3f n1 = {0, 0, 1}; auto best_orientation = results_vector[0].first; + for (int i = 1; i< results_vector.size()-1; i++) { + if (abs(results_vector[i].second.unprintability - results_vector[0].second.unprintability) < EPSILON && abs(results_vector[0].first.dot(n1)-1) > EPSILON) { + if (abs(results_vector[i].first.dot(n1)-1) < EPSILON*EPSILON) { + best_orientation = n1; + break; + } + } + else { + break; + } + + } + BOOST_LOG_TRIVIAL(info) << std::fixed << std::setprecision(6) << "best:" << best_orientation.transpose() << ", costs:" << results_vector[0].second.field_values(); std::cout << std::fixed << std::setprecision(6) << "best:" << best_orientation.transpose() << ", costs:" << results_vector[0].second.field_values() << std::endl; @@ -166,17 +184,16 @@ public: { int face_count = mesh->facets_count(); auto its = mesh->its; - auto face_normals = its_face_normals(its); + face_normals = its_face_normals(its); areas = Eigen::VectorXf::Zero(face_count); is_apperance = Eigen::VectorXf::Zero(face_count); normals = Eigen::MatrixXf::Zero(face_count, 3); + normals_quantize = Eigen::MatrixXf::Zero(face_count, 3); for (size_t i = 0; i < face_count; i++) { float area = its.facet_area(i); - if (params.NEGL_FACE_SIZE > 0 && area < params.NEGL_FACE_SIZE) - continue; - - normals.row(i) = quantize_vec3f(face_normals[i]); + normals.row(i) = face_normals[i]; + normals_quantize.row(i) = quantize_vec3f(face_normals[i]); areas(i) = area; is_apperance(i) = (its.get_property(i).type == EnumFaceTypes::eExteriorAppearance); count_apperance += (is_apperance(i)==1); @@ -193,15 +210,17 @@ public: int face_count = mesh_convex_hull.facets_count(); auto its = mesh_convex_hull.its; - auto face_normals = its_face_normals(its); + face_count_hull = mesh_convex_hull.facets_count(); + face_normals_hull = its_face_normals(its); areas_hull = Eigen::VectorXf::Zero(face_count); - normals_hull = Eigen::MatrixXf::Zero(face_count, 3); + normals_hull = Eigen::MatrixXf::Zero(face_count_hull, 3); + normals_hull_quantize = Eigen::MatrixXf::Zero(face_count_hull, 3); for (size_t i = 0; i < face_count; i++) { float area = its.facet_area(i); - if (params.NEGL_FACE_SIZE > 0 && area < params.NEGL_FACE_SIZE) - continue; - normals_hull.row(i) = quantize_vec3f(face_normals[i]); + //We cannot use quantized vector here, the accumulated error will result in bad orientations. + normals_hull.row(i) = face_normals_hull[i]; + normals_hull_quantize.row(i) = quantize_vec3f(face_normals_hull[i]); areas_hull(i) = area; } } @@ -227,10 +246,41 @@ public: for (size_t i = 0; i < num_directions; i++) { orientations.push_back(align_counts[i].first); + //orientations.push_back(its_face_normals(mesh->its)[i]); BOOST_LOG_TRIVIAL(debug) << align_counts[i].first.transpose() << ", area: " << align_counts[i].second; } } + //This function is to make sure to return the accurate normal rather than quantized normal + void area_cumulation_accurate( std::vector& normals_, const Eigen::MatrixXf& quantize_normals_, const Eigen::VectorXf& areas_, int num_directions = 10) + { + std::unordered_map, Vec3f>, VecHash> alignments_; + Vec3f n1 = { 0, 0, 0 }; + std::vector current_areas = {0, 0}; + // init to 0 + for (size_t i = 0; i < areas_.size(); i++) { + alignments_.insert(std::pair(quantize_normals_.row(i), std::pair(current_areas, n1))); + } + // cumulate areas + for (size_t i = 0; i < areas_.size(); i++) + { + alignments_[quantize_normals_.row(i)].first[1] += areas_(i); + if (areas_(i) > alignments_[quantize_normals_.row(i)].first[0]){ + alignments_[quantize_normals_.row(i)].second = normals_[i]; + alignments_[quantize_normals_.row(i)].first[0] = areas_(i); + } + } + typedef std::pair, Vec3f>> PAIR; + std::vector align_counts(alignments_.begin(), alignments_.end()); + sort(align_counts.begin(), align_counts.end(), [](const PAIR& p1, const PAIR& p2) {return p1.second.first[1] > p2.second.first[1]; }); + + num_directions = std::min((size_t)num_directions, align_counts.size()); + for (size_t i = 0; i < num_directions; i++) + { + orientations.push_back(align_counts[i].second.second); + BOOST_LOG_TRIVIAL(debug) << align_counts[i].second.second.transpose() << ", area: " << align_counts[i].second.first[1]; + } + } void add_supplements() { std::vector vecs = { {0, 0, -1} ,{0.70710678, 0, -0.70710678},{0, 0.70710678, -0.70710678}, @@ -246,7 +296,7 @@ public: /// remove duplicate orientations /// /// tolerance. default 0.01 =sin(0.57\degree) - void remove_duplicates(float tol=0.01) + void remove_duplicates(double tol=0.0000001) { for (auto it = orientations.begin()+1; it < orientations.end(); ) { @@ -332,8 +382,14 @@ public: float total_min_z = z_projected.minCoeff(); // filter bottom area - auto bottom_condition = z_max.array() < total_min_z + this->params.FIRST_LAY_H; - costs.bottom = bottom_condition.select(areas, 0).sum(); + auto bottom_condition = z_max.array() < total_min_z + this->params.FIRST_LAY_H - EPSILON; + auto bottom_condition_hull = z_max_hull.array() < total_min_z + this->params.FIRST_LAY_H - EPSILON; + auto bottom_condition_2nd = z_max.array() < total_min_z + this->params.FIRST_LAY_H/2.f - EPSILON; + //The first layer is sliced on half of the first layer height. + //The bottom area is measured by accumulating first layer area with the facets area below first layer height. + //By combining these two factors, we can avoid the wrong orientation of large planar faces while not influence the + //orientations of complex objects with small bottom areas. + costs.bottom = bottom_condition.select(areas, 0).sum()*0.5 + bottom_condition_2nd.select(areas, 0).sum(); // filter overhang Eigen::VectorXf normal_projection(normals.rows(), 1);// = this->normals.dot(orientation); @@ -342,7 +398,7 @@ public: normal_projection(i) = normals.row(i).dot(orientation); } auto areas_appearance = areas.cwiseProduct((is_apperance * params.APPERANCE_FACE_SUPP + Eigen::VectorXf::Ones(is_apperance.rows(), is_apperance.cols()))); - auto overhang_areas = ((normal_projection.array() < params.ASCENT) * (!bottom_condition)).select(areas_appearance, 0); + auto overhang_areas = ((normal_projection.array() < params.ASCENT) * (!bottom_condition_2nd)).select(areas_appearance, 0); Eigen::MatrixXf inner = normal_projection.array() - params.ASCENT; inner = inner.cwiseMin(0).cwiseAbs(); if (min_volume) @@ -378,7 +434,7 @@ public: } // bottom of convex hull - costs.bottom_hull = (z_max_hull.array()< total_min_z + this->params.FIRST_LAY_H).select(areas_hull, 0).sum(); + costs.bottom_hull = (bottom_condition_hull).select(areas_hull, 0).sum(); // low angle faces auto normal_projection_abs = normal_projection.cwiseAbs(); diff --git a/src/libslic3r/Orient.hpp b/src/libslic3r/Orient.hpp index 5e46d050ee..76be064cd1 100644 --- a/src/libslic3r/Orient.hpp +++ b/src/libslic3r/Orient.hpp @@ -53,7 +53,7 @@ struct OrientParamsArea { float TAR_E = 0.0115f; float FIRST_LAY_H = 0.2f;//0.0475; float VECTOR_TOL = -0.00083f; - float NEGL_FACE_SIZE = 0.1f; + float NEGL_FACE_SIZE = 0.01f; float ASCENT = -0.5f; float PLAFOND_ADV = 0.0599f; float CONTOUR_AMOUNT = 0.0182427f; @@ -61,14 +61,14 @@ struct OrientParamsArea { float height_offset = 2.3728f; float height_log = 0.041375f; float height_log_k = 1.9325457f; - float LAF_MAX = 0.9997f; // cos(1.4\degree) for low angle face - float LAF_MIN = 0.9703f; // cos(14\degree) - float TAR_LAF = 0.01f; + float LAF_MAX = 0.999f; // cos(1.4\degree) for low angle face 0.9997f + float LAF_MIN = 0.97f; // cos(14\degree) 0.9703f + float TAR_LAF = 0.001f; //0.01f float TAR_PROJ_AREA = 0.1f; float BOTTOM_MIN = 0.1f; // min bottom area. If lower than it the object may be unstable - float BOTTOM_MAX = 400; // max bottom area. If get to it the object is stable enough (further increase bottom area won't do more help) + float BOTTOM_MAX = 2000; // max bottom area. If get to it the object is stable enough (further increase bottom area won't do more help) float height_to_bottom_hull_ratio_MIN = 1; - float BOTTOM_HULL_MAX = 600;// max bottom hull area + float BOTTOM_HULL_MAX = 2000;// max bottom hull area float APPERANCE_FACE_SUPP=3; // penalty of generating supports on appearance face float overhang_angle = 60.f; @@ -109,14 +109,14 @@ struct OrientParams { float height_offset = 2.7417608343142073f; float height_log = 0.06442030687034085f; float height_log_k = 0.3933594673063997f; - float LAF_MAX = 0.9997f; // cos(1.4\degree) for low angle face - float LAF_MIN= 0.9703f; // cos(14\degree) - float TAR_LAF= 0.1f; + float LAF_MAX = 0.999f; // cos(1.4\degree) for low angle face //0.9997f; + float LAF_MIN= 0.9703f; // cos(14\degree) 0.9703f; + float TAR_LAF = 0.01f; //0.1f float TAR_PROJ_AREA = 0.1f; float BOTTOM_MIN = 0.1f; // min bottom area. If lower than it the objects may be unstable - float BOTTOM_MAX = 400; + float BOTTOM_MAX = 2000; //400 float height_to_bottom_hull_ratio_MIN = 1; - float BOTTOM_HULL_MAX = 600;// max bottom hull area to clip + float BOTTOM_HULL_MAX = 2000;// max bottom hull area to clip //600 float APPERANCE_FACE_SUPP=3; // penalty of generating supports on appearance face float overhang_angle = 60.f; diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index c0faedfe75..97fb33b576 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -4,6 +4,8 @@ #include "ShortestPath.hpp" #include "VariableWidth.hpp" #include "CurveAnalyzer.hpp" +#include "Clipper2Utils.hpp" +#include "Arachne/WallToolPaths.hpp" #include #include @@ -78,6 +80,51 @@ static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuz poly.points = std::move(out); } +// Thanks Cura developers for this function. +static void fuzzy_extrusion_line(Arachne::ExtrusionLine& ext_lines, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) +{ + const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value + const double range_random_point_dist = fuzzy_skin_point_dist / 2.; + double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + + auto* p0 = &ext_lines.front(); + std::vector out; + out.reserve(ext_lines.size()); + for (auto& p1 : ext_lines) { + if (p0->p == p1.p) { // Connect endpoints. + out.emplace_back(p1.p, p1.w, p1.perimeter_index); + continue; + } + + // 'a' is the (next) new point between p0 and p1 + Vec2d p0p1 = (p1.p - p0->p).cast(); + double p0p1_size = p0p1.norm(); + // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size + double dist_last_point = dist_left_over + p0p1_size * 2.; + for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) { + double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; + out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); + dist_last_point = p0pa_dist; + } + dist_left_over = p0p1_size - dist_last_point; + p0 = &p1; + } + + while (out.size() < 3) { + size_t point_idx = ext_lines.size() - 2; + out.emplace_back(ext_lines[point_idx].p, ext_lines[point_idx].w, ext_lines[point_idx].perimeter_index); + if (point_idx == 0) + break; + --point_idx; + } + + if (ext_lines.back().p == ext_lines.front().p) // Connect endpoints. + out.front().p = out.back().p; + + if (out.size() >= 3) + ext_lines.junctions = std::move(out); +} + using PerimeterGeneratorLoops = std::vector; static void lowpass_filter_by_paths_overhang_degree(ExtrusionPaths& paths) { @@ -230,7 +277,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime Polylines inside_polines = (it == lower_polygons_series->begin()) ? intersection_pl({ polygon }, it->second) : - intersection_pl(remain_polines, it->second); + intersection_pl_2(remain_polines, it->second); extrusion_paths_append( paths, std::move(inside_polines), @@ -243,7 +290,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime remain_polines = (it == lower_polygons_series->begin()) ? diff_pl({ polygon }, it->second) : - diff_pl(remain_polines, it->second); + diff_pl_2(remain_polines, it->second); if (remain_polines.size() == 0) break; @@ -355,7 +402,229 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime return out; } -void PerimeterGenerator::process() +static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path& subject, const ClipperLib_Z::Paths& clip, ClipperLib_Z::ClipType clipType) +{ + ClipperLib_Z::Clipper clipper; + clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, + const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) { + ClipperLib_Z::IntPoint start = e1bot; + ClipperLib_Z::IntPoint end = e1top; + + if (start.z() <= 0 && end.z() <= 0) { + start = e2bot; + end = e2top; + } + + assert(start.z() > 0 && end.z() > 0); + + // Interpolate extrusion line width. + double length_sqr = (end - start).cast().squaredNorm(); + double dist_sqr = (pt - start).cast().squaredNorm(); + double t = std::sqrt(dist_sqr / length_sqr); + + pt.z() = start.z() + coord_t((end.z() - start.z()) * t); + }); + + clipper.AddPath(subject, ClipperLib_Z::ptSubject, false); + clipper.AddPaths(clip, ClipperLib_Z::ptClip, true); + + ClipperLib_Z::PolyTree clipped_polytree; + ClipperLib_Z::Paths clipped_paths; + clipper.Execute(clipType, clipped_polytree, ClipperLib_Z::pftNonZero, ClipperLib_Z::pftNonZero); + ClipperLib_Z::PolyTreeToPaths(clipped_polytree, clipped_paths); + + // Clipped path could contain vertices from the clip with a Z coordinate equal to zero. + // For those vertices, we must assign value based on the subject. + // This happens only in sporadic cases. + for (ClipperLib_Z::Path& path : clipped_paths) + for (ClipperLib_Z::IntPoint& c_pt : path) + if (c_pt.z() == 0) { + // Now we must find the corresponding line on with this point is located and compute line width (Z coordinate). + if (subject.size() <= 2) + continue; + + const Point pt(c_pt.x(), c_pt.y()); + Point projected_pt_min; + auto it_min = subject.begin(); + auto dist_sqr_min = std::numeric_limits::max(); + Point prev(subject.front().x(), subject.front().y()); + for (auto it = std::next(subject.begin()); it != subject.end(); ++it) { + Point curr(it->x(), it->y()); + Point projected_pt = pt.projection_onto(Line(prev, curr)); + if (double dist_sqr = (projected_pt - pt).cast().squaredNorm(); dist_sqr < dist_sqr_min) { + dist_sqr_min = dist_sqr; + projected_pt_min = projected_pt; + it_min = std::prev(it); + } + prev = curr; + } + + assert(dist_sqr_min <= SCALED_EPSILON); + assert(std::next(it_min) != subject.end()); + + const Point pt_a(it_min->x(), it_min->y()); + const Point pt_b(std::next(it_min)->x(), std::next(it_min)->y()); + const double line_len = (pt_b - pt_a).cast().norm(); + const double dist = (projected_pt_min - pt_a).cast().norm(); + c_pt.z() = coord_t(double(it_min->z()) + (dist / line_len) * double(std::next(it_min)->z() - it_min->z())); + } + + assert([&clipped_paths = std::as_const(clipped_paths)]() -> bool { + for (const ClipperLib_Z::Path& path : clipped_paths) + for (const ClipperLib_Z::IntPoint& pt : path) + if (pt.z() <= 0) + return false; + return true; + }()); + + return clipped_paths; +} + +struct PerimeterGeneratorArachneExtrusion +{ + Arachne::ExtrusionLine* extrusion = nullptr; + // Indicates if closed ExtrusionLine is a contour or a hole. Used it only when ExtrusionLine is a closed loop. + bool is_contour = false; + // Should this extrusion be fuzzyfied on path generation? + bool fuzzify = false; +}; + +static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector& pg_extrusions) +{ + ExtrusionEntityCollection extrusion_coll; + for (PerimeterGeneratorArachneExtrusion& pg_extrusion : pg_extrusions) { + Arachne::ExtrusionLine* extrusion = pg_extrusion.extrusion; + if (extrusion->empty()) + continue; + + const bool is_external = extrusion->inset_idx == 0; + ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter; + + if (pg_extrusion.fuzzify) + fuzzy_extrusion_line(*extrusion, scaled(perimeter_generator.config->fuzzy_skin_thickness.value), scaled(perimeter_generator.config->fuzzy_skin_point_distance.value)); + + ExtrusionPaths paths; + // detect overhanging/bridging perimeters + if (perimeter_generator.config->detect_overhang_wall && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers + && !((perimeter_generator.object_config->enable_support || perimeter_generator.object_config->enforce_support_layers > 0) && + perimeter_generator.object_config->support_top_z_distance.value == 0)) { + + ClipperLib_Z::Path extrusion_path; + extrusion_path.reserve(extrusion->size()); + for (const Arachne::ExtrusionJunction& ej : extrusion->junctions) + extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w); + + ClipperLib_Z::Paths lower_slices_paths; + lower_slices_paths.reserve(perimeter_generator.lower_slices_polygons().size()); + for (const Polygon& poly : perimeter_generator.lower_slices_polygons()) { + lower_slices_paths.emplace_back(); + ClipperLib_Z::Path& out = lower_slices_paths.back(); + out.reserve(poly.points.size()); + for (const Point& pt : poly.points) + out.emplace_back(pt.x(), pt.y(), 0); + } + + // get non-overhang paths by intersecting this loop with the grown lower slices + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role, + is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); + + // get overhang paths by checking what parts of this loop fall + // outside the grown lower slices (thus where the distance between + // the loop centerline and original lower slices is >= half nozzle diameter + extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter, + perimeter_generator.overhang_flow); + + // Reapply the nearest point search for starting point. + // We allow polyline reversal because Clipper may have randomly reversed polylines during clipping. + // Arachne sometimes creates extrusion with zero-length (just two same endpoints); + if (!paths.empty()) { + Point start_point = paths.front().first_point(); + if (!extrusion->is_closed) { + // Especially for open extrusion, we need to select a starting point that is at the start + // or the end of the extrusions to make one continuous line. Also, we prefer a non-overhang + // starting point. + struct PointInfo + { + size_t occurrence = 0; + bool is_overhang = false; + }; + std::unordered_map point_occurrence; + for (const ExtrusionPath& path : paths) { + ++point_occurrence[path.polyline.first_point()].occurrence; + ++point_occurrence[path.polyline.last_point()].occurrence; + if (path.role() == erOverhangPerimeter) { + point_occurrence[path.polyline.first_point()].is_overhang = true; + point_occurrence[path.polyline.last_point()].is_overhang = true; + } + } + + // Prefer non-overhang point as a starting point. + for (const std::pair pt : point_occurrence) + if (pt.second.occurrence == 1) { + start_point = pt.first; + if (!pt.second.is_overhang) { + start_point = pt.first; + break; + } + } + } + + chain_and_reorder_extrusion_paths(paths, &start_point); + } + } + else { + extrusion_paths_append(paths, *extrusion, role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); + } + + // Append paths to collection. + if (!paths.empty()) { + if (extrusion->is_closed) { + ExtrusionLoop extrusion_loop(std::move(paths)); + // Restore the orientation of the extrusion loop. + if (pg_extrusion.is_contour) + extrusion_loop.make_counter_clockwise(); + else + extrusion_loop.make_clockwise(); + + for (auto it = std::next(extrusion_loop.paths.begin()); it != extrusion_loop.paths.end(); ++it) { + assert(it->polyline.points.size() >= 2); + assert(std::prev(it)->polyline.last_point() == it->polyline.first_point()); + } + assert(extrusion_loop.paths.front().first_point() == extrusion_loop.paths.back().last_point()); + + extrusion_coll.append(std::move(extrusion_loop)); + } + else { + // Because we are processing one ExtrusionLine all ExtrusionPaths should form one connected path. + // But there is possibility that due to numerical issue there is poss + assert([&paths = std::as_const(paths)]() -> bool { + for (auto it = std::next(paths.begin()); it != paths.end(); ++it) + if (std::prev(it)->polyline.last_point() != it->polyline.first_point()) + return false; + return true; + }()); + ExtrusionMultiPath multi_path; + multi_path.paths.emplace_back(std::move(paths.front())); + + for (auto it_path = std::next(paths.begin()); it_path != paths.end(); ++it_path) { + if (multi_path.paths.back().last_point() != it_path->first_point()) { + extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path))); + multi_path = ExtrusionMultiPath(); + } + multi_path.paths.emplace_back(std::move(*it_path)); + } + + extrusion_coll.append(ExtrusionMultiPath(std::move(multi_path))); + } + } + } + + return extrusion_coll; +} + + + +void PerimeterGenerator::process_classic() { // other perimeters m_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); @@ -562,7 +831,7 @@ void PerimeterGenerator::process() //BBS: refer to superslicer //store surface for top infill if only_one_wall_top - if (i == 0 && config->only_one_wall_top && this->upper_slices != NULL) { + if (i == 0 && i!=loop_number && config->only_one_wall_top && this->upper_slices != NULL) { //split the polygons with top/not_top //get the offset from solid surface anchor coord_t offset_top_surface = scale_(1.5 * (config->wall_loops.value == 0 ? 0. : unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(config->wall_loops.value) - int(1)))))); @@ -577,9 +846,19 @@ void PerimeterGenerator::process() //set the clip to a virtual "second perimeter" fill_clip = offset_ex(last, -double(ext_perimeter_spacing)); // get the real top surface - ExPolygons top_polygons = diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes); + ExPolygons grown_lower_slices; + ExPolygons bridge_checker; + // BBS: check whether surface be bridge or not + if (this->lower_slices != NULL) { + grown_lower_slices =*this->lower_slices; + double bridge_offset = std::max(double(ext_perimeter_spacing), (double(perimeter_width))); + bridge_checker = offset_ex(diff_ex(last, grown_lower_slices, ApplySafetyOffset::Yes), 1.5 * bridge_offset); + } + ExPolygons delete_bridge = diff_ex(last, bridge_checker, ApplySafetyOffset::Yes); + ExPolygons top_polygons = diff_ex(delete_bridge, grown_upper_slices, ApplySafetyOffset::Yes); //get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before) + ExPolygons temp_gap = diff_ex(top_polygons, fill_clip); ExPolygons inner_polygons = diff_ex(last, offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)), ApplySafetyOffset::Yes); @@ -591,6 +870,8 @@ void PerimeterGenerator::process() double infill_spacing_unscaled = this->config->sparse_infill_line_width.value; fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); last = intersection_ex(inner_polygons, last); + if (has_gap_fill) + last = union_ex(last,temp_gap); //{ // std::stringstream stri; // stri << this->layer->id() << "_1_"<< i <<"_only_one_peri"<< ".svg"; @@ -818,6 +1099,261 @@ void PerimeterGenerator::process() } // for each island } +// 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() +{ + // other perimeters + m_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); + coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing(); + + // external perimeters + m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm(); + coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); + coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); + coord_t ext_perimeter_spacing2 = scaled(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing())); + + // overhang perimeters + m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm(); + + // solid infill + coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing(); + + // prepare grown lower layer slices for overhang detection + if (this->lower_slices != nullptr && this->config->detect_overhang_wall) { + // We consider overhang any part where the entire nozzle diameter is not supported by the + // lower layer, so we take lower slices and offset them by half the nozzle diameter used + // in the current layer + double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->wall_filament - 1); + m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter / 2))); + } + + // we need to process each island separately because we might have different + // extra perimeters for each one + for (const Surface& surface : this->slices->surfaces) { + // detect how many perimeters must be generated for this island + int loop_number = this->config->wall_loops + surface.extra_perimeters - 1; // 0-indexed loops + ExPolygons last = offset_ex(surface.expolygon.simplify_p(m_scaled_resolution), -float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); + Polygons last_p = to_polygons(last); + + double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end()); + Arachne::WallToolPathsParams input_params; + { + if (const auto& min_feature_size_opt = object_config->min_feature_size) + input_params.min_feature_size = min_feature_size_opt.value * 0.01 * min_nozzle_diameter; + + if (const auto& min_bead_width_opt = object_config->min_bead_width) + input_params.min_bead_width = min_bead_width_opt.value * 0.01 * min_nozzle_diameter; + + if (const auto& wall_transition_filter_deviation_opt = object_config->wall_transition_filter_deviation) + input_params.wall_transition_filter_deviation = wall_transition_filter_deviation_opt.value * 0.01 * min_nozzle_diameter; + + if (const auto& wall_transition_length_opt = object_config->wall_transition_length) + input_params.wall_transition_length = wall_transition_length_opt.value * 0.01 * min_nozzle_diameter; + + input_params.wall_transition_angle = this->object_config->wall_transition_angle.value; + input_params.wall_distribution_count = this->object_config->wall_distribution_count.value; + } + + Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, layer_height, input_params); + std::vector perimeters = wallToolPaths.getToolPaths(); + loop_number = int(perimeters.size()) - 1; + +#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())); + } +#endif + + // All closed ExtrusionLine should have the same the first and the last point. + // But in rare cases, Arachne produce ExtrusionLine marked as closed but without + // equal the first and the last point. + assert([&perimeters = std::as_const(perimeters)]() -> bool { + for (const Arachne::VariableWidthLines& perimeter : perimeters) + for (const Arachne::ExtrusionLine& el : perimeter) + if (el.is_closed && el.junctions.front().p != el.junctions.back().p) + return false; + return true; + }()); + + int start_perimeter = int(perimeters.size()) - 1; + int end_perimeter = -1; + int direction = -1; + + bool is_outer_wall_first = + this->print_config->wall_infill_order == WallInfillOrder::OuterInnerInfill || + this->print_config->wall_infill_order == WallInfillOrder::InfillOuterInner; + if (is_outer_wall_first) { + start_perimeter = 0; + end_perimeter = int(perimeters.size()); + direction = 1; + } + + std::vector all_extrusions; + for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) { + if (perimeters[perimeter_idx].empty()) + continue; + for (Arachne::ExtrusionLine& wall : perimeters[perimeter_idx]) + all_extrusions.emplace_back(&wall); + } + + // Find topological order with constraints from extrusions_constrains. + std::vector blocked(all_extrusions.size(), 0); // Value indicating how many extrusions it is blocking (preceding extrusions) an extrusion. + std::vector> blocking(all_extrusions.size()); // Each extrusion contains a vector of extrusions that are blocked by this extrusion. + std::unordered_map map_extrusion_to_idx; + for (size_t idx = 0; idx < all_extrusions.size(); idx++) + map_extrusion_to_idx.emplace(all_extrusions[idx], idx); + + auto extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, is_outer_wall_first); + for (auto [before, after] : extrusions_constrains) { + auto after_it = map_extrusion_to_idx.find(after); + ++blocked[after_it->second]; + blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second); + } + + std::vector processed(all_extrusions.size(), false); // Indicate that the extrusion was already processed. + Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.front()->junctions.front().p; // Some starting position. + std::vector ordered_extrusions; // To store our result in. At the end we'll std::swap. + ordered_extrusions.reserve(all_extrusions.size()); + + while (ordered_extrusions.size() < all_extrusions.size()) { + size_t best_candidate = 0; + double best_distance_sqr = std::numeric_limits::max(); + bool is_best_closed = false; + + std::vector available_candidates; + for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) { + if (processed[candidate] || blocked[candidate]) + continue; // Not a valid candidate. + available_candidates.push_back(candidate); + } + + std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool { + return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed; + }); + + for (const size_t candidate_path_idx : available_candidates) { + auto& path = all_extrusions[candidate_path_idx]; + + if (path->junctions.empty()) { // No vertices in the path. Can't find the start position then or really plan it in. Put that at the end. + if (best_distance_sqr == std::numeric_limits::max()) { + best_candidate = candidate_path_idx; + is_best_closed = path->is_closed; + } + continue; + } + + const Point candidate_position = path->junctions.front().p; + double distance_sqr = (current_position - candidate_position).cast().norm(); + if (distance_sqr < best_distance_sqr) { // Closer than the best candidate so far. + if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits::max()) || (!path->is_closed && !is_best_closed)) { + best_candidate = candidate_path_idx; + best_distance_sqr = distance_sqr; + is_best_closed = path->is_closed; + } + } + } + + auto& best_path = all_extrusions[best_candidate]; + ordered_extrusions.push_back({ best_path, best_path->is_contour(), false }); + processed[best_candidate] = true; + for (size_t unlocked_idx : blocking[best_candidate]) + blocked[unlocked_idx]--; + + if (!best_path->junctions.empty()) { //If all paths were empty, the best path is still empty. We don't upate the current position then. + if (best_path->is_closed) + current_position = best_path->junctions[0].p; //We end where we started. + else + current_position = best_path->junctions.back().p; //Pick the other end from where we started. + } + } + + if (this->layer_id > 0 && this->config->fuzzy_skin != FuzzySkinType::None) { + std::vector closed_loop_extrusions; + for (PerimeterGeneratorArachneExtrusion& extrusion : ordered_extrusions) + if (extrusion.extrusion->inset_idx == 0) { + if (extrusion.extrusion->is_closed && this->config->fuzzy_skin == FuzzySkinType::External) { + closed_loop_extrusions.emplace_back(&extrusion); + } + else { + extrusion.fuzzify = true; + } + } + + if (this->config->fuzzy_skin == FuzzySkinType::External) { + ClipperLib_Z::Paths loops_paths; + loops_paths.reserve(closed_loop_extrusions.size()); + for (const auto& cl_extrusion : closed_loop_extrusions) { + assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back()); + size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front(); + ClipperLib_Z::Path loop_path; + loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1); + for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it) + loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx); + loops_paths.emplace_back(loop_path); + } + + ClipperLib_Z::Clipper clipper; + clipper.AddPaths(loops_paths, ClipperLib_Z::ptSubject, true); + ClipperLib_Z::PolyTree loops_polytree; + clipper.Execute(ClipperLib_Z::ctUnion, loops_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd); + + for (const ClipperLib_Z::PolyNode* child_node : loops_polytree.Childs) { + // The whole contour must have the same index. + coord_t polygon_idx = child_node->Contour.front().z(); + bool has_same_idx = std::all_of(child_node->Contour.begin(), child_node->Contour.end(), + [&polygon_idx](const ClipperLib_Z::IntPoint& point) -> bool { return polygon_idx == point.z(); }); + if (has_same_idx) + closed_loop_extrusions[polygon_idx]->fuzzify = true; + } + } + } + + if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty()) + this->loops->append(extrusion_coll); + + 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. + + // 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 inset = + (loop_number < 0) ? 0 : + (loop_number == 0) ? + // one loop + ext_perimeter_spacing : + // two or more loops? + perimeter_spacing; + + inset = coord_t(scale_(this->config->infill_wall_overlap.get_abs_value(unscale(inset)))); + Polygons pp; + for (ExPolygon& ex : infill_contour) + ex.simplify_p(m_scaled_resolution, &pp); + // collapse too narrow infill areas + const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); + // append infill areas to fill_surfaces + this->fill_surfaces->append( + offset2_ex( + union_ex(pp), + float(-min_perimeter_infill_spacing / 2.), + float(inset + min_perimeter_infill_spacing / 2.)), + stInternal); + + // BBS: get the no-overlap infill expolygons + { + append(*this->fill_no_overlap, offset2_ex( + union_ex(pp), + float(-min_perimeter_infill_spacing / 2.), + float(+min_perimeter_infill_spacing / 2.))); + } + } +} + bool PerimeterGeneratorLoop::is_internal_contour() const { // An internal contour is a contour containing no other contours diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 2d64de497e..c772a05634 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -66,13 +66,15 @@ public: m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1), m_ext_mm3_per_mm_smaller_width(-1) {} - void process(); + void process_classic(); + void process_arachne(); 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; } //BBS double smaller_width_ext_mm3_per_mm() const { return m_ext_mm3_per_mm_smaller_width; } + Polygons lower_slices_polygons() const { return m_lower_slices_polygons; } private: std::map generate_lower_polygons_series(float width); @@ -85,6 +87,7 @@ private: double m_mm3_per_mm_overhang; //BBS double m_ext_mm3_per_mm_smaller_width; + Polygons m_lower_slices_polygons; }; } diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 4ac4e1b69d..a64b3b8786 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -8,8 +8,7 @@ #include #include #include - -#include +#include #include "LocalesUtils.hpp" diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 242b68e4f0..15424401ce 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -521,10 +521,10 @@ void Preset::save(DynamicPrintConfig* parent_config) ConfigOption *opt_dst = temp_config.option(option, true); opt_dst->set(opt_src); } - temp_config.save_to_json(this->file, this->name, from_str, this->version.to_string()); + 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->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"); @@ -662,6 +662,28 @@ std::string Preset::get_printer_type(PresetBundle *preset_bundle) return ""; } +std::string Preset::get_current_printer_type(PresetBundle *preset_bundle) +{ + if (preset_bundle) { + auto config = &(this->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; + return vendor_model.model_id; + } + } + } + return ""; +} + +bool Preset::is_custom_defined() +{ + if (custom_defined == "1") + return true; + return false; +} bool Preset::is_bbl_vendor_preset(PresetBundle *preset_bundle) { @@ -684,11 +706,11 @@ bool Preset::is_bbl_vendor_preset(PresetBundle *preset_bundle) } static std::vector s_Preset_print_options { - "layer_height", "initial_layer_print_height", "wall_loops", "slice_closing_radius", "spiral_mode", + "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", - "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", + "ensure_vertical_shell_thickness", "reduce_crossing_wall", "detect_thin_wall", "detect_overhang_wall", "seam_position", "wall_infill_order", "sparse_infill_density", "sparse_infill_pattern", "top_surface_pattern", "bottom_surface_pattern", - "infill_direction", + "infill_direction", "bridge_angle", "minimum_sparse_infill_area", "reduce_infill_retraction", "ironing_type", "ironing_flow", "ironing_speed", "ironing_spacing", "max_travel_detour_distance", @@ -703,13 +725,13 @@ static std::vector s_Preset_print_options { "default_jerk", "outer_wall_jerk", "inner_wall_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk", "brim_width", "brim_object_gap", "brim_type", "enable_support", "support_type", "support_threshold_angle", "enforce_support_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", - "support_base_pattern", "support_base_pattern_spacing", "support_style", + "support_base_pattern", "support_base_pattern_spacing", "support_expansion", "support_style", // BBS //"independent_support_layer_height", "support_angle", "support_interface_top_layers", "support_interface_bottom_layers", "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", - "filename_format", "wall_filament", + "filename_format", "wall_filament", "support_bottom_z_distance", "sparse_infill_filament", "solid_infill_filament", "support_filament", "support_interface_filament", "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", @@ -719,20 +741,21 @@ static std::vector s_Preset_print_options { "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", "flush_into_infill", "flush_into_objects", "flush_into_support", // BBS - "tree_support_branch_angle", "tree_support_with_infill", "tree_support_wall_count", "tree_support_branch_distance", + "tree_support_branch_angle", "tree_support_wall_count", "tree_support_branch_distance", "tree_support_branch_diameter", "detect_narrow_internal_solid_infill", - "gcode_add_line_number", "enable_arc_fitting", "infill_combination", "adaptive_layer_height", + "gcode_add_line_number", "enable_arc_fitting", "infill_combination", /*"adaptive_layer_height",*/ "support_bottom_interface_spacing", "enable_overhang_speed", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed", - "initial_layer_infill_speed", "only_one_wall_top", "only_one_wall_first_layer", - "timelapse_type", + "initial_layer_infill_speed", "only_one_wall_top", + "timelapse_type", "internal_bridge_support_thickness", + "wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", + "wall_distribution_count", "min_feature_size", "min_bead_width", //SoftFever - "top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio" - + "top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer" }; static std::vector s_Preset_filament_options { - /*"filament_colour", */"filament_diameter", "filament_type", "filament_soluble", "filament_is_support", "filament_max_volumetric_speed", + /*"filament_colour", */ "default_filament_colour","filament_diameter", "filament_type", "filament_soluble", "filament_is_support", "filament_max_volumetric_speed", "filament_flow_ratio", "enable_pressure_advance", "pressure_advance", "filament_density", "filament_cost", "filament_minimal_purge_on_wipe_tower", "chamber_temperature", "nozzle_temperature", "nozzle_temperature_initial_layer", // BBS @@ -762,14 +785,14 @@ static std::vector s_Preset_machine_limits_options { static std::vector s_Preset_printer_options { "printer_technology", - "printable_area", "bed_exclude_area", "gcode_flavor","z_lift_type", + "printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor", "z_lift_type", "single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "change_filament_gcode", "printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_max_radius","extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod", "default_print_profile", "inherits", "silent_mode", // BBS "scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "machine_pause_gcode", "template_custom_gcode", - "nozzle_type", "nozzle_diameter", "auxiliary_fan", "nozzle_volume", + "nozzle_type", "nozzle_hrc","nozzle_diameter", "auxiliary_fan", "nozzle_volume","upward_compatible_machine", //SoftFever "host_type", "print_host", "printhost_apikey", "printhost_cafile","printhost_port","printhost_authorization_type", @@ -848,7 +871,7 @@ static std::vector s_Preset_sla_material_options { static std::vector s_Preset_sla_printer_options { "printer_technology", - "printable_area", "printable_height", + "printable_area","bed_custom_texture", "bed_custom_model", "printable_height", "display_width", "display_height", "display_pixels_x", "display_pixels_y", "display_mirror_x", "display_mirror_y", "display_orientation", @@ -1024,14 +1047,20 @@ void PresetCollection::load_presets( } preset.version = *version; + if (key_values.find(BBL_JSON_KEY_IS_CUSTOM) != key_values.end()) + preset.custom_defined = key_values[BBL_JSON_KEY_IS_CUSTOM]; + //BBS: use inherit config as the base Preset* inherit_preset = nullptr; ConfigOption* inherits_config = config.option(BBL_JSON_KEY_INHERITS); + + // check inherits_config if (inherits_config) { ConfigOptionString * option_str = dynamic_cast (inherits_config); std::string inherits_value = option_str->value; - inherit_preset = this->find_preset(inherits_value, false, true); + } else { + ; } const Preset& default_preset = this->default_preset_for(config); if (inherit_preset) { @@ -1039,19 +1068,22 @@ void PresetCollection::load_presets( preset.filament_id = inherit_preset->filament_id; } else { + if (!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; + //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; - continue; + preset.config = default_preset.config; } preset.config.apply(std::move(config)); Preset::normalize(preset.config); // Report configuration fields, which are misplaced into a wrong group. std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config); - if (! incorrect_keys.empty()) + 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"; + preset.file << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed"; preset.loaded = true; //BBS: add some workaround for previous incorrect settings if ((!preset.setting_id.empty())&&(preset.setting_id == preset.base_id)) @@ -1359,25 +1391,29 @@ void PresetCollection::save_user_presets(const std::string& dir_path, const std: if (!preset->is_user()) continue; preset->file = path_from_name(preset->name); - //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); - continue; - } - Preset* parent_preset = this->find_preset(inherits, false, true); - if (!parent_preset) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find parent preset for %1% , inherits %2%")%preset->name %inherits; - continue; - } + if (preset->is_custom_defined()) { + preset->save(nullptr); + } else { + //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); + continue; + } + Preset* parent_preset = this->find_preset(inherits, false, true); + if (!parent_preset) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" can not find parent preset for %1% , inherits %2%")%preset->name %inherits; + continue; + } - if (preset->base_id.empty()) - preset->base_id = parent_preset->setting_id; - preset->save(&(parent_preset->config)); + if (preset->base_id.empty()) + preset->base_id = parent_preset->setting_id; + preset->save(&(parent_preset->config)); + } } for (auto delete_name: delete_name_list) @@ -1603,11 +1639,11 @@ bool PresetCollection::validate_printers(const std::string &name, DynamicPrintCo // Load a preset from an already parsed config file, insert it into the sorted sequence of presets // and select it, losing previous modifications. -Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select) +Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select, Semver file_version, bool is_custom_defined) { DynamicPrintConfig cfg(this->default_preset().config); cfg.apply_only(config, cfg.keys(), true); - return this->load_preset(path, name, std::move(cfg), select); + return this->load_preset(path, name, std::move(cfg), select, file_version, is_custom_defined); } static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new) @@ -1874,7 +1910,7 @@ std::pair PresetCollection::load_external_preset( return std::make_pair(&preset, false); } -Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select) +Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select, Semver file_version, bool is_custom_defined) { lock(); auto it = this->find_preset_internal(name); @@ -1889,6 +1925,10 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string preset.config = std::move(config); preset.loaded = true; preset.is_dirty = false; + preset.custom_defined = is_custom_defined ? "1": "0"; + //BBS + if (file_version.valid()) + preset.version = file_version; if (select) this->select_preset_by_name(name, true); unlock(); diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index 7578bb2393..e319f60cbc 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -29,6 +29,7 @@ //BBS: add json support #define BBL_JSON_KEY_VERSION "version" +#define BBL_JSON_KEY_IS_CUSTOM "is_custom_defined" #define BBL_JSON_KEY_URL "url" #define BBL_JSON_KEY_NAME "name" #define BBL_JSON_KEY_DESCRIPTION "description" @@ -229,6 +230,7 @@ public: std::string user_id; // preset user_id std::string base_id; // base id of preset std::string sync_info; // enum: "delete", "create", "update", "" + std::string custom_defined; // enum: "1", "0", "" long long updated_time{0}; //last updated time std::map key_values; @@ -296,10 +298,14 @@ public: // special for upport G and Support W std::string get_filament_type(std::string &display_filament_type); - std::string get_printer_type(PresetBundle *preset_bundle); + 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 is_custom_defined(); bool is_bbl_vendor_preset(PresetBundle *preset_bundle); + + static const std::vector& print_options(); static const std::vector& filament_options(); // Printer options contain the nozzle options. @@ -434,8 +440,8 @@ public: // Load a preset from an already parsed config file, insert it into the sorted sequence of presets // and select it, losing previous modifications. - Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true); - Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true); + 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); // 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 diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index fb20b3297d..e02a60fa8e 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -13,7 +13,7 @@ #include #include #include - +#include #include #include #include @@ -1165,7 +1165,12 @@ void PresetBundle::load_installed_filaments(AppConfig &config) if (!add_default_materials) continue; - for (auto default_filament: printer.vendor->models[0].default_materials) + const VendorProfile::PrinterModel *printer_model = PresetUtils::system_printer_model(printer); + if (!printer_model) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": can not find printer_model for printer %1%")%printer.name; + continue; + } + for (auto default_filament: printer_model->default_materials) { Preset* filament = filaments.find_preset(default_filament, false, true); if (filament && filament->is_system) @@ -1256,8 +1261,6 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p sla_prints.select_preset_by_name_strict(initial_sla_print_profile_name); sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name); - // BBS: filament_presets are now considered as project config instead of app config -#if 0 // Load the names of the other filament profiles selected for a multi-material printer. // Load it even if the current printer technology is SLA. // The possibly excessive filament names will be later removed with this->update_multi_material_filament_presets() @@ -1270,7 +1273,22 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p break; this->filament_presets.emplace_back(remove_ini_suffix(config.get("presets", name))); } -#endif + std::vector filament_colors; + if (config.has("presets", "filament_colors")) { + boost::algorithm::split(filament_colors, config.get("presets", "filament_colors"), boost::algorithm::is_any_of(",")); + project_config.option("filament_colour")->values = filament_colors; + } + std::vector matrix; + if (config.has("presets", "flush_volumes_matrix")) { + boost::algorithm::split(matrix, config.get("presets", "flush_volumes_matrix"), boost::algorithm::is_any_of("|")); + auto flush_volumes_matrix = matrix | boost::adaptors::transformed(boost::lexical_cast); + project_config.option("flush_volumes_matrix")->values = std::vector(flush_volumes_matrix.begin(), flush_volumes_matrix.end()); + } + if (config.has("presets", "flush_volumes_vector")) { + boost::algorithm::split(matrix, config.get("presets", "flush_volumes_vector"), boost::algorithm::is_any_of("|")); + auto flush_volumes_vector = matrix | boost::adaptors::transformed(boost::lexical_cast); + project_config.option("flush_volumes_vector")->values = std::vector(flush_volumes_vector.begin(), flush_volumes_vector.end()); + } // Update visibility of presets based on their compatibility with the active printer. // Always try to select a compatible print and filament preset to the current printer preset, @@ -1298,6 +1316,15 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p } } + std::string first_visible_filament_name; + for (auto & fp : filament_presets) { + if (auto it = filaments.find_preset_internal(fp); it == filaments.end() || !it->is_visible || !it->is_compatible) { + if (first_visible_filament_name.empty()) + first_visible_filament_name = filaments.first_compatible().name; + fp = first_visible_filament_name; + } + } + // Parse the initial physical printer name. std::string initial_physical_printer_name = remove_ini_suffix(config.get("presets", "physical_printer")); @@ -1322,6 +1349,17 @@ void PresetBundle::export_selections(AppConfig &config) sprintf(name, "filament_%u", i); config.set("presets", name, filament_presets[i]); } + CNumericLocalesSetter locales_setter; + std::string filament_colors = boost::algorithm::join(project_config.option("filament_colour")->values, ","); + config.set("presets", "filament_colors", filament_colors); + std::string flush_volumes_matrix = boost::algorithm::join(project_config.option("flush_volumes_matrix")->values | + boost::adaptors::transformed(static_cast(std::to_string)), + "|"); + config.set("presets", "flush_volumes_matrix", flush_volumes_matrix); + std::string flush_volumes_vector = boost::algorithm::join(project_config.option("flush_volumes_vector")->values | + boost::adaptors::transformed(static_cast(std::to_string)), + "|"); + config.set("presets", "flush_volumes_vector", flush_volumes_vector); config.set("presets", PRESET_PRINTER_NAME, printers.get_selected_preset_name()); // BBS @@ -1357,7 +1395,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color) update_multi_material_filament_presets(); } -unsigned int PresetBundle::sync_ams_list() +unsigned int PresetBundle::sync_ams_list(unsigned int &unknowns) { std::vector filament_presets; std::vector filament_colors; @@ -1367,7 +1405,16 @@ unsigned int PresetBundle::sync_ams_list() 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; }); if (iter == filaments.end()) { BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id; - continue; + auto filament_type = "Generic " + ams.opt_string("filament_type", 0u); + iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) { return f.is_compatible && f.is_system + && boost::algorithm::starts_with(f.name, filament_type); + }); + if (iter == filaments.end()) + 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; + filament_id = iter->filament_id; } filament_presets.push_back(iter->name); filament_colors.push_back(filament_color); @@ -1449,10 +1496,15 @@ DynamicPrintConfig PresetBundle::full_fff_config() const std::vector compatible_prints_condition; std::vector inherits; std::vector filament_ids; + std::vector print_compatible_printers; //BBS: add logic for settings check between different system presets std::vector different_settings; std::string different_print_settings, different_printer_settings; compatible_printers_condition.emplace_back(this->prints.get_edited_preset().compatible_printers_condition()); + + const ConfigOptionStrings* compatible_printers = (const_cast(this))->prints.get_edited_preset().config.option("compatible_printers", false); + if (compatible_printers) + print_compatible_printers = compatible_printers->values; //BBS: add logic for settings check between different system presets std::string print_inherits = this->prints.get_edited_preset().inherits(); inherits .emplace_back(print_inherits); @@ -1627,6 +1679,7 @@ DynamicPrintConfig PresetBundle::full_fff_config() const add_if_some_non_empty(std::move(inherits), "inherits_group"); //BBS: add logic for settings check between different system presets add_if_some_non_empty(std::move(different_settings), "different_settings_to_system"); + add_if_some_non_empty(std::move(print_compatible_printers), "print_compatible_printers"); out.option("printer_technology", true)->value = ptFFF; return out; @@ -1756,20 +1809,19 @@ ConfigSubstitutions PresetBundle::load_config_file(const std::string &path, Forw // Load a config file from a boost property_tree. This is a private method called from load_config_file. // is_external == false on if called from ConfigWizard -void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version) +void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version, bool selected, bool is_custom_defined) { PrinterTechnology printer_technology = Preset::printer_technology(config); - // The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway, - // but some of the alpha versions of Slic3r did. - { + auto clear_compatible_printers = [](DynamicPrintConfig& config){ ConfigOption *opt_compatible = config.optptr("compatible_printers"); if (opt_compatible != nullptr) { assert(opt_compatible->type() == coStrings); if (opt_compatible->type() == coStrings) static_cast(opt_compatible)->values.clear(); } - } + }; + clear_compatible_printers(config); #if 0 size_t num_extruders = (printer_technology == ptFFF) ? @@ -1791,6 +1843,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool std::vector compatible_prints_condition_values = std::move(config.option("compatible_process_expression_group", true)->values); std::vector inherits_values = std::move(config.option("inherits_group", true)->values); std::vector filament_ids = std::move(config.option("filament_ids", true)->values); + std::vector print_compatible_printers = std::move(config.option("print_compatible_printers", true)->values); //BBS: add different settings check logic bool has_different_settings_to_system = config.option("different_settings_to_system")?true:false; std::vector different_values = std::move(config.option("different_settings_to_system", true)->values); @@ -1826,7 +1879,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool [&config, &inherits, &inherits_values, &compatible_printers_condition, &compatible_printers_condition_values, &compatible_prints_condition, &compatible_prints_condition_values, - is_external, &name, &name_or_path, file_version] + is_external, &name, &name_or_path, file_version, selected, is_custom_defined] (PresetCollection &presets, size_t idx, const std::string &key, const std::set &different_keys, std::string filament_id) { // Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles. inherits = inherits_values[idx]; @@ -1838,7 +1891,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).save(nullptr); + presets.load_preset(presets.path_from_name(name), name, config, selected, file_version, is_custom_defined).save(nullptr); }; switch (Preset::printer_technology(config)) { @@ -1855,8 +1908,16 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool //} //else print_different_keys_set.insert(ignore_settings_list.begin(), ignore_settings_list.end()); + if (!print_compatible_printers.empty()) { + ConfigOptionStrings* compatible_printers = config.option("compatible_printers", true); + compatible_printers->values = print_compatible_printers; + } + load_preset(this->prints, 0, "print_settings_id", print_different_keys_set, std::string()); + //clear compatible printers + clear_compatible_printers(config); + std::vector printer_different_keys_vector; std::string printer_different_settings = different_values[num_filaments + 1]; Slic3r::unescape_strings_cstyle(printer_different_settings, printer_different_keys_vector); @@ -1899,7 +1960,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); + loaded= &this->filaments.load_preset(this->filaments.path_from_name(name), name, config, true, file_version, is_custom_defined); loaded->save(nullptr); } this->filament_presets.clear(); @@ -3424,8 +3485,10 @@ std::vector PresetBundle::export_current_configs(const std::string // an optional "(modified)" suffix will be removed from the filament name. void PresetBundle::set_filament_preset(size_t idx, const std::string &name) { - if (idx >= filament_presets.size()) - filament_presets.resize(idx + 1, filaments.default_preset().name); + if (idx >= filament_presets.size()) { + BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: set_filament_preset out of range %1% - %2%") % idx % filament_presets.size(); + return; + } filament_presets[idx] = Preset::remove_suffix_modified(name); } diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index 5b5c41d502..8c0e2dd825 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -81,7 +81,7 @@ public: // BBS void set_num_filaments(unsigned int n, std::string new_col = ""); - unsigned int sync_ams_list(); + unsigned int sync_ams_list(unsigned int & unknowns); //BBS: check whether this is the only edited filament bool is_the_only_edited_filament(unsigned int filament_index); @@ -126,8 +126,8 @@ public: // Load user configuration and store it into the user profiles. // This method is called by the configuration wizard. - void load_config_from_wizard(const std::string &name, DynamicPrintConfig config) - { this->load_config_file_config(name, false, std::move(config)); } + void load_config_from_wizard(const std::string &name, DynamicPrintConfig config, Semver file_version, bool is_custom_defined = false) + { this->load_config_file_config(name, false, std::move(config), file_version, true, is_custom_defined); } // Load configuration that comes from a model file containing configuration, such as 3MF et al. // This method is called by the Plater. @@ -225,7 +225,7 @@ private: // Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path. // and the external config is just referenced, not stored into user profile directory. // If it is not an external config, then the config will be stored into the user profile directory. - void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version = Semver()); + void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version = Semver(), bool selected = false, bool is_custom_defined = false); /*ConfigSubstitutions load_config_file_config_bundle( const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);*/ diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 095451de0b..ce5a4505d9 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -24,6 +24,11 @@ #include #include +//BBS: add json support +#include "nlohmann/json.hpp" + +using namespace nlohmann; + // Mark string for localization and translate. #define L(s) Slic3r::I18N::translate(s) @@ -90,12 +95,14 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "fan_cooling_layer_time", "full_fan_speed_layer", "filament_colour", + "default_filament_colour", "filament_diameter", "filament_density", "filament_cost", "outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration", + "outer_wall_acceleration", "top_surface_acceleration", "travel_acceleration", // BBS @@ -136,7 +143,10 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "curr_bed_type", "nozzle_volume", "chamber_temperature", - "thumbnails" + "thumbnails", + "nozzle_hrc", + "required_nozzle_HRC", + "upward_compatible_machine" }; static std::unordered_set steps_ignore; @@ -399,10 +409,18 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print const PrintInstance *print_instance; BoundingBox bounding_box; Polygon hull_polygon; - int index; + int object_index; double arrange_score; double height; }; + auto find_object_index = [](const Model& model, const ModelObject* obj) { + for (int index = 0; index < model.objects.size(); index++) + { + if (model.objects[index] == obj) + return index; + } + return -1; + }; std::vector print_instance_with_bounding_box; { // sequential_print_horizontal_clearance_valid @@ -452,7 +470,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print single_object_exception.object = instance.model_instance->get_object(); } else { - single_object_exception.string += (boost::format(L("\n%1% is too close to exclusion area, there may be collisions when printing.")) %instance.model_instance->get_object()->name).str(); + single_object_exception.string += "\n"+(boost::format(L("%1% is too close to exclusion area, there may be collisions when printing.")) %instance.model_instance->get_object()->name).str(); single_object_exception.object = nullptr; } //if (polygons) { @@ -480,6 +498,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print } struct print_instance_info print_info {&instance, convex_hull.bounding_box(), convex_hull}; print_info.height = instance.print_object->height(); + print_info.object_index = find_object_index(print.model(), print_object->model_object()); print_instance_with_bounding_box.push_back(std::move(print_info)); convex_hulls_other.emplace_back(std::move(convex_hull)); } @@ -499,6 +518,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print double hc2 = scale_(print.config().extruder_clearance_height_to_rod); // height to rod double printable_height = scale_(print.config().printable_height); +#if 0 //do not sort anymore, use the order in object list auto bed_points = get_bed_shape(print_config); float bed_width = bed_points[1].x() - bed_points[0].x(); // 如果扩大以后的多边形的距离小于这个值,就需要严格保证从左到右的打印顺序,否则会撞工具头右侧 @@ -511,17 +531,17 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print } }; std::unordered_set left_right_pair; // pairs in this vector must strictly obey the left-right order - for (size_t i = 0; i < print_instance_with_bounding_box.size();i++) { + for (size_t i = 0; i < print_instance_with_bounding_box.size();i++) { auto &inst = print_instance_with_bounding_box[i]; inst.index = i; Point pt = inst.bounding_box.center(); inst.arrange_score = pt.x() / 2 + pt.y(); // we prefer print row-by-row, so cost on x-direction is smaller } for (size_t i = 0; i < print_instance_with_bounding_box.size(); i++) { - auto &inst = print_instance_with_bounding_box[i]; + auto &inst = print_instance_with_bounding_box[i]; auto &l = print_instance_with_bounding_box[i]; for (size_t j = 0; j < print_instance_with_bounding_box.size(); j++) { - if (j != i) { + if (j != i) { auto &r = print_instance_with_bounding_box[j]; auto ly1 = l.bounding_box.min.y(); auto ly2 = l.bounding_box.max.y(); @@ -534,12 +554,9 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print auto inter_min = std::max(ly1, ry1); auto inter_max = std::min(ly2, ry2); auto inter_y = inter_max - inter_min; - inter_min = std::max(lx1, rx1); - inter_max = std::min(lx2, rx2); - auto inter_x = inter_max - inter_min; // 如果y方向的重合超过轮廓的膨胀量,说明两个物体在一行,应该先打左边的物体,即先比较二者的x坐标。 - if (inter_y > scale_(1)) { + if (inter_y > scale_(0.5 * print.config().extruder_clearance_radius.value)) { if (std::max(rx1 - lx2, lx1 - rx2) < unsafe_dist) { if (lx1 > rx1) { left_right_pair.insert({j, i}); @@ -551,7 +568,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print << " -> " << r.print_instance->model_instance->get_object()->name << "(" << r.arrange_score << ")"; } } - } + } if (l.height > hc1 && r.height < hc1) { // 当前物体超过了顶盖高度,必须后打 left_right_pair.insert({j, i}); @@ -560,7 +577,8 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print } else if (l.height > hc2 && l.height > r.height && l.arrange_scorehc2, print_instance " << inst.print_instance->model_instance->get_object()->name << ", right=" << r.print_instance->model_instance->get_object()->name << ", l.score: " << l.arrange_score << ", r.score: " << r.arrange_score; @@ -568,7 +586,6 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print } } } - BOOST_LOG_TRIVIAL(debug) << "bed width: " << bed_width << ", unsafe_dist:" << unsafe_dist; // 多做几次代价传播,因为前一次有些值没有更新。 // TODO 更好的办法是建立一颗树,一步到位。不过我暂时没精力搞,先就这样吧 for (int k=0;k<5;k++) @@ -576,14 +593,15 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print auto &l = print_instance_with_bounding_box[p(0)]; auto &r = print_instance_with_bounding_box[p(1)]; if(r.arrange_scoremodel_instance->get_object()->name << "(" << l.arrange_score << ")" - << " -> " << r.print_instance->model_instance->get_object()->name << "(" << r.arrange_score << ")"; + BOOST_LOG_TRIVIAL(debug) << "print_instance " << I18N::translate(l.print_instance->model_instance->get_object()->name) << "(" << l.arrange_score << ")" + << " -> " << I18N::translate(r.print_instance->model_instance->get_object()->name) << "(" << r.arrange_score << ")"; } // sort the print instance std::sort(print_instance_with_bounding_box.begin(), print_instance_with_bounding_box.end(), @@ -592,7 +610,16 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print for (auto &inst : print_instance_with_bounding_box) BOOST_LOG_TRIVIAL(debug) << "after sorting print_instance " << inst.print_instance->model_instance->get_object()->name << ", score: " << inst.arrange_score << ", height:"<< inst.height; +#else + // sort the print instance + std::sort(print_instance_with_bounding_box.begin(), print_instance_with_bounding_box.end(), + [](print_instance_info& l, print_instance_info& r) {return l.object_index < r.object_index;}); + for (auto &inst : print_instance_with_bounding_box) + BOOST_LOG_TRIVIAL(debug) << "after sorting print_instance " << inst.print_instance->model_instance->get_object()->name << ", object_index: " << inst.object_index + << ", height:"<< inst.height; + +#endif // sequential_print_vertical_clearance_valid { // Ignore the last instance printed. @@ -622,7 +649,6 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print break; }*/ - // if objects are not overlapped on y-axis, they will not collide even if they are taller than extruder_clearance_height_to_rod int print_instance_count = print_instance_with_bounding_box.size(); std::map> too_tall_instances; @@ -790,7 +816,7 @@ static StringObjectException layered_print_cleareance_valid(const Print &print, static std::map filament_is_high_temp { {"PLA", false}, {"PLA-CF", false}, - {"PETG", true}, + //{"PETG", true}, {"ABS", true}, {"TPU", false}, {"PA", true}, @@ -837,7 +863,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* if (extruders.empty()) return { L("No extrusions under current settings.") }; - if (extruders.size() > 1) { + if (extruders.size() > 1 && m_config.print_sequence != PrintSequence::ByObject) { auto ret = check_multi_filament_valid(*this); if (!ret.string.empty()) return ret; @@ -954,16 +980,26 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* } // BBS: remove obsolete logics and _L() -#if 0 if (has_custom_layering) { - for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) { - if (idx_object == tallest_object_idx) - continue; - if (layer_height_profiles[idx_object] != layer_height_profiles[tallest_object_idx]) - return {("The prime tower is only supported if all objects have the same variable layer height"), m_objects[idx_object]}; + for (size_t idx_object = 0; idx_object < m_objects.size(); ++idx_object) { + if (idx_object == tallest_object_idx) continue; + // Check that the layer height profiles are equal. This will happen when one object is + // a copy of another, or when a layer height modifier is used the same way on both objects. + // The latter case might create a floating point inaccuracy mismatch, so compare + // element-wise using an epsilon check. + size_t i = 0; + const coordf_t eps = 0.5 * EPSILON; // layers closer than EPSILON will be merged later. Let's make + // this check a bit more sensitive to make sure we never consider two different layers as one. + while (i < layer_height_profiles[idx_object].size() && i < layer_height_profiles[tallest_object_idx].size()) { + // BBS: remove the break condition, because a variable layer height object and a new object will not be checked when slicing + //if (i % 2 == 0 && layer_height_profiles[tallest_object_idx][i] > layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2]) + // break; + if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps) + return {L("The prime tower is only supported if all objects have the same variable layer height")}; + ++i; + } } } -#endif } } @@ -1079,28 +1115,34 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* } -// 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; -// for (unsigned int extruder_id : extruders) { -// const ConfigOptionInts* bed_temp_opt = m_config.option(get_bed_temp_key(m_config.curr_bed_type)); -// for (unsigned int extruder_id : extruders) { -// int curr_bed_temp = bed_temp_opt->get_at(extruder_id); -// if (curr_bed_temp == 0 && bed_type_keys_map != nullptr) { -// std::string bed_type_name; -// for (auto item : *bed_type_keys_map) { -// if (item.second == m_config.curr_bed_type) { -// bed_type_name = item.first; -// break; -// } -// } -// -// return { format(L("Plate %d: %s does not support filament %s.\n"), this->get_plate_index() + 1, -// L(bed_type_name), extruder_id + 1) }; -// } -// } -// } + 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; + for (unsigned int extruder_id : extruders) { + const ConfigOptionInts* bed_temp_opt = m_config.option(get_bed_temp_key(m_config.curr_bed_type)); + for (unsigned int extruder_id : extruders) { + int curr_bed_temp = bed_temp_opt->get_at(extruder_id); + if (curr_bed_temp == 0 && bed_type_keys_map != nullptr) { + std::string bed_type_name; + for (auto item : *bed_type_keys_map) { + if (item.second == m_config.curr_bed_type) { + bed_type_name = item.first; + break; + } + } + + StringObjectException except; + except.string = format(L("Plate %d: %s does not support filament %s\n"), this->get_plate_index() + 1, L(bed_type_name), extruder_id + 1); + except.type = STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE; + except.params.push_back(std::to_string(this->get_plate_index() + 1)); + except.params.push_back(L(bed_type_name)); + except.params.push_back(std::to_string(extruder_id+1)); + except.object = nullptr; + return except; + } + } + } return {}; } @@ -1315,12 +1357,15 @@ std::map getObjectExtruderMap(const Print& print) { } // Slicing process, running at a background thread. -void Print::process() +void Print::process(bool use_cache) { name_tbb_thread_pool_threads_set_locale(); //compute the PrintObject with the same geometries - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter")%this; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter, use_cache=%2%, object size=%3%")%this%use_cache%m_objects.size(); + if (m_objects.empty()) + return; + for (PrintObject *obj : m_objects) obj->clear_shared_object(); @@ -1366,58 +1411,105 @@ void Print::process() }; int object_count = m_objects.size(); std::set need_slicing_objects; - for (int index = 0; index < object_count; index++) - { - PrintObject *obj = m_objects[index]; - for (PrintObject *slicing_obj : need_slicing_objects) + if (!use_cache) { + for (int index = 0; index < object_count; index++) { - if (is_print_object_the_same(obj, slicing_obj)) { - obj->set_shared_object(slicing_obj); - break; + PrintObject *obj = m_objects[index]; + for (PrintObject *slicing_obj : need_slicing_objects) + { + if (is_print_object_the_same(obj, slicing_obj)) { + obj->set_shared_object(slicing_obj); + break; + } + } + if (!obj->get_shared_object()) + need_slicing_objects.insert(obj); + } + } + else { + for (int index = 0; index < object_count; index++) + { + PrintObject *obj = m_objects[index]; + if (obj->layer_count() > 0) + need_slicing_objects.insert(obj); + } + for (int index = 0; index < object_count; index++) + { + PrintObject *obj = m_objects[index]; + if (need_slicing_objects.find(obj) == need_slicing_objects.end()) { + for (PrintObject *slicing_obj : need_slicing_objects) + { + if (is_print_object_the_same(obj, slicing_obj)) { + obj->set_shared_object(slicing_obj); + break; + } + } } } - if (!obj->get_shared_object()) - need_slicing_objects.insert(obj); } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": total object counts %1% in current print, need to slice %2%")%m_objects.size()%need_slicing_objects.size(); BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info(); - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->make_perimeters(); + if (!use_cache) { + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->make_perimeters(); + } + else { + if (obj->set_started(posSlice)) + obj->set_done(posSlice); + if (obj->set_started(posPerimeters)) + obj->set_done(posPerimeters); + } } - else { + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->infill(); + } + else { + if (obj->set_started(posPrepareInfill)) + obj->set_done(posPrepareInfill); + if (obj->set_started(posInfill)) + obj->set_done(posInfill); + } + } + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->ironing(); + } + else { + if (obj->set_started(posIroning)) + obj->set_done(posIroning); + } + } + + tbb::parallel_for(tbb::blocked_range(0, int(m_objects.size())), + [this, need_slicing_objects](const tbb::blocked_range& range) { + for (int i = range.begin(); i < range.end(); i++) { + PrintObject* obj = m_objects[i]; + if (need_slicing_objects.count(obj) != 0) { + obj->generate_support_material(); + } + else { + if (obj->set_started(posSupportMaterial)) + obj->set_done(posSupportMaterial); + } + } + } + ); + } + else { + for (PrintObject *obj : m_objects) { if (obj->set_started(posSlice)) obj->set_done(posSlice); if (obj->set_started(posPerimeters)) obj->set_done(posPerimeters); - } - } - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->infill(); - } - else { if (obj->set_started(posPrepareInfill)) obj->set_done(posPrepareInfill); if (obj->set_started(posInfill)) obj->set_done(posInfill); - } - } - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->ironing(); - } - else { if (obj->set_started(posIroning)) obj->set_done(posIroning); - } - } - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->generate_support_material(); - } - else { if (obj->set_started(posSupportMaterial)) obj->set_done(posSupportMaterial); } @@ -1428,6 +1520,7 @@ void Print::process() if (need_slicing_objects.count(obj) == 0) obj->copy_layers_from_shared_object(); } + if (this->set_started(psWipeTower)) { m_wipe_tower_data.clear(); m_tool_ordering.clear(); @@ -1531,7 +1624,7 @@ void Print::process() } //BBS for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { + if ((!use_cache)&&(need_slicing_objects.count(obj) != 0)) { obj->simplify_extrusion_path(); } else { @@ -1940,23 +2033,22 @@ void Print::_make_wipe_tower() for (auto &layer_tools : m_wipe_tower_data.tool_ordering.layer_tools()) { // for all layers if (!layer_tools.has_wipe_tower) continue; bool first_layer = &layer_tools == &m_wipe_tower_data.tool_ordering.front(); - wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id, false); + wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id); for (const auto extruder_id : layer_tools.extruders) { // BBS: priming logic is removed, so no need to do toolchange for first extruder if (/*(first_layer && extruder_id == m_wipe_tower_data.tool_ordering.all_extruders().back()) || */extruder_id != current_extruder_id) { float volume_to_purge = wipe_volumes[current_extruder_id][extruder_id]; + volume_to_purge *= m_config.flush_multiplier; // Not all of that can be used for infill purging: //volume_to_purge -= (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); - volume_to_purge -= (float)m_config.nozzle_volume; // try to assign some infills/objects for the wiping: volume_to_purge = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_purge); // add back the minimal amount toforce on the wipe tower: //volume_to_purge += (float)m_config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id); - volume_to_purge += (float)m_config.nozzle_volume; // request a toolchange at the wipe tower with at least volume_to_wipe purging amount wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, @@ -2098,4 +2190,1278 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co return final_path; } +/*add json export/import related functions */ +#define JSON_POLYGON_CONTOUR "contour" +#define JSON_POLYGON_HOLES "holes" +#define JSON_POINTS "points" +#define JSON_EXPOLYGON "expolygon" +#define JSON_ARC_FITTING "arc_fitting" +#define JSON_OBJECT_NAME "name" +#define JSON_ARRANGE_ORDER "arrange_order" + + +#define JSON_LAYERS "layers" +#define JSON_SUPPORT_LAYERS "support_layers" +#define JSON_TREE_SUPPORT_LAYERS "tree_support_layers" +#define JSON_LAYER_REGIONS "layer_regions" + + +#define JSON_LAYER_PRINT_Z "print_z" +#define JSON_LAYER_SLICE_Z "slice_z" +#define JSON_LAYER_HEIGHT "height" +#define JSON_LAYER_ID "layer_id" +#define JSON_LAYER_SLICED_POLYGONS "sliced_polygons" +#define JSON_LAYER_SLLICED_BBOXES "sliced_bboxes" + +#define JSON_SUPPORT_LAYER_ISLANDS "support_islands" +#define JSON_SUPPORT_LAYER_FILLS "support_fills" +#define JSON_SUPPORT_LAYER_INTERFACE_ID "interface_id" + + +#define JSON_LAYER_REGION_CONFIG_HASH "config_hash" +#define JSON_LAYER_REGION_SLICES "slices" +#define JSON_LAYER_REGION_RAW_SLICES "raw_slices" +//#define JSON_LAYER_REGION_ENTITIES "entities" +#define JSON_LAYER_REGION_THIN_FILLS "thin_fills" +#define JSON_LAYER_REGION_FILL_EXPOLYGONS "fill_expolygons" +#define JSON_LAYER_REGION_FILL_SURFACES "fill_surfaces" +#define JSON_LAYER_REGION_FILL_NO_OVERLAP "fill_no_overlap_expolygons" +#define JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES "unsupported_bridge_edges" +#define JSON_LAYER_REGION_PERIMETERS "perimeters" +#define JSON_LAYER_REGION_FILLS "fills" + + + +#define JSON_SURF_TYPE "surface_type" +#define JSON_SURF_THICKNESS "thickness" +#define JSON_SURF_THICKNESS_LAYER "thickness_layers" +#define JSON_SURF_BRIDGE_ANGLE "bridge_angle" +#define JSON_SURF_EXTRA_PERIMETERS "extra_perimeters" + +#define JSON_ARC_DATA "arc_data" +#define JSON_ARC_START_INDEX "start_index" +#define JSON_ARC_END_INDEX "end_index" +#define JSON_ARC_PATH_TYPE "path_type" + +#define JSON_IS_ARC "is_arc" +#define JSON_ARC_LENGTH "length" +#define JSON_ARC_ANGLE_RADIUS "angle_radians" +#define JSON_ARC_POLAY_START_THETA "polar_start_theta" +#define JSON_ARC_POLAY_END_THETA "polar_end_theta" +#define JSON_ARC_START_POINT "start_point" +#define JSON_ARC_END_POINT "end_point" +#define JSON_ARC_DIRECTION "direction" +#define JSON_ARC_RADIUS "radius" +#define JSON_ARC_CENTER "center" + +//extrusions +#define JSON_EXTRUSION_ENTITY_TYPE "entity_type" +#define JSON_EXTRUSION_NO_SORT "no_sort" +#define JSON_EXTRUSION_PATHS "paths" +#define JSON_EXTRUSION_ENTITIES "entities" +#define JSON_EXTRUSION_TYPE_PATH "path" +#define JSON_EXTRUSION_TYPE_MULTIPATH "multipath" +#define JSON_EXTRUSION_TYPE_LOOP "loop" +#define JSON_EXTRUSION_TYPE_COLLECTION "collection" +#define JSON_EXTRUSION_POLYLINE "polyline" +#define JSON_EXTRUSION_OVERHANG_DEGREE "overhang_degree" +#define JSON_EXTRUSION_CURVE_DEGREE "curve_degree" +#define JSON_EXTRUSION_MM3_PER_MM "mm3_per_mm" +#define JSON_EXTRUSION_WIDTH "width" +#define JSON_EXTRUSION_HEIGHT "height" +#define JSON_EXTRUSION_ROLE "role" +#define JSON_EXTRUSION_NO_EXTRUSION "no_extrusion" +#define JSON_EXTRUSION_LOOP_ROLE "loop_role" + + +static void to_json(json& j, const Points& p_s) { + for (const Point& p : p_s) + { + j.push_back(p.x()); + j.push_back(p.y()); + } +} + +static void to_json(json& j, const BoundingBox& bb) { + j.push_back(bb.min.x()); + j.push_back(bb.min.y()); + j.push_back(bb.max.x()); + j.push_back(bb.max.y()); +} + +static void to_json(json& j, const ExPolygon& polygon) { + json contour_json = json::array(), holes_json = json::array(); + + //contour + const Polygon& slice_contour = polygon.contour; + contour_json = slice_contour.points; + j[JSON_POLYGON_CONTOUR] = std::move(contour_json); + + //holes + const Polygons& slice_holes = polygon.holes; + for (const Polygon& hole_polyon : slice_holes) + { + json hole_json = json::array(); + hole_json = hole_polyon.points; + holes_json.push_back(std::move(hole_json)); + } + j[JSON_POLYGON_HOLES] = std::move(holes_json); +} + +static void to_json(json& j, const Surface& surf) { + j[JSON_EXPOLYGON] = surf.expolygon; + j[JSON_SURF_TYPE] = surf.surface_type; + j[JSON_SURF_THICKNESS] = surf.thickness; + j[JSON_SURF_THICKNESS_LAYER] = surf.thickness_layers; + j[JSON_SURF_BRIDGE_ANGLE] = surf.bridge_angle; + j[JSON_SURF_EXTRA_PERIMETERS] = surf.extra_perimeters; +} + +static void to_json(json& j, const ArcSegment& arc_seg) { + json start_point_json = json::array(), end_point_json = json::array(), center_point_json = json::array(); + j[JSON_IS_ARC] = arc_seg.is_arc; + j[JSON_ARC_LENGTH] = arc_seg.length; + j[JSON_ARC_ANGLE_RADIUS] = arc_seg.angle_radians; + j[JSON_ARC_POLAY_START_THETA] = arc_seg.polar_start_theta; + j[JSON_ARC_POLAY_END_THETA] = arc_seg.polar_end_theta; + start_point_json.push_back(arc_seg.start_point.x()); + start_point_json.push_back(arc_seg.start_point.y()); + j[JSON_ARC_START_POINT] = std::move(start_point_json); + end_point_json.push_back(arc_seg.end_point.x()); + end_point_json.push_back(arc_seg.end_point.y()); + j[JSON_ARC_END_POINT] = std::move(end_point_json); + j[JSON_ARC_DIRECTION] = arc_seg.direction; + j[JSON_ARC_RADIUS] = arc_seg.radius; + center_point_json.push_back(arc_seg.center.x()); + center_point_json.push_back(arc_seg.center.y()); + j[JSON_ARC_CENTER] = std::move(center_point_json); +} + + +static void to_json(json& j, const Polyline& poly_line) { + json points_json = json::array(), fittings_json = json::array(); + points_json = poly_line.points; + + j[JSON_POINTS] = std::move(points_json); + for (const PathFittingData& path_fitting : poly_line.fitting_result) + { + json fitting_json; + fitting_json[JSON_ARC_START_INDEX] = path_fitting.start_point_index; + fitting_json[JSON_ARC_END_INDEX] = path_fitting.end_point_index; + fitting_json[JSON_ARC_PATH_TYPE] = path_fitting.path_type; + if (path_fitting.arc_data.is_arc) + fitting_json[JSON_ARC_DATA] = path_fitting.arc_data; + + fittings_json.push_back(std::move(fitting_json)); + } + j[JSON_ARC_FITTING] = fittings_json; +} + +static void to_json(json& j, const ExtrusionPath& extrusion_path) { + j[JSON_EXTRUSION_POLYLINE] = extrusion_path.polyline; + j[JSON_EXTRUSION_OVERHANG_DEGREE] = extrusion_path.overhang_degree; + j[JSON_EXTRUSION_CURVE_DEGREE] = extrusion_path.curve_degree; + j[JSON_EXTRUSION_MM3_PER_MM] = extrusion_path.mm3_per_mm; + j[JSON_EXTRUSION_WIDTH] = extrusion_path.width; + j[JSON_EXTRUSION_HEIGHT] = extrusion_path.height; + j[JSON_EXTRUSION_ROLE] = extrusion_path.role(); + j[JSON_EXTRUSION_NO_EXTRUSION] = extrusion_path.is_force_no_extrusion(); +} + +static bool convert_extrusion_to_json(json& entity_json, json& entity_paths_json, const ExtrusionEntity* extrusion_entity) { + std::string path_type; + const ExtrusionPath* path = NULL; + const ExtrusionMultiPath* multipath = NULL; + const ExtrusionLoop* loop = NULL; + const ExtrusionEntityCollection* collection = dynamic_cast(extrusion_entity); + + if (!collection) + path = dynamic_cast(extrusion_entity); + + if (!collection && !path) + multipath = dynamic_cast(extrusion_entity); + + if (!collection && !path && !multipath) + loop = dynamic_cast(extrusion_entity); + + path_type = path?JSON_EXTRUSION_TYPE_PATH:(multipath?JSON_EXTRUSION_TYPE_MULTIPATH:(loop?JSON_EXTRUSION_TYPE_LOOP:JSON_EXTRUSION_TYPE_COLLECTION)); + if (path_type.empty()) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":invalid extrusion path type Found"); + return false; + } + + entity_json[JSON_EXTRUSION_ENTITY_TYPE] = path_type; + + if (path) { + json entity_path_json = *path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + else if (multipath) { + for (const ExtrusionPath& extrusion_path : multipath->paths) + { + json entity_path_json = extrusion_path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + } + else if (loop) { + entity_json[JSON_EXTRUSION_LOOP_ROLE] = loop->loop_role(); + for (const ExtrusionPath& extrusion_path : loop->paths) + { + json entity_path_json = extrusion_path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + } + else { + //recursive collections + entity_json[JSON_EXTRUSION_NO_SORT] = collection->no_sort; + for (const ExtrusionEntity* recursive_extrusion_entity : collection->entities) { + json recursive_entity_json, recursive_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(recursive_entity_json, recursive_entity_paths_json, recursive_extrusion_entity); + if (!ret) { + continue; + } + entity_paths_json.push_back(std::move(recursive_entity_json)); + } + } + + if (collection) + entity_json[JSON_EXTRUSION_ENTITIES] = std::move(entity_paths_json); + else + entity_json[JSON_EXTRUSION_PATHS] = std::move(entity_paths_json); + return true; +} + +static void to_json(json& j, const LayerRegion& layer_region) { + json unsupported_bridge_edges_json = json::array(), slices_surfaces_json = json::array(), raw_slices_json = json::array(), thin_fills_json, thin_fill_entities_json = json::array(); + json fill_expolygons_json = json::array(), fill_no_overlap_expolygons_json = json::array(), fill_surfaces_json = json::array(), perimeters_json, perimeter_entities_json = json::array(), fills_json, fill_entities_json = json::array(); + + j[JSON_LAYER_REGION_CONFIG_HASH] = layer_region.region().config_hash(); + //slices + for (const Surface& slice_surface : layer_region.slices.surfaces) { + json surface_json = slice_surface; + slices_surfaces_json.push_back(std::move(surface_json)); + } + j.push_back({JSON_LAYER_REGION_SLICES, std::move(slices_surfaces_json)}); + + //raw_slices + for (const ExPolygon& raw_slice_explogyon : layer_region.raw_slices) { + json raw_polygon_json = raw_slice_explogyon; + + raw_slices_json.push_back(std::move(raw_polygon_json)); + } + j.push_back({JSON_LAYER_REGION_RAW_SLICES, std::move(raw_slices_json)}); + + //thin fills + thin_fills_json[JSON_EXTRUSION_NO_SORT] = layer_region.thin_fills.no_sort; + thin_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.thin_fills.entities) { + json thinfills_entity_json, thinfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(thinfills_entity_json, thinfill_entity_paths_json, extrusion_entity); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":error found at print_z %1%") % layer_region.layer()->print_z; + continue; + } + + thin_fill_entities_json.push_back(std::move(thinfills_entity_json)); + } + thin_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(thin_fill_entities_json); + j.push_back({JSON_LAYER_REGION_THIN_FILLS, std::move(thin_fills_json)}); + + //fill_expolygons + for (const ExPolygon& fill_expolygon : layer_region.fill_expolygons) { + json fill_expolygon_json = fill_expolygon; + + fill_expolygons_json.push_back(std::move(fill_expolygon_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_EXPOLYGONS, std::move(fill_expolygons_json)}); + + //fill_surfaces + for (const Surface& fill_surface : layer_region.fill_surfaces.surfaces) { + json surface_json = fill_surface; + fill_surfaces_json.push_back(std::move(surface_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_SURFACES, std::move(fill_surfaces_json)}); + + //fill_no_overlap_expolygons + for (const ExPolygon& fill_no_overlap_expolygon : layer_region.fill_no_overlap_expolygons) { + json fill_no_overlap_expolygon_json = fill_no_overlap_expolygon; + + fill_no_overlap_expolygons_json.push_back(std::move(fill_no_overlap_expolygon_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_NO_OVERLAP, std::move(fill_no_overlap_expolygons_json)}); + + //unsupported_bridge_edges + for (const Polyline& poly_line : layer_region.unsupported_bridge_edges) + { + json polyline_json = poly_line; + + unsupported_bridge_edges_json.push_back(std::move(polyline_json)); + } + j.push_back({JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES, std::move(unsupported_bridge_edges_json)}); + + //perimeters + perimeters_json[JSON_EXTRUSION_NO_SORT] = layer_region.perimeters.no_sort; + perimeters_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.perimeters.entities) { + json perimeters_entity_json, perimeters_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(perimeters_entity_json, perimeters_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + perimeter_entities_json.push_back(std::move(perimeters_entity_json)); + } + perimeters_json[JSON_EXTRUSION_ENTITIES] = std::move(perimeter_entities_json); + j.push_back({JSON_LAYER_REGION_PERIMETERS, std::move(perimeters_json)}); + + //fills + fills_json[JSON_EXTRUSION_NO_SORT] = layer_region.fills.no_sort; + fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.fills.entities) { + json fill_entity_json, fill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(fill_entity_json, fill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + fill_entities_json.push_back(std::move(fill_entity_json)); + } + fills_json[JSON_EXTRUSION_ENTITIES] = std::move(fill_entities_json); + j.push_back({JSON_LAYER_REGION_FILLS, std::move(fills_json)}); + + return; +} + +//load apis from json +static void from_json(const json& j, Points& p_s) { + int array_size = j.size(); + for (int index = 0; index < array_size/2; index++) + { + coord_t x = j[2*index], y = j[2*index+1]; + Point p(x, y); + p_s.push_back(std::move(p)); + } + return; +} + +static void from_json(const json& j, BoundingBox& bbox) { + bbox.min[0] = j[0]; + bbox.min[1] = j[1]; + bbox.max[0] = j[2]; + bbox.max[1] = j[3]; + bbox.defined = true; + + return; +} + +static void from_json(const json& j, ExPolygon& polygon) { + polygon.contour.points = j[JSON_POLYGON_CONTOUR]; + + int holes_count = j[JSON_POLYGON_HOLES].size(); + for (int holes_index = 0; holes_index < holes_count; holes_index++) + { + Polygon poly; + + poly.points = j[JSON_POLYGON_HOLES][holes_index]; + polygon.holes.push_back(std::move(poly)); + } + return; +} + +static void from_json(const json& j, Surface& surf) { + surf.expolygon = j[JSON_EXPOLYGON]; + surf.surface_type = j[JSON_SURF_TYPE]; + surf.thickness = j[JSON_SURF_THICKNESS]; + surf.thickness_layers = j[JSON_SURF_THICKNESS_LAYER]; + surf.bridge_angle = j[JSON_SURF_BRIDGE_ANGLE]; + surf.extra_perimeters = j[JSON_SURF_EXTRA_PERIMETERS]; + + return; +} + +static void from_json(const json& j, ArcSegment& arc_seg) { + arc_seg.is_arc = j[JSON_IS_ARC]; + arc_seg.length = j[JSON_ARC_LENGTH]; + arc_seg.angle_radians = j[JSON_ARC_ANGLE_RADIUS]; + arc_seg.polar_start_theta = j[JSON_ARC_POLAY_START_THETA]; + arc_seg.polar_end_theta = j[JSON_ARC_POLAY_END_THETA]; + arc_seg.start_point.x() = j[JSON_ARC_START_POINT][0]; + arc_seg.start_point.y() = j[JSON_ARC_START_POINT][1]; + arc_seg.end_point.x() = j[JSON_ARC_END_POINT][0]; + arc_seg.end_point.y() = j[JSON_ARC_END_POINT][1]; + arc_seg.direction = j[JSON_ARC_DIRECTION]; + arc_seg.radius = j[JSON_ARC_RADIUS]; + arc_seg.center.x() = j[JSON_ARC_CENTER][0]; + arc_seg.center.y() = j[JSON_ARC_CENTER][1]; + + return; +} + + +static void from_json(const json& j, Polyline& poly_line) { + poly_line.points = j[JSON_POINTS]; + + int arc_fitting_count = j[JSON_ARC_FITTING].size(); + for (int arc_fitting_index = 0; arc_fitting_index < arc_fitting_count; arc_fitting_index++) + { + const json& fitting_json = j[JSON_ARC_FITTING][arc_fitting_index]; + PathFittingData path_fitting; + path_fitting.start_point_index = fitting_json[JSON_ARC_START_INDEX]; + path_fitting.end_point_index = fitting_json[JSON_ARC_END_INDEX]; + path_fitting.path_type = fitting_json[JSON_ARC_PATH_TYPE]; + + if (fitting_json.contains(JSON_ARC_DATA)) { + path_fitting.arc_data = fitting_json[JSON_ARC_DATA]; + } + + poly_line.fitting_result.push_back(std::move(path_fitting)); + } + return; +} + +static void from_json(const json& j, ExtrusionPath& extrusion_path) { + extrusion_path.polyline = j[JSON_EXTRUSION_POLYLINE]; + extrusion_path.overhang_degree = j[JSON_EXTRUSION_OVERHANG_DEGREE]; + extrusion_path.curve_degree = j[JSON_EXTRUSION_CURVE_DEGREE]; + extrusion_path.mm3_per_mm = j[JSON_EXTRUSION_MM3_PER_MM]; + extrusion_path.width = j[JSON_EXTRUSION_WIDTH]; + extrusion_path.height = j[JSON_EXTRUSION_HEIGHT]; + extrusion_path.set_extrusion_role(j[JSON_EXTRUSION_ROLE]); + extrusion_path.set_force_no_extrusion(j[JSON_EXTRUSION_NO_EXTRUSION]); +} + +static bool convert_extrusion_from_json(const json& entity_json, ExtrusionEntityCollection& entity_collection) { + std::string path_type = entity_json[JSON_EXTRUSION_ENTITY_TYPE]; + bool ret = false; + + if (path_type == JSON_EXTRUSION_TYPE_PATH) { + ExtrusionPath* path = new ExtrusionPath(); + if (!path) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionPath"); + return false; + } + *path = entity_json[JSON_EXTRUSION_PATHS][0]; + entity_collection.entities.push_back(path); + } + else if (path_type == JSON_EXTRUSION_TYPE_MULTIPATH) { + ExtrusionMultiPath* multipath = new ExtrusionMultiPath(); + if (!multipath) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionMultiPath"); + return false; + } + int paths_count = entity_json[JSON_EXTRUSION_PATHS].size(); + for (int path_index = 0; path_index < paths_count; path_index++) + { + ExtrusionPath path; + path = entity_json[JSON_EXTRUSION_PATHS][path_index]; + multipath->paths.push_back(std::move(path)); + } + entity_collection.entities.push_back(multipath); + } + else if (path_type == JSON_EXTRUSION_TYPE_LOOP) { + ExtrusionLoop* loop = new ExtrusionLoop(); + if (!loop) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionLoop"); + return false; + } + loop->set_loop_role(entity_json[JSON_EXTRUSION_LOOP_ROLE]); + int paths_count = entity_json[JSON_EXTRUSION_PATHS].size(); + for (int path_index = 0; path_index < paths_count; path_index++) + { + ExtrusionPath path; + path = entity_json[JSON_EXTRUSION_PATHS][path_index]; + loop->paths.push_back(std::move(path)); + } + entity_collection.entities.push_back(loop); + } + else if (path_type == JSON_EXTRUSION_TYPE_COLLECTION) { + ExtrusionEntityCollection* collection = new ExtrusionEntityCollection(); + if (!collection) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionEntityCollection"); + return false; + } + collection->no_sort = entity_json[JSON_EXTRUSION_NO_SORT]; + int entities_count = entity_json[JSON_EXTRUSION_ENTITIES].size(); + for (int entity_index = 0; entity_index < entities_count; entity_index++) + { + const json& entity_item_json = entity_json[JSON_EXTRUSION_ENTITIES][entity_index]; + ret = convert_extrusion_from_json(entity_item_json, *collection); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": convert_extrusion_from_json failed"); + return false; + } + } + entity_collection.entities.push_back(collection); + } + else { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": unknown path type %1%")%path_type; + return false; + } + + return true; +} + +static void convert_layer_region_from_json(const json& j, LayerRegion& layer_region) { + //slices + int slices_count = j[JSON_LAYER_REGION_SLICES].size(); + for (int slices_index = 0; slices_index < slices_count; slices_index++) + { + Surface surface; + + surface = j[JSON_LAYER_REGION_SLICES][slices_index]; + layer_region.slices.surfaces.push_back(std::move(surface)); + } + + //raw_slices + int raw_slices_count = j[JSON_LAYER_REGION_RAW_SLICES].size(); + for (int raw_slices_index = 0; raw_slices_index < raw_slices_count; raw_slices_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_RAW_SLICES][raw_slices_index]; + layer_region.raw_slices.push_back(std::move(polygon)); + } + + //thin fills + layer_region.thin_fills.no_sort = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_NO_SORT]; + int thinfills_entities_count = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int thinfills_entities_index = 0; thinfills_entities_index < thinfills_entities_count; thinfills_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_ENTITIES][thinfills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.thin_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":error parsing thin_fills found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing thin_fills at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + //fill_expolygons + int fill_expolygons_count = j[JSON_LAYER_REGION_FILL_EXPOLYGONS].size(); + for (int fill_expolygons_index = 0; fill_expolygons_index < fill_expolygons_count; fill_expolygons_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_FILL_EXPOLYGONS][fill_expolygons_index]; + layer_region.fill_expolygons.push_back(std::move(polygon)); + } + + //fill_surfaces + int fill_surfaces_count = j[JSON_LAYER_REGION_FILL_SURFACES].size(); + for (int fill_surfaces_index = 0; fill_surfaces_index < fill_surfaces_count; fill_surfaces_index++) + { + Surface surface; + + surface = j[JSON_LAYER_REGION_FILL_SURFACES][fill_surfaces_index]; + layer_region.fill_surfaces.surfaces.push_back(std::move(surface)); + } + + //fill_no_overlap_expolygons + int fill_no_overlap_expolygons_count = j[JSON_LAYER_REGION_FILL_NO_OVERLAP].size(); + for (int fill_no_overlap_expolygons_index = 0; fill_no_overlap_expolygons_index < fill_no_overlap_expolygons_count; fill_no_overlap_expolygons_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_FILL_NO_OVERLAP][fill_no_overlap_expolygons_index]; + layer_region.fill_no_overlap_expolygons.push_back(std::move(polygon)); + } + + //unsupported_bridge_edges + int unsupported_bridge_edges_count = j[JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES].size(); + for (int unsupported_bridge_edges_index = 0; unsupported_bridge_edges_index < unsupported_bridge_edges_count; unsupported_bridge_edges_index++) + { + Polyline polyline; + + polyline = j[JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES][unsupported_bridge_edges_index]; + layer_region.unsupported_bridge_edges.push_back(std::move(polyline)); + } + + //perimeters + layer_region.perimeters.no_sort = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_NO_SORT]; + int perimeters_entities_count = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_ENTITIES].size(); + for (int perimeters_entities_index = 0; perimeters_entities_index < perimeters_entities_count; perimeters_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_ENTITIES][perimeters_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.perimeters); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing perimeters found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing perimeters at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + //fills + layer_region.fills.no_sort = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_NO_SORT]; + int fills_entities_count = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int fills_entities_index = 0; fills_entities_index < fills_entities_count; fills_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_ENTITIES][fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + + +void extract_layer(const json& layer_json, Layer& layer) { + //slice_polygons + int slice_polygons_count = layer_json[JSON_LAYER_SLICED_POLYGONS].size(); + for (int polygon_index = 0; polygon_index < slice_polygons_count; polygon_index++) + { + ExPolygon polygon; + + polygon = layer_json[JSON_LAYER_SLICED_POLYGONS][polygon_index]; + layer.lslices.push_back(std::move(polygon)); + } + + //slice_bboxes + int sliced_bboxes_count = layer_json[JSON_LAYER_SLLICED_BBOXES].size(); + for (int bbox_index = 0; bbox_index < sliced_bboxes_count; bbox_index++) + { + BoundingBox bbox; + + bbox = layer_json[JSON_LAYER_SLLICED_BBOXES][bbox_index]; + layer.lslices_bboxes.push_back(std::move(bbox)); + } + + //layer_regions + int layer_region_count = layer.region_count(); + for (int layer_region_index = 0; layer_region_index < layer_region_count; layer_region_index++) + { + LayerRegion* layer_region = layer.get_region(layer_region_index); + const json& layer_region_json = layer_json[JSON_LAYER_REGIONS][layer_region_index]; + convert_layer_region_from_json(layer_region_json, *layer_region); + + //LayerRegion layer_region = layer_json[JSON_LAYER_REGIONS][layer_region_index]; + } + + return; +} + +void extract_support_layer(const json& support_layer_json, SupportLayer& support_layer) { + extract_layer(support_layer_json, support_layer); + + //support_islands + int islands_count = support_layer_json[JSON_SUPPORT_LAYER_ISLANDS].size(); + for (int islands_index = 0; islands_index < islands_count; islands_index++) + { + ExPolygon polygon; + + polygon = support_layer_json[JSON_SUPPORT_LAYER_ISLANDS][islands_index]; + support_layer.support_islands.expolygons.push_back(std::move(polygon)); + } + + //support_fills + support_layer.support_fills.no_sort = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_NO_SORT]; + int support_fills_entities_count = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int support_fills_entities_index = 0; support_fills_entities_index < support_fills_entities_count; support_fills_entities_index++) + { + const json& extrusion_entity_json = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES][support_fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, support_layer.support_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at support_layer %1%, print_z %2%")%support_layer.id() %support_layer.print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at support_layer %d, print_z %f", support_layer.id(), support_layer.print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + +void extract_tree_support_layer(const json& tree_support_layer_json, TreeSupportLayer& tree_support_layer) { + extract_layer(tree_support_layer_json, tree_support_layer); + + //support_fills + tree_support_layer.support_fills.no_sort = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_NO_SORT]; + int treesupport_fills_entities_count = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int treesupport_fills_entities_index = 0; treesupport_fills_entities_index < treesupport_fills_entities_count; treesupport_fills_entities_index++) + { + const json& extrusion_entity_json = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES][treesupport_fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, tree_support_layer.support_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at tree_support_layer %1%, print_z %2%")%tree_support_layer.id() %tree_support_layer.print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at tree_support_layer %d, print_z %f", tree_support_layer.id(), tree_support_layer.print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + +int Print::export_cached_data(const std::string& directory, bool with_space) +{ + int ret = 0; + boost::filesystem::path directory_path(directory); + + auto convert_layer_to_json = [](json& layer_json, const Layer* layer) { + json slice_polygons_json = json::array(), slice_bboxs_json = json::array(), layer_regions_json = json::array(); + layer_json[JSON_LAYER_PRINT_Z] = layer->print_z; + layer_json[JSON_LAYER_HEIGHT] = layer->height; + layer_json[JSON_LAYER_SLICE_Z] = layer->slice_z; + layer_json[JSON_LAYER_ID] = layer->id(); + //layer_json["slicing_errors"] = layer->slicing_errors; + + //sliced_polygons + for (const ExPolygon& slice_polygon : layer->lslices) { + json slice_polygon_json = slice_polygon; + slice_polygons_json.push_back(std::move(slice_polygon_json)); + } + layer_json[JSON_LAYER_SLICED_POLYGONS] = std::move(slice_polygons_json); + + //sliced_bbox + for (const BoundingBox& slice_bbox : layer->lslices_bboxes) { + json bbox_json = json::array(); + + bbox_json = slice_bbox; + slice_bboxs_json.push_back(std::move(bbox_json)); + } + layer_json[JSON_LAYER_SLLICED_BBOXES] = std::move(slice_bboxs_json); + + for (const LayerRegion *layer_region : layer->regions()) { + json region_json = *layer_region; + + layer_regions_json.push_back(std::move(region_json)); + } + layer_json[JSON_LAYER_REGIONS] = std::move(layer_regions_json); + + return; + }; + + //firstly clear this directory + if (fs::exists(directory_path)) { + fs::remove_all(directory_path); + } + if (!fs::create_directory(directory_path)) { + BOOST_LOG_TRIVIAL(error) << boost::format("create directory %1% failed")%directory; + return CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED; + } + + int count = 0; + std::vector filename_vector; + std::vector json_vector; + for (PrintObject *obj : m_objects) { + const ModelObject* model_obj = obj->model_object(); + if (obj->get_shared_object()) { + BOOST_LOG_TRIVIAL(info) << boost::format("shared object %1%, skip directly")%model_obj->name; + continue; + } + BOOST_LOG_TRIVIAL(info) << boost::format("begin to dump object %1%")%model_obj->name; + + const PrintInstance &print_instance = obj->instances()[0]; + const ModelInstance *model_instance = print_instance.model_instance; + int arrange_order = model_instance->arrange_order; + std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + + try { + json root_json, layers_json = json::array(), support_layers_json = json::array(), tree_support_layers_json = json::array(); + + root_json[JSON_OBJECT_NAME] = model_obj->name; + root_json[JSON_ARRANGE_ORDER] = arrange_order; + + //export the layers + std::vector layers_json_vector(obj->layer_count()); + tbb::parallel_for( + tbb::blocked_range(0, obj->layer_count()), + [&layers_json_vector, obj, convert_layer_to_json](const tbb::blocked_range& layer_range) { + for (size_t layer_index = layer_range.begin(); layer_index < layer_range.end(); ++ layer_index) { + const Layer *layer = obj->get_layer(layer_index); + json layer_json; + convert_layer_to_json(layer_json, layer); + layers_json_vector[layer_index] = std::move(layer_json); + } + } + ); + for (int l_index = 0; l_index < layers_json_vector.size(); l_index++) { + layers_json.push_back(std::move(layers_json_vector[l_index])); + } + layers_json_vector.clear(); + /*for (const Layer *layer : obj->layers()) { + // for each layer + json layer_json; + + convert_layer_to_json(layer_json, layer); + + layers_json.push_back(std::move(layer_json)); + }*/ + + root_json[JSON_LAYERS] = std::move(layers_json); + + //export the support layers + std::vector support_layers_json_vector(obj->support_layer_count()); + tbb::parallel_for( + tbb::blocked_range(0, obj->support_layer_count()), + [&support_layers_json_vector, obj, convert_layer_to_json](const tbb::blocked_range& support_layer_range) { + for (size_t s_layer_index = support_layer_range.begin(); s_layer_index < support_layer_range.end(); ++ s_layer_index) { + const SupportLayer *support_layer = obj->get_support_layer(s_layer_index); + json support_layer_json, support_islands_json = json::array(), support_fills_json, supportfills_entities_json = json::array(); + + convert_layer_to_json(support_layer_json, support_layer); + + support_layer_json[JSON_SUPPORT_LAYER_INTERFACE_ID] = support_layer->interface_id(); + + //support_islands + for (const ExPolygon& support_island : support_layer->support_islands.expolygons) { + json support_island_json = support_island; + support_islands_json.push_back(std::move(support_island_json)); + } + support_layer_json[JSON_SUPPORT_LAYER_ISLANDS] = std::move(support_islands_json); + + //support_fills + support_fills_json[JSON_EXTRUSION_NO_SORT] = support_layer->support_fills.no_sort; + support_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : support_layer->support_fills.entities) { + json supportfill_entity_json, supportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(supportfill_entity_json, supportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + supportfills_entities_json.push_back(std::move(supportfill_entity_json)); + } + support_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(supportfills_entities_json); + support_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(support_fills_json); + + support_layers_json_vector[s_layer_index] = std::move(support_layer_json); + } + } + ); + for (int s_index = 0; s_index < support_layers_json_vector.size(); s_index++) { + support_layers_json.push_back(std::move(support_layers_json_vector[s_index])); + } + support_layers_json_vector.clear(); + + /*for (const SupportLayer *support_layer : obj->support_layers()) { + json support_layer_json, support_islands_json = json::array(), support_fills_json, supportfills_entities_json = json::array(); + + convert_layer_to_json(support_layer_json, support_layer); + + support_layer_json[JSON_SUPPORT_LAYER_INTERFACE_ID] = support_layer->interface_id(); + + //support_islands + for (const ExPolygon& support_island : support_layer->support_islands.expolygons) { + json support_island_json = support_island; + support_islands_json.push_back(std::move(support_island_json)); + } + support_layer_json[JSON_SUPPORT_LAYER_ISLANDS] = std::move(support_islands_json); + + //support_fills + support_fills_json[JSON_EXTRUSION_NO_SORT] = support_layer->support_fills.no_sort; + support_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : support_layer->support_fills.entities) { + json supportfill_entity_json, supportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(supportfill_entity_json, supportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + supportfills_entities_json.push_back(std::move(supportfill_entity_json)); + } + support_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(supportfills_entities_json); + support_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(support_fills_json); + + support_layers_json.push_back(std::move(support_layer_json)); + } // for each layer*/ + root_json[JSON_SUPPORT_LAYERS] = std::move(support_layers_json); + + //export the tree support layers + std::vector tree_support_layers_json_vector(obj->tree_support_layer_count()); + tbb::parallel_for( + tbb::blocked_range(0, obj->tree_support_layer_count()), + [&tree_support_layers_json_vector, obj, convert_layer_to_json](const tbb::blocked_range& tree_support_layer_range) { + for (size_t ts_layer_index = tree_support_layer_range.begin(); ts_layer_index < tree_support_layer_range.end(); ++ ts_layer_index) { + const TreeSupportLayer *tree_support_layer = obj->get_tree_support_layer(ts_layer_index); + json treesupport_layer_json, treesupport_fills_json, treesupportfills_entities_json = json::array(); + //json overhang_areas_json = json::array(), roof_areas_json = json::array(), roof_1st_layer_json = json::array(), floor_areas_json = json::array(), base_areas_json = json::array(); + + convert_layer_to_json(treesupport_layer_json, tree_support_layer); + + //tree_support_fills + treesupport_fills_json[JSON_EXTRUSION_NO_SORT] = tree_support_layer->support_fills.no_sort; + treesupport_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : tree_support_layer->support_fills.entities) { + json treesupportfill_entity_json, treesupportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(treesupportfill_entity_json, treesupportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + treesupportfills_entities_json.push_back(std::move(treesupportfill_entity_json)); + } + treesupport_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(treesupportfills_entities_json); + treesupport_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(treesupport_fills_json); + + //following data are not needed in the later stage + //overhang_areas + /*for (const ExPolygon& overhang_area : tree_support_layer->overhang_areas) { + json overhang_area_json = overhang_area; + overhang_areas_json.push_back(std::move(overhang_area_json)); + } + treesupport_layer_json["overhang_areas"] = std::move(overhang_areas_json); + + //roof_areas + for (const ExPolygon& roof_area : tree_support_layer->roof_areas) { + json roof_area_json = roof_area; + roof_areas_json.push_back(std::move(roof_area_json)); + } + treesupport_layer_json["roof_areas"] = std::move(roof_areas_json); + + //roof_1st_layer + for (const ExPolygon& layer_poly : tree_support_layer->roof_1st_layer) { + json layer_poly_json = layer_poly; + roof_1st_layer_json.push_back(std::move(layer_poly_json)); + } + treesupport_layer_json["roof_1st_layer"] = std::move(roof_1st_layer_json); + + //floor_areas + for (const ExPolygon& floor_area : tree_support_layer->floor_areas) { + json floor_area_json = floor_area; + floor_areas_json.push_back(std::move(floor_area_json)); + } + treesupport_layer_json["floor_areas"] = std::move(floor_areas_json); + + //base_areas + for (const ExPolygon& base_area : tree_support_layer->base_areas) { + json base_area_json = base_area; + base_areas_json.push_back(std::move(base_area_json)); + } + treesupport_layer_json["base_areas"] = std::move(base_areas_json);*/ + + tree_support_layers_json_vector[ts_layer_index] = std::move(treesupport_layer_json); + } + } + ); + for (int ts_index = 0; ts_index < tree_support_layers_json_vector.size(); ts_index++) { + tree_support_layers_json.push_back(std::move(tree_support_layers_json_vector[ts_index])); + } + tree_support_layers_json_vector.clear(); +#if 0 + for (const TreeSupportLayer *tree_support_layer : obj->tree_support_layers()) { + json treesupport_layer_json, treesupport_fills_json, treesupportfills_entities_json = json::array(); + json overhang_areas_json = json::array(), roof_areas_json = json::array(), roof_1st_layer_json = json::array(), floor_areas_json = json::array(), base_areas_json = json::array(); + + convert_layer_to_json(treesupport_layer_json, tree_support_layer); + + //tree_support_fills + treesupport_fills_json[JSON_EXTRUSION_NO_SORT] = tree_support_layer->support_fills.no_sort; + treesupport_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : tree_support_layer->support_fills.entities) { + json treesupportfill_entity_json, treesupportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(treesupportfill_entity_json, treesupportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + treesupportfills_entities_json.push_back(std::move(treesupportfill_entity_json)); + } + treesupport_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(treesupportfills_entities_json); + treesupport_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(treesupport_fills_json); + + //overhang_areas + /*for (const ExPolygon& overhang_area : tree_support_layer->overhang_areas) { + json overhang_area_json = overhang_area; + overhang_areas_json.push_back(std::move(overhang_area_json)); + } + treesupport_layer_json["overhang_areas"] = std::move(overhang_areas_json); + + //roof_areas + for (const ExPolygon& roof_area : tree_support_layer->roof_areas) { + json roof_area_json = roof_area; + roof_areas_json.push_back(std::move(roof_area_json)); + } + treesupport_layer_json["roof_areas"] = std::move(roof_areas_json); + + //roof_1st_layer + for (const ExPolygon& layer_poly : tree_support_layer->roof_1st_layer) { + json layer_poly_json = layer_poly; + roof_1st_layer_json.push_back(std::move(layer_poly_json)); + } + treesupport_layer_json["roof_1st_layer"] = std::move(roof_1st_layer_json); + + //floor_areas + for (const ExPolygon& floor_area : tree_support_layer->floor_areas) { + json floor_area_json = floor_area; + floor_areas_json.push_back(std::move(floor_area_json)); + } + treesupport_layer_json["floor_areas"] = std::move(floor_areas_json); + + //base_areas + for (const ExPolygon& base_area : tree_support_layer->base_areas) { + json base_area_json = base_area; + base_areas_json.push_back(std::move(base_area_json)); + } + treesupport_layer_json["base_areas"] = std::move(base_areas_json);*/ + + tree_support_layers_json.push_back(std::move(treesupport_layer_json)); + } // for each layer +#endif + root_json[JSON_TREE_SUPPORT_LAYERS] = std::move(tree_support_layers_json); + + filename_vector.push_back(file_name); + json_vector.push_back(std::move(root_json)); + /*boost::nowide::ofstream c; + c.open(file_name, std::ios::out | std::ios::trunc); + if (with_space) + c << std::setw(4) << root_json << std::endl; + else + c << root_json.dump(0) << std::endl; + c.close();*/ + count ++; + BOOST_LOG_TRIVIAL(info) << boost::format("will dump object %1%'s json to %2%.")%model_obj->name%file_name; + } + catch(std::exception &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": save to "< const PrintRegion* { + int regions_count = object->num_printing_regions(); + for (int index = 0; index < regions_count; index++ ) + { + const PrintRegion& print_region = object->printing_region(index); + if (print_region.config_hash() == config_hash ) { + return &print_region; + } + } + return NULL; + }; + + int count = 0; + std::vector> object_filenames; + for (PrintObject *obj : m_objects) { + const ModelObject* model_obj = obj->model_object(); + const PrintInstance &print_instance = obj->instances()[0]; + const ModelInstance *model_instance = print_instance.model_instance; + + obj->clear_layers(); + obj->clear_support_layers(); + obj->clear_tree_support_layers(); + + int arrange_order = model_instance->arrange_order; + if (arrange_order <= 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": object %1% has invalid arrange_order %2%, can not load cached_data")%model_obj->name %arrange_order; + continue; + } + std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + + if (!fs::exists(file_name)) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__< object_jsons(object_filenames.size()); + tbb::parallel_for( + tbb::blocked_range(0, object_filenames.size()), + [object_filenames, &ret, &object_jsons, &mutex](const tbb::blocked_range& filename_range) { + for (size_t filename_index = filename_range.begin(); filename_index < filename_range.end(); ++ filename_index) { + try { + json root_json; + boost::nowide::ifstream ifs(object_filenames[filename_index].first); + ifs >> root_json; + object_jsons[filename_index] = std::move(root_json); + } + catch(std::exception &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": load from "<> root_json; + + std::string name = root_json.at(JSON_OBJECT_NAME); + int order = root_json.at(JSON_ARRANGE_ORDER); + int layer_count = 0, support_layer_count = 0, treesupport_layer_count = 0; + + layer_count = root_json[JSON_LAYERS].size(); + support_layer_count = root_json[JSON_SUPPORT_LAYERS].size(); + treesupport_layer_count = root_json[JSON_TREE_SUPPORT_LAYERS].size(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<add_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z], layer_json[JSON_LAYER_SLICE_Z]); + if (!new_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":create_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_layer) { + previous_layer->upper_layer = new_layer; + new_layer->lower_layer = previous_layer; + } + previous_layer = new_layer; + + //layer regions + int layer_regions_count = layer_json[JSON_LAYER_REGIONS].size(); + for (int region_index = 0; region_index < layer_regions_count; region_index++) + { + json& region_json = layer_json[JSON_LAYER_REGIONS][region_index]; + size_t config_hash = region_json[JSON_LAYER_REGION_CONFIG_HASH]; + const PrintRegion *print_region = find_region(obj, config_hash); + + if (!print_region){ + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":can not find print region of object %1%, layer %2%, print_z %3%, layer_region %4%") + %name % index %new_layer->print_z %region_index; + //delete new_layer; + return CLI_IMPORT_CACHE_DATA_CAN_NOT_USE; + } + + new_layer->add_region(print_region); + } + + } + + //load the layer data parallel + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<(0, obj->layer_count()), + [&root_json, &obj](const tbb::blocked_range& layer_range) { + for (size_t layer_index = layer_range.begin(); layer_index < layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_LAYERS][layer_index]; + Layer* layer = obj->get_layer(layer_index); + extract_layer(layer_json, *layer); + } + } + ); + + //support layers + Layer* previous_support_layer = NULL; + //create support_layers + for (int index = 0; index < support_layer_count; index++) + { + json& layer_json = root_json[JSON_SUPPORT_LAYERS][index]; + SupportLayer* new_support_layer = obj->add_support_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_SUPPORT_LAYER_INTERFACE_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z]); + if (!new_support_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":add_support_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_support_layer) { + previous_support_layer->upper_layer = new_support_layer; + new_support_layer->lower_layer = previous_support_layer; + } + previous_support_layer = new_support_layer; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": finished load layers, start to load support_layers."); + tbb::parallel_for( + tbb::blocked_range(0, obj->support_layer_count()), + [&root_json, &obj](const tbb::blocked_range& support_layer_range) { + for (size_t layer_index = support_layer_range.begin(); layer_index < support_layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_SUPPORT_LAYERS][layer_index]; + SupportLayer* support_layer = obj->get_support_layer(layer_index); + extract_support_layer(layer_json, *support_layer); + } + } + ); + + //tree support layers + Layer* previous_tree_support_layer = NULL; + //create tree_support_layers + for (int index = 0; index < treesupport_layer_count; index++) + { + json& layer_json = root_json[JSON_TREE_SUPPORT_LAYERS][index]; + TreeSupportLayer* new_tree_support_layer = obj->add_tree_support_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z], layer_json[JSON_LAYER_SLICE_Z]); + if (!new_tree_support_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":add_support_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_tree_support_layer) { + previous_tree_support_layer->upper_layer = new_tree_support_layer; + new_tree_support_layer->lower_layer = previous_tree_support_layer; + } + previous_tree_support_layer = new_tree_support_layer; + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": finished load support_layers, start to load treesupport_layers."); + tbb::parallel_for( + tbb::blocked_range(0, obj->tree_support_layer_count()), + [&root_json, &obj](const tbb::blocked_range& tree_support_layer_range) { + for (size_t layer_index = tree_support_layer_range.begin(); layer_index < tree_support_layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_TREE_SUPPORT_LAYERS][layer_index]; + TreeSupportLayer* tree_support_layer = obj->get_tree_support_layer(layer_index); + extract_tree_support_layer(layer_json, *tree_support_layer); + } + } + ); + + count ++; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": load object %1% from %2% successfully.")%count%object_filenames[obj_index].first; + } + catch(nlohmann::detail::parse_error &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<>* height_polygons = nullptr); @@ -777,6 +781,7 @@ private: // Estimated print time, filament consumed. PrintStatistics m_print_statistics; + bool m_support_used {false}; //BBS: plate's origin Vec3d m_origin; @@ -793,6 +798,7 @@ public: static float min_skirt_length; }; + } /* slic3r_Print_hpp_ */ #endif diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index f78f6c52d2..c43c9111e0 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -97,7 +97,7 @@ static inline void layer_height_ranges_copy_configs(t_layer_config_ranges &lr_ds } } -static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs) +static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d &rhs) { typedef Transform3d::Scalar T; const T *lv = lhs.data(); @@ -111,7 +111,7 @@ static inline bool transform3d_lower(const Transform3d &lhs, const Transform3d & return false; } -static inline bool transform3d_equal(const Transform3d &lhs, const Transform3d &rhs) +static inline bool transform3d_equal(const Transform3d &lhs, const Transform3d &rhs) { typedef Transform3d::Scalar T; const T *lv = lhs.data(); @@ -434,7 +434,7 @@ struct PrintObjectStatus { New }; - PrintObjectStatus(PrintObject *print_object, Status status = Unknown) : + PrintObjectStatus(PrintObject *print_object, Status status = Unknown) : id(print_object->model_object()->id()), print_object(print_object), trafo(print_object->trafo()), @@ -445,7 +445,7 @@ struct PrintObjectStatus { ObjectID id; // Pointer to the old PrintObject PrintObject *print_object; - // Trafo generated with model_object->world_matrix(true) + // Trafo generated with model_object->world_matrix(true) Transform3d trafo; Status status; @@ -464,7 +464,7 @@ public: } struct iterator_range : std::pair - { + { using std::pair::pair; iterator_range(const std::pair in) : std::pair(in) {} @@ -549,7 +549,7 @@ static PrintObjectRegions::BoundingBox transformed_its_bbox2d(const indexed_tria } static void transformed_its_bboxes_in_z_ranges( - const indexed_triangle_set &its, + const indexed_triangle_set &its, const Transform3f &m, const std::vector &z_ranges, std::vector> &bboxes, @@ -732,7 +732,7 @@ bool verify_update_print_object_regions( assert(next_region_id == int(layer_range.volume_regions.size()) || layer_range.volume_regions[next_region_id].model_volume != region.model_volume || layer_range.volume_regions[next_region_id].parent <= parent_region_id); - if (next_region_id < int(layer_range.volume_regions.size()) && + if (next_region_id < int(layer_range.volume_regions.size()) && layer_range.volume_regions[next_region_id].model_volume == region.model_volume && layer_range.volume_regions[next_region_id].parent == parent_region_id) { // A parent region is already overridden. @@ -767,7 +767,7 @@ bool verify_update_print_object_regions( } } - // Verify and / or update PrintRegions produced by color painting. + // Verify and / or update PrintRegions produced by color painting. for (const PrintObjectRegions::LayerRangeRegions &layer_range : print_object_regions.layer_ranges) for (const PrintObjectRegions::PaintedRegion ®ion : layer_range.painted_regions) { const PrintObjectRegions::VolumeRegion &parent_region = layer_range.volume_regions[region.parent]; @@ -819,7 +819,7 @@ void update_volume_bboxes( std::vector &layer_ranges, std::vector &cached_volume_ids, ModelVolumePtrs model_volumes, - const Transform3d &object_trafo, + const Transform3d &object_trafo, const float offset) { // output will be sorted by the order of model_volumes sorted by their ObjectIDs. @@ -968,7 +968,7 @@ static PrintObjectRegions* generate_print_object_regions( if (parent_volume.is_model_part() || parent_volume.is_modifier()) if (PrintObjectRegions::BoundingBox parent_bbox = find_modifier_volume_extents(layer_range, parent_region_id); parent_bbox.intersects(*bbox)) { // Only create new region for a modifier, which actually modifies config of it's parent. - if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders); + if (PrintRegionConfig config = region_config_from_model_volume(parent_region.region->config(), nullptr, volume, num_extruders); config != parent_region.region->config()) { added = true; layer_range.volume_regions.push_back({ &volume, parent_region_id, get_create_region(std::move(config)), bbox }); @@ -1021,7 +1021,21 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ new_full_config.option("printer_settings_id", true); // BBS int used_filaments = this->extruders().size(); - new_full_config.normalize_fdm(used_filaments); + //new_full_config.normalize_fdm(used_filaments); + new_full_config.normalize_fdm_1(); + t_config_option_keys changed_keys = new_full_config.normalize_fdm_2(used_filaments); + if (changed_keys.size() > 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", got changed_keys, size=%1%")%changed_keys.size(); + for (int i = 0; i < changed_keys.size(); i++) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", i=%1%, key=%2%")%i %changed_keys[i]; + } + } + const ConfigOption* enable_support_option = new_full_config.option("enable_support"); + if (enable_support_option && enable_support_option->getBool()) + m_support_used = true; + else + m_support_used = false; // Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles. DynamicPrintConfig filament_overrides; @@ -1075,13 +1089,14 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ m_default_object_config.apply_only(new_full_config, object_diff, true); // Handle changes to regions config defaults m_default_region_config.apply_only(new_full_config, region_diff, true); - m_full_print_config = std::move(new_full_config); + //m_full_print_config = std::move(new_full_config); + m_full_print_config = new_full_config; if (num_extruders != m_config.filament_diameter.size()) { num_extruders = m_config.filament_diameter.size(); num_extruders_changed = true; } } - + ModelObjectStatusDB model_object_status_db; // 1) Synchronize model objects. @@ -1219,7 +1234,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ if (solid_or_modifier_differ || model_origin_translation_differ || layer_height_ranges_differ || ! model_object.layer_height_profile.timestamp_matches(model_object_new.layer_height_profile)) { // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. - model_object_status.print_object_regions_status = + model_object_status.print_object_regions_status = model_object_status.print_object_regions == nullptr || model_origin_translation_differ || layer_height_ranges_differ ? // Drop print_objects_regions. ModelObjectStatus::PrintObjectRegionsStatus::Invalid : @@ -1279,7 +1294,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; // Only refresh ModelInstances if there is any change. - if (model_object.instances.size() != model_object_new.instances.size() || + if (model_object.instances.size() != model_object_new.instances.size() || ! std::equal(model_object.instances.begin(), model_object.instances.end(), model_object_new.instances.begin(), [](auto l, auto r){ return l->id() == r->id(); })) { // G-code generator accesses model_object.instances to generate sequential print ordering matching the Plater object list. update_apply_status(this->invalidate_step(psGCodeExport)); @@ -1289,8 +1304,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ model_object.instances.emplace_back(new ModelInstance(*model_instance)); model_object.instances.back()->set_model_object(&model_object); } - } else if (! std::equal(model_object.instances.begin(), model_object.instances.end(), model_object_new.instances.begin(), - [](auto l, auto r){ return l->print_volume_state == r->print_volume_state && l->printable == r->printable && + } else if (! std::equal(model_object.instances.begin(), model_object.instances.end(), model_object_new.instances.begin(), + [](auto l, auto r){ return l->print_volume_state == r->print_volume_state && l->printable == r->printable && l->get_transformation().get_matrix().isApprox(r->get_transformation().get_matrix()); })) { // If some of the instances changed, the bounding box of the updated ModelObject is likely no more valid. // This is safe as the ModelObject's bounding box is only accessed from this function, which is called from the main thread only. @@ -1391,12 +1406,50 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // BBS for (PrintObject* object : m_objects) { auto ept_iter = std::find(print_diff.begin(), print_diff.end(), "enable_prime_tower"); - if (object->config().adaptive_layer_height && ept_iter != print_diff.end()) { + if (/*object->config().adaptive_layer_height &&*/ ept_iter != print_diff.end()) { update_apply_status(object->invalidate_step(posSlice)); } } } + //BBS: check the config again + int new_used_filaments = this->extruders().size(); + t_config_option_keys new_changed_keys = new_full_config.normalize_fdm_2(new_used_filaments); + if (new_changed_keys.size() > 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", got new_changed_keys, size=%1%")%new_changed_keys.size(); + for (int i = 0; i < new_changed_keys.size(); i++) + { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", i=%1%, key=%2%")%i %new_changed_keys[i]; + } + + update_apply_status(false); + + // The following call may stop the background processing. + update_apply_status(this->invalidate_state_by_config_options(new_full_config, new_changed_keys)); + + update_apply_status(this->invalidate_step(psGCodeExport)); + + if (full_config_diff.empty()) { + //BBS: previous empty + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: full_config_diff previous empty, need to apply now.")%__LINE__; + + m_placeholder_parser.clear_config(); + // Set the profile aliases for the PrintBase::output_filename() + m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone()); + m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); + m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone()); + + //m_placeholder_parser.apply_config(filament_overrides); + } + // It is also safe to change m_config now after this->invalidate_state_by_config_options() call. + m_config.apply_only(new_full_config, new_changed_keys, true); + // Handle changes to object config defaults + m_default_object_config.apply_only(new_full_config, new_changed_keys, true); + // Handle changes to regions config defaults + m_default_region_config.apply_only(new_full_config, new_changed_keys, true); + m_full_print_config = std::move(new_full_config); + } + // All regions now have distinct settings. // Check whether applying the new region config defaults we would get different regions, // update regions or create regions from scratch. @@ -1502,7 +1555,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ // If it is not valid, then it is ensured that PrintObject.m_slicing_params is not in use // (posSlicing and posSupportMaterial was invalidated). for (PrintObject *object : m_objects) + { object->update_slicing_parameters(); + m_support_used |= object->config().enable_support; + } #ifdef _DEBUG check_model_ids_equal(m_model, model); @@ -1511,7 +1567,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ //BBS: add timestamp logic if (apply_status != APPLY_STATUS_UNCHANGED) m_modified_count++; - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: finished, this %2%, m_modified_count %3%, apply_status %4%, ")%__LINE__ %this %m_modified_count %apply_status; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: finished, this %2%, m_modified_count %3%, apply_status %4%, m_support_used %5%")%__LINE__ %this %m_modified_count %apply_status %m_support_used; return static_cast(apply_status); } diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index c6ecf4ebeb..0d8730b073 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -16,12 +16,20 @@ namespace Slic3r { +enum StringExceptionType { + STRING_EXCEPT_NOT_DEFINED = 0, + STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE = 1, + STRING_EXCEPT_COUNT +}; + // BBS: error with object struct StringObjectException { std::string string; ObjectBase const *object = nullptr; std::string opt_key; + StringExceptionType type; // warning type for tips + std::vector params; // warning params for tips }; class CanceledException : public std::exception @@ -411,7 +419,9 @@ public: // After calling the apply() function, call set_task() to limit the task to be processed by process(). virtual void set_task(const TaskParams ¶ms) {} // Perform the calculation. This is the only method that is to be called at a worker thread. - virtual void process() = 0; + virtual void process(bool use_cache = false) = 0; + virtual int export_cached_data(const std::string& dir_path, bool with_space=false) { return 0;} + virtual int load_cached_data(const std::string& directory) { return 0;} // Clean up after process() finished, either with success, error or if canceled. // The adjustments on the Print / PrintObject data due to set_task() are to be reverted here. virtual void finalize() {} diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b9d0dea647..af38e58f79 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -141,9 +141,7 @@ static t_config_enum_values s_keys_map_InfillPattern { { "archimedeanchords", ipArchimedeanChords }, { "octagramspiral", ipOctagramSpiral }, { "supportcubic", ipSupportCubic }, -#if HAS_LIGHTNING_INFILL { "lightning", ipLightning } -#endif // HAS_LIGHTNING_INFILL }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InfillPattern) @@ -183,9 +181,9 @@ static t_config_enum_values s_keys_map_SupportMaterialPattern { { "rectilinear", smpRectilinear }, { "rectilinear-grid", smpRectilinearGrid }, { "honeycomb", smpHoneycomb }, -#if HAS_LIGHTNING_INFILL { "lightning", smpLightning }, -#endif + { "default", smpDefault}, + { "none", smpNone}, }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportMaterialPattern) @@ -206,8 +204,8 @@ static t_config_enum_values s_keys_map_SupportType{ { "normal(auto)", stNormalAuto }, { "tree(auto)", stTreeAuto }, { "hybrid(auto)", stHybridAuto }, - { "normal", stNormal }, - { "tree", stTree } + { "normal(manual)", stNormal }, + { "tree(manual)", stTree } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(SupportType) @@ -247,11 +245,10 @@ static const t_config_enum_values s_keys_map_BrimType = { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BrimType) -// using 0,1,2 to compatible with old files +// using 0,1 to compatible with old files static const t_config_enum_values s_keys_map_TimelapseType = { - {"0", tlNone}, - {"1", tlSmooth}, - {"2", tlTraditional} + {"0", tlTraditional}, + {"1", tlSmooth} }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(TimelapseType) @@ -270,19 +267,22 @@ static const t_config_enum_values s_keys_map_ForwardCompatibilitySubstitutionRul CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule) static const t_config_enum_values s_keys_map_OverhangFanThreshold = { + { "0%", Overhang_threshold_none }, { "5%", Overhang_threshold_1_4 }, { "25%", Overhang_threshold_2_4 }, { "50%", Overhang_threshold_3_4 }, { "75%", Overhang_threshold_4_4 }, { "95%", Overhang_threshold_bridge } }; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(OverhangFanThreshold) // BBS static const t_config_enum_values s_keys_map_BedType = { + { "Default Plate", btDefault }, { "Cool Plate", btPC }, { "Engineering Plate", btEP }, { "High Temp Plate", btPEI }, - { "Textured PEI Plate", btPTE } + { "Textured PEI Plate", btPTE } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(BedType) @@ -294,6 +294,12 @@ static t_config_enum_values s_keys_map_NozzleType { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NozzleType) +static t_config_enum_values s_keys_map_PerimeterGeneratorType{ + { "classic", int(PerimeterGeneratorType::Classic) }, + { "arachne", int(PerimeterGeneratorType::Arachne) } +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PerimeterGeneratorType) + static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology) { for (std::pair &kvp : options) @@ -340,6 +346,16 @@ void PrintConfigDef::init_common_params() def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) }); + def = this->add("bed_custom_texture", coString); + def->label = L("Bed custom texture"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionString("")); + + def = this->add("bed_custom_model", coString); + def->label = L("Bed custom model"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionString("")); + def = this->add("elefant_foot_compensation", coFloat); def->label = L("Elephant foot compensation"); def->category = L("Quality"); @@ -412,14 +428,14 @@ void PrintConfigDef::init_common_params() def = this->add("printhost_user", coString); def->label = L("User"); - // def->tooltip = L(""); + // def->tooltip = ""; def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); def = this->add("printhost_password", coString); def->label = L("Password"); - // def->tooltip = L(""); + // def->tooltip = ""; def->mode = comAdvanced; def->cli = ConfigOptionDef::nocli; def->set_default_value(new ConfigOptionString("")); @@ -441,7 +457,7 @@ void PrintConfigDef::init_common_params() def = this->add("printhost_authorization_type", coEnum); def->label = L("Authorization Type"); - // def->tooltip = L(""); + // def->tooltip = ""; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("key"); def->enum_values.push_back("user"); @@ -565,7 +581,7 @@ void PrintConfigDef::init_fff_params() def->max = 120; def->set_default_value(new ConfigOptionInts{45}); - def = this->add("curr_bed_type", coEnums); + def = this->add("curr_bed_type", coEnum); def->label = L("Bed type"); def->tooltip = L("Bed types supported by the printer"); def->mode = comSimple; @@ -629,15 +645,18 @@ void PrintConfigDef::init_fff_params() def = this->add("overhang_fan_threshold", coEnums); def->label = L("Cooling overhang threshold"); def->tooltip = L("Force cooling fan to be specific speed when overhang degree of printed part exceeds this value. " - "Expressed as percentage which indicides how much width of the line without support from lower layer"); - def->sidetext = L(""); - def->enum_keys_map = &s_keys_map_OverhangFanThreshold; + "Expressed as percentage which indicides how much width of the line without support from lower layer. " + "0% means forcing cooling for all outer wall no matter how much overhang degree"); + def->sidetext = ""; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->mode = comAdvanced; + def->enum_values.emplace_back("0%"); def->enum_values.emplace_back("5%"); def->enum_values.emplace_back("25%"); def->enum_values.emplace_back("50%"); def->enum_values.emplace_back("75%"); def->enum_values.emplace_back("95%"); + def->enum_labels.emplace_back("0%"); def->enum_labels.emplace_back("10%"); def->enum_labels.emplace_back("25%"); def->enum_labels.emplace_back("50%"); @@ -645,6 +664,17 @@ void PrintConfigDef::init_fff_params() def->enum_labels.emplace_back("95%"); def->set_default_value(new ConfigOptionEnumsGeneric{ (int)Overhang_threshold_bridge }); + def = this->add("bridge_angle", coFloat); + def->label = L("Bridge direction"); + def->category = L("Strength"); + def->tooltip = L("Bridging angle override. If left to zero, the bridging angle will be calculated " + "automatically. Otherwise the provided angle will be used for external bridges. " + "Use 180°for zero angle."); + def->sidetext = L("°"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.)); + def = this->add("bridge_flow", coFloat); def->label = L("Bridge flow"); def->category = L("Quality"); @@ -791,6 +821,13 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings()); def->cli = ConfigOptionDef::nocli; + //BBS. + def = this->add("upward_compatible_machine", coStrings); + def->label = L("upward compatible machine"); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionStrings()); + def->cli = ConfigOptionDef::nocli; + def = this->add("compatible_printers_condition", coString); def->label = L("Compatible machine condition"); //def->tooltip = L("A boolean expression using the configuration values of an active printer profile. " @@ -829,6 +866,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionStrings()); def->cli = ConfigOptionDef::nocli; + def = this->add("print_compatible_printers", coStrings); + def->set_default_value(new ConfigOptionStrings()); + def->cli = ConfigOptionDef::nocli; + def = this->add("print_sequence", coEnum); def->label = L("Print sequence"); def->tooltip = L("Print sequence, layer by layer or object by object"); @@ -887,7 +928,7 @@ void PrintConfigDef::init_fff_params() def = this->add("thick_bridges", coBool); def->label = L("Thick bridges"); - def->category = L("Layers and Perimeters"); + def->category = L("Quality"); def->tooltip = L("If enabled, bridges are more reliable, can bridge longer distances, but may look worse. " "If disabled, bridges look better but are reliable just for shorter bridged distances."); def->mode = comAdvanced; @@ -920,6 +961,26 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings { " " }); + def = this->add("ensure_vertical_shell_thickness", coBool); + def->label = L("Ensure vertical shell thickness"); + def->category = L("Strength"); + def->tooltip = L("Add solid infill near sloping surfaces to guarantee the vertical shell thickness " + "(top+bottom solid layers)"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(true)); + + def = this->add("internal_bridge_support_thickness", coFloat); + def->label = L("Internal bridge support thickness"); + def->category = L("Strength"); + def->tooltip = L("If enabled, Studio will generate support loops under the contours of internal bridges." + "These support loops could prevent internal bridges from extruding over the air and improve the top surface quality, especially when the sparse infill density is low." + "This value determines the thickness of the support loops. 0 means disable this feature"); + def->sidetext = L("mm"); + def->min = 0; + def->max = 2; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0)); + auto def_top_fill_pattern = def = this->add("top_surface_pattern", coEnum); def->label = L("Top surface pattern"); def->category = L("Strength"); @@ -931,16 +992,16 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("monotonicline"); def->enum_values.push_back("alignedrectilinear"); def->enum_values.push_back("hilbertcurve"); - //def->enum_values.push_back("archimedeanchords"); - //def->enum_values.push_back("octagramspiral"); + def->enum_values.push_back("archimedeanchords"); + def->enum_values.push_back("octagramspiral"); def->enum_labels.push_back(L("Concentric")); def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Monotonic")); def->enum_labels.push_back(L("Monotonic line")); def->enum_labels.push_back(L("Aligned Rectilinear")); def->enum_labels.push_back(L("Hilbert Curve")); - //def->enum_labels.push_back(L("Archimedean Chords")); - //def->enum_labels.push_back(L("Octagram Spiral")); + def->enum_labels.push_back(L("Archimedean Chords")); + def->enum_labels.push_back(L("Octagram Spiral")); def->set_default_value(new ConfigOptionEnum(ipRectilinear)); def = this->add("bottom_surface_pattern", coEnum); @@ -1126,6 +1187,13 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionFloats{ 60.0f }); + def = this->add("default_filament_colour", coStrings); + def->label = L("Default color"); + def->tooltip = L("Default filament color"); + def->gui_type = ConfigOptionDef::GUIType::color; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionStrings{""}); + def = this->add("filament_colour", coStrings); def->label = L("Color"); def->tooltip = L("Only used as a visual help on UI"); @@ -1133,15 +1201,25 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionStrings{ "#00AE42" }); + //bbs + def = this->add("required_nozzle_HRC", coInts); + def->label = L("Required nozzle HRC"); + def->tooltip = L("Minimum HRC of nozzle required to print the filament. Zero means no checking of nozzle's HRC."); + def->min = 0; + def->max = 500; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{0}); + def = this->add("filament_max_volumetric_speed", coFloats); def->label = L("Max volumetric speed"); def->tooltip = L("This setting stands for how much volume of filament can be melted and extruded per second. " "Printing speed is limited by max volumetric speed, in case of too high and unreasonable speed setting. " - "Zero means no limit"); + "Can't be zero"); def->sidetext = L("mm³/s"); def->min = 0; + def->max = 50; def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloats { 0. }); + def->set_default_value(new ConfigOptionFloats { 2. }); def = this->add("filament_minimal_purge_on_wipe_tower", coFloats); def->label = L("Minimal purge on wipe tower"); @@ -1289,14 +1367,12 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("honeycomb"); def->enum_values.push_back("adaptivecubic"); def->enum_values.push_back("alignedrectilinear"); - //def->enum_values.push_back("3dhoneycomb"); - //def->enum_values.push_back("hilbertcurve"); - //def->enum_values.push_back("archimedeanchords"); - //def->enum_values.push_back("octagramspiral"); - //def->enum_values.push_back("supportcubic"); -#if HAS_LIGHTNING_INFILL + def->enum_values.push_back("3dhoneycomb"); + def->enum_values.push_back("hilbertcurve"); + def->enum_values.push_back("archimedeanchords"); + def->enum_values.push_back("octagramspiral"); + def->enum_values.push_back("supportcubic"); def->enum_values.push_back("lightning"); -#endif // HAS_LIGHTNING_INFILL def->enum_labels.push_back(L("Concentric")); def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Grid")); @@ -1308,14 +1384,12 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back(L("Honeycomb")); def->enum_labels.push_back(L("Adaptive Cubic")); def->enum_labels.push_back(L("Aligned Rectilinear")); - //def->enum_labels.push_back(L("3D Honeycomb")); - //def->enum_labels.push_back(L("Hilbert Curve")); - //def->enum_labels.push_back(L("Archimedean Chords")); - //def->enum_labels.push_back(L("Octagram Spiral")); - //def->enum_labels.push_back(L("Support Cubic")); -#if HAS_LIGHTNING_INFILL + def->enum_labels.push_back(L("3D Honeycomb")); + def->enum_labels.push_back(L("Hilbert Curve")); + def->enum_labels.push_back(L("Archimedean Chords")); + def->enum_labels.push_back(L("Octagram Spiral")); + def->enum_labels.push_back(L("Support Cubic")); def->enum_labels.push_back(L("Lightning")); -#endif // HAS_LIGHTNING_INFILL def->set_default_value(new ConfigOptionEnum(ipCubic)); def = this->add("outer_wall_acceleration", coFloat); @@ -1350,6 +1424,14 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(500)); + def = this->add("outer_wall_acceleration", coFloat); + def->label = L("Outer wall"); + def->tooltip = L("Acceleration of outer wall. Using a lower value can improve quality"); + def->sidetext = L("mm/s²"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(500)); + def = this->add("initial_layer_acceleration", coFloat); def->label = L("Initial layer"); def->tooltip = L("Acceleration of initial layer. Using a lower value can improve build plate adhensive"); @@ -1423,13 +1505,13 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(0.2)); - def = this->add("adaptive_layer_height", coBool); - def->label = L("Adaptive layer height"); - def->category = L("Quality"); - def->tooltip = L("Enabling this option means the height of every layer except the first will be automatically calculated " - "during slicing according to the slope of the model’s surface.\n" - "Note that this option only takes effect if no prime tower is generated in current plate."); - def->set_default_value(new ConfigOptionBool(0)); + //def = this->add("adaptive_layer_height", coBool); + //def->label = L("Adaptive layer height"); + //def->category = L("Quality"); + //def->tooltip = L("Enabling this option means the height of every layer except the first will be automatically calculated " + // "during slicing according to the slope of the model’s surface.\n" + // "Note that this option only takes effect if no prime tower is generated in current plate."); + //def->set_default_value(new ConfigOptionBool(0)); def = this->add("initial_layer_speed", coFloat); def->label = L("Initial layer"); @@ -1488,7 +1570,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("The width within which to jitter. It's adversed to be below outer wall line width"); def->sidetext = L("mm"); def->min = 0; - def->mode = comAdvanced; + def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(0.3)); def = this->add("fuzzy_skin_point_distance", coFloat); @@ -1496,7 +1578,7 @@ void PrintConfigDef::init_fff_params() def->category = L("Others"); def->tooltip = L("The average diatance between the random points introducded on each line segment"); def->sidetext = L("mm"); - def->mode = comAdvanced; + def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(0.8)); def = this->add("filter_out_gap_fill", coFloat); @@ -1558,6 +1640,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(ntUndefine)); + def = this->add("nozzle_hrc", coInt); + def->label = L("Nozzle HRC"); + def->tooltip = L("The nozzle's hardness. Zero means no checking for nozzle's hardness during slicing."); + def->sidetext = L("HRC"); + def->min = 0; + def->max = 500; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInt{0}); + def = this->add("auxiliary_fan", coBool); def->label = L("Auxiliary part cooling fan"); def->tooltip = L("Enable this option if machine has auxiliary part cooling fan"); @@ -2358,12 +2449,10 @@ void PrintConfigDef::init_fff_params() def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.emplace_back("0"); def->enum_values.emplace_back("1"); - def->enum_values.emplace_back("2"); - def->enum_labels.emplace_back(L("None")); - def->enum_labels.emplace_back(L("Smooth")); def->enum_labels.emplace_back(L("Traditional")); + def->enum_labels.emplace_back(L("Smooth")); def->mode = comSimple; - def->set_default_value(new ConfigOptionEnum(tlNone)); + def->set_default_value(new ConfigOptionEnum(tlTraditional)); def = this->add("standby_temperature_delta", coInt); def->label = L("Temperature variation"); @@ -2418,6 +2507,20 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.049)); + def = this->add("slicing_mode", coEnum); + def->label = L("Slicing Mode"); + def->category = L("Other"); + def->tooltip = L("Use \"Even-odd\" for 3DLabPrint airplane models. Use \"Close holes\" to close all holes in the model."); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("regular"); + def->enum_values.push_back("even_odd"); + def->enum_values.push_back("close_holes"); + def->enum_labels.push_back(L("Regular")); + def->enum_labels.push_back(L("Even-odd")); + def->enum_labels.push_back(L("Close holes")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(SlicingMode::Regular)); + def = this->add("enable_support", coBool); //BBS: remove material behind support def->label = L("Enable support"); @@ -2434,13 +2537,13 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("normal(auto)"); def->enum_values.push_back("tree(auto)"); def->enum_values.push_back("hybrid(auto)"); - def->enum_values.push_back("normal"); - def->enum_values.push_back("tree"); + def->enum_values.push_back("normal(manual)"); + def->enum_values.push_back("tree(manual)"); def->enum_labels.push_back(L("normal(auto)")); def->enum_labels.push_back(L("tree(auto)")); def->enum_labels.push_back(L("hybrid(auto)")); - def->enum_labels.push_back(L("normal")); - def->enum_labels.push_back(L("tree")); + def->enum_labels.push_back(L("normal(manual)")); + def->enum_labels.push_back(L("tree(manual)")); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(stNormalAuto)); @@ -2500,6 +2603,15 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(0.2)); + // BBS:MusangKing + def = this->add("support_bottom_z_distance", coFloat); + def->label = L("Bottom Z distance"); + def->category = L("Support"); + def->tooltip = L("The z gap between the bottom support interface and object"); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.2)); + def = this->add("enforce_support_layers", coInt); //def->label = L("Enforce support for the first"); def->category = L("Support"); @@ -2515,9 +2627,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(0)); def = this->add("support_filament", coInt); - def->label = L("Support"); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; + def->label = L("Support"); def->category = L("Support"); - def->tooltip = L("Filament to print support and skirt. 0 means no specific filament for support and current filament is used"); + def->tooltip = L("Filament to print support 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)); @@ -2539,11 +2652,12 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionBool(false)); def = this->add("support_interface_filament", coInt); - def->label = L("Support interface"); + def->gui_type = ConfigOptionDef::GUIType::i_enum_open; + def->label = L("Support interface"); def->category = L("Support"); - def->tooltip = L("Filament to print support interface. 0 means no specific filament for support interface and current filament is used"); + def->tooltip = L("Filament to print support interface. \"Default\" means no specific filament for support interface and current filament is used"); def->min = 0; - //BBS + // BBS def->mode = comSimple; def->set_default_value(new ConfigOptionInt(1)); @@ -2614,18 +2728,18 @@ void PrintConfigDef::init_fff_params() def->category = L("Support"); def->tooltip = L("Line pattern of support"); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("default"); def->enum_values.push_back("rectilinear"); def->enum_values.push_back("rectilinear-grid"); def->enum_values.push_back("honeycomb"); -#if HAS_LIGHTNING_INFILL def->enum_values.push_back("lightning"); -#endif + def->enum_values.push_back("none"); + def->enum_labels.push_back(L("Default")); def->enum_labels.push_back(L("Rectilinear")); def->enum_labels.push_back(L("Rectilinear grid")); def->enum_labels.push_back(L("Honeycomb")); -#if HAS_LIGHTNING_INFILL def->enum_labels.push_back(L("Lightning")); -#endif + def->enum_labels.push_back(L("None")); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(smpRectilinear)); @@ -2654,6 +2768,14 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloat(2.5)); + def = this->add("support_expansion", coFloat); + def->label = L("Normal Support expansion"); + def->category = L("Support"); + def->tooltip = L("Expand (+) or shrink (-) the horizontal span of normal support"); + def->sidetext = L("mm"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("support_speed", coFloat); def->label = L("Support"); def->category = L("Speed"); @@ -2760,19 +2882,19 @@ void PrintConfigDef::init_fff_params() def = this->add("nozzle_temperature_range_low", coInts); def->label = L("Min"); - //def->tooltip = L(""); + //def->tooltip = ""; def->sidetext = L("°C"); def->min = 0; def->max = max_temp; - def->set_default_value(new ConfigOptionInts { 0 }); + def->set_default_value(new ConfigOptionInts { 190 }); def = this->add("nozzle_temperature_range_high", coInts); def->label = L("Max"); - //def->tooltip = L(""); + //def->tooltip = ""; def->sidetext = L("°C"); def->min = 0; def->max = max_temp; - def->set_default_value(new ConfigOptionInts { 0 }); + def->set_default_value(new ConfigOptionInts { 240 }); def = this->add("bed_temperature_difference", coInts); def->label = L("Bed temperature difference"); @@ -2914,10 +3036,8 @@ void PrintConfigDef::init_fff_params() def = this->add("flush_multiplier", coFloat); def->label = L("Flush multiplier"); - def->tooltip = L(""); - def->sidetext = L(""); - def->mode = comAdvanced; - def->min = 0; + def->tooltip = L("The actual flushing volumes is equal to the flush multiplier multiplied by the flushing volumes in the table."); + def->sidetext = ""; def->set_default_value(new ConfigOptionFloat(1.0)); // BBS @@ -2925,7 +3045,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Prime volume"); def->tooltip = L("The volume of material to prime extruder on tower."); def->sidetext = L("mm³"); - def->min = 0; + def->min = 1.0; def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(45.)); @@ -2949,6 +3069,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Width"); def->tooltip = L("Width of prime tower"); def->sidetext = L("mm"); + def->min = 2.0; def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(35.)); @@ -2972,21 +3093,24 @@ void PrintConfigDef::init_fff_params() def->label = L("Flush into objects' infill"); def->tooltip = L("Purging after filament change will be done inside objects' infills. " "This may lower the amount of waste and decrease the print time. " - "If the walls are printed with transparent filament, the mixed color infill will be seen outside"); + "If the walls are printed with transparent filament, the mixed color infill will be seen outside. " + "It will not take effect, unless the prime tower is enabled."); def->set_default_value(new ConfigOptionBool(false)); def = this->add("flush_into_support", coBool); def->category = L("Flush options"); def->label = L("Flush into objects' support"); def->tooltip = L("Purging after filament change will be done inside objects' support. " - "This may lower the amount of waste and decrease the print time"); + "This may lower the amount of waste and decrease the print time. " + "It will not take effect, unless the prime tower is enabled."); def->set_default_value(new ConfigOptionBool(true)); def = this->add("flush_into_objects", coBool); def->category = L("Flush options"); def->label = L("Flush into this object"); def->tooltip = L("This object will be used to purge the nozzle after a filament change to save filament and decrease the print time. " - "Colours of the objects will be mixed as a result"); + "Colours of the objects will be mixed as a result. " + "It will not take effect, unless the prime tower is enabled."); def->set_default_value(new ConfigOptionBool(false)); //BBS @@ -3024,6 +3148,92 @@ void PrintConfigDef::init_fff_params() def->gui_type = ConfigOptionDef::GUIType::one_string; def->set_default_value(new ConfigOptionPoints{Vec2d(300, 300)}); + def = this->add("wall_generator", coEnum); + def->label = L("Wall generator"); + def->category = L("Quality"); + def->tooltip = L("Classic wall generator produces walls with constant extrusion width and for " + "very thin areas is used gap-fill. " + "Arachne engine produces walls with variable extrusion width"); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("classic"); + def->enum_values.push_back("arachne"); + def->enum_labels.push_back(L("Classic")); + def->enum_labels.push_back(L("Arachne")); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionEnum(PerimeterGeneratorType::Classic)); + + def = this->add("wall_transition_length", coPercent); + def->label = L("Wall transition length"); + def->category = L("Quality"); + def->tooltip = L("When transitioning between different numbers of walls as the part becomes " + "thinner, a certain amount of space is allotted to split or join the wall segments. " + "It's expressed as a percentage over nozzle diameter"); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionPercent(100)); + + def = this->add("wall_transition_filter_deviation", coPercent); + def->label = L("Wall transitioning filter margin"); + def->category = L("Quality"); + def->tooltip = L("Prevent transitioning back and forth between one extra wall and one less. This " + "margin extends the range of extrusion widths which follow to [Minimum wall width " + "- margin, 2 * Minimum wall width + margin]. Increasing this margin " + "reduces the number of transitions, which reduces the number of extrusion " + "starts/stops and travel time. However, large extrusion width variation can lead to " + "under- or overextrusion problems. " + "It's expressed as a percentage over nozzle diameter"); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionPercent(25)); + + def = this->add("wall_transition_angle", coFloat); + def->label = L("Wall transitioning threshold angle"); + def->category = L("Quality"); + def->tooltip = L("When to create transitions between even and odd numbers of walls. A wedge shape with" + " an angle greater than this setting will not have transitions and no walls will be " + "printed in the center to fill the remaining space. Reducing this setting reduces " + "the number and length of these center walls, but may leave gaps or overextrude"); + def->sidetext = L("°"); + def->mode = comAdvanced; + def->min = 1.; + def->max = 59.; + def->set_default_value(new ConfigOptionFloat(10.)); + + def = this->add("wall_distribution_count", coInt); + def->label = L("Wall distribution count"); + def->category = L("Quality"); + def->tooltip = L("The number of walls, counted from the center, over which the variation needs to be " + "spread. Lower values mean that the outer walls don't change in width"); + def->mode = comAdvanced; + def->min = 1; + def->set_default_value(new ConfigOptionInt(1)); + + def = this->add("min_feature_size", coPercent); + def->label = L("Minimum feature size"); + def->category = L("Quality"); + def->tooltip = L("Minimum thickness of thin features. Model features that are thinner than this value will " + "not be printed, while features thicker than the Minimum feature size will be widened to " + "the Minimum wall width. " + "It's expressed as a percentage over nozzle diameter"); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionPercent(25)); + + def = this->add("min_bead_width", coPercent); + def->label = L("Minimum wall width"); + def->category = L("Quality"); + def->tooltip = L("Width of the wall that will replace thin features (according to the Minimum feature size) " + "of the model. If the Minimum wall width is thinner than the thickness of the feature," + " the wall will become as thick as the feature itself. " + "It's expressed as a percentage over nozzle diameter"); + def->sidetext = L("%"); + def->mode = comAdvanced; + def->min = 0; + def->set_default_value(new ConfigOptionPercent(85)); + // Declare retract values for filament profile, overriding the printer's extruder profile. for (const char *opt_key : { // floats @@ -3097,7 +3307,7 @@ void PrintConfigDef::init_filament_option_keys() "filament_diameter", "min_layer_height", "max_layer_height", "retraction_length", "z_hop", "retraction_speed", "deretraction_speed", "retract_before_wipe", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance", - "retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", /*"filament_colour",*/ + "retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", "filament_colour", "default_filament_profile" }; @@ -3797,6 +4007,14 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va opt_key = "slow_down_for_layer_cooling"; } else if (opt_key == "timelapse_no_toolhead") { opt_key = "timelapse_type"; + } else if (opt_key == "timelapse_type" && value == "2") { + // old file "0" is None, "2" is Traditional + // new file "0" is Traditional, erase "2" + value = "0"; + } else if (opt_key == "support_type" && value == "normal") { + value = "normal(manual)"; + } else if (opt_key == "support_type" && value == "tree") { + value = "tree(manual)"; } else if (opt_key == "different_settings_to_system") { std::string copy_value = value; copy_value.erase(std::remove(copy_value.begin(), copy_value.end(), '\"'), copy_value.end()); // remove '"' in string @@ -3820,12 +4038,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va #endif /* HAS_PRESSURE_EQUALIZER */ // BBS , "support_sharp_tails","remove_small_overhangs", "support_with_sheath", - "tree_support_branch_diameter_angle", "tree_support_collision_resolution", + "tree_support_branch_diameter_angle", "tree_support_collision_resolution", "tree_support_with_infill", "max_volumetric_speed", "max_print_speed", - "support_bottom_z_distance", "support_closing_radius", "slicing_mode", + "support_closing_radius", "remove_freq_sweep", "remove_bed_leveling", "remove_extrusion_calibration", "support_transition_line_width", "support_transition_speed", "bed_temperature", "bed_temperature_initial_layer", - "can_switch_nozzle_type", "can_add_auxiliary_fan", "extra_flush_volume", "spaghetti_detector" + "can_switch_nozzle_type", "can_add_auxiliary_fan", "extra_flush_volume", "spaghetti_detector", "adaptive_layer_height" }; if (ignore.find(opt_key) != ignore.end()) { @@ -3931,7 +4149,7 @@ void DynamicPrintConfig::normalize_fdm(int used_filaments) ConfigOptionBool* ept_opt = this->option("enable_prime_tower"); if (used_filaments > 0 && ept_opt != nullptr) { ConfigOptionBool* islh_opt = this->option("independent_support_layer_height", true); - ConfigOptionBool* alh_opt = this->option("adaptive_layer_height"); + //ConfigOptionBool* alh_opt = this->option("adaptive_layer_height"); ConfigOptionEnum* ps_opt = this->option>("print_sequence"); ConfigOptionEnum* timelapse_opt = this->option>("timelapse_type"); @@ -3943,8 +4161,8 @@ void DynamicPrintConfig::normalize_fdm(int used_filaments) if (ept_opt->value) { if (islh_opt) islh_opt->value = false; - if (alh_opt) - alh_opt->value = false; + //if (alh_opt) + // alh_opt->value = false; } else { if (islh_opt) @@ -3953,6 +4171,102 @@ void DynamicPrintConfig::normalize_fdm(int used_filaments) } } +//BBS:divide normalize_fdm to 2 steps and call them one by one in Print::Apply +void DynamicPrintConfig::normalize_fdm_1() +{ + if (this->has("extruder")) { + int extruder = this->option("extruder")->getInt(); + this->erase("extruder"); + if (extruder != 0) { + if (!this->has("sparse_infill_filament")) + this->option("sparse_infill_filament", true)->setInt(extruder); + if (!this->has("wall_filament")) + this->option("wall_filament", true)->setInt(extruder); + // Don't propagate the current extruder to support. + // For non-soluble supports, the default "0" extruder means to use the active extruder, + // for soluble supports one certainly does not want to set the extruder to non-soluble. + // if (!this->has("support_filament")) + // this->option("support_filament", true)->setInt(extruder); + // if (!this->has("support_interface_filament")) + // this->option("support_interface_filament", true)->setInt(extruder); + } + } + + if (!this->has("solid_infill_filament") && this->has("sparse_infill_filament")) + this->option("solid_infill_filament", true)->setInt(this->option("sparse_infill_filament")->getInt()); + + if (this->has("spiral_mode") && this->opt("spiral_mode", true)->value) { + { + // this should be actually done only on the spiral layers instead of all + auto* opt = this->opt("retract_when_changing_layer", true); + opt->values.assign(opt->values.size(), false); // set all values to false + // Disable retract on layer change also for filament overrides. + auto* opt_n = this->opt("filament_retract_when_changing_layer", true); + opt_n->values.assign(opt_n->values.size(), false); // Set all values to false. + } + { + this->opt("wall_loops", true)->value = 1; + this->opt("top_shell_layers", true)->value = 0; + this->opt("sparse_infill_density", true)->value = 0; + } + } + + if (auto *opt_gcode_resolution = this->opt("resolution", false); opt_gcode_resolution) + // Resolution will be above 1um. + opt_gcode_resolution->value = std::max(opt_gcode_resolution->value, 0.001); + + return; +} + +t_config_option_keys DynamicPrintConfig::normalize_fdm_2(int used_filaments) +{ + t_config_option_keys changed_keys; + ConfigOptionBool* ept_opt = this->option("enable_prime_tower"); + if (used_filaments > 0 && ept_opt != nullptr) { + ConfigOptionBool* islh_opt = this->option("independent_support_layer_height", true); + //ConfigOptionBool* alh_opt = this->option("adaptive_layer_height"); + ConfigOptionEnum* ps_opt = this->option>("print_sequence"); + + ConfigOptionEnum* timelapse_opt = this->option>("timelapse_type"); + bool is_smooth_timelapse = timelapse_opt != nullptr && timelapse_opt->value == TimelapseType::tlSmooth; + if (!is_smooth_timelapse && (used_filaments == 1 || ps_opt->value == PrintSequence::ByObject)) { + if (ept_opt->value) { + ept_opt->value = false; + changed_keys.push_back("enable_prime_tower"); + } + //ept_opt->value = false; + } + + if (ept_opt->value) { + if (islh_opt) { + if (islh_opt->value) { + islh_opt->value = false; + changed_keys.push_back("independent_support_layer_height"); + } + //islh_opt->value = false; + } + //if (alh_opt) { + // if (alh_opt->value) { + // alh_opt->value = false; + // changed_keys.push_back("adaptive_layer_height"); + // } + // //alh_opt->value = false; + //} + } + else { + if (islh_opt) { + if (!islh_opt->value) { + islh_opt->value = true; + changed_keys.push_back("independent_support_layer_height"); + } + //islh_opt->value = true; + } + } + } + + return changed_keys; +} + void handle_legacy_sla(DynamicPrintConfig &config) { for (std::string corr : {"relative_correction", "material_correction"}) { @@ -4084,6 +4398,16 @@ std::string DynamicPrintConfig::get_filament_type(std::string &displayed_filamen return "PLA"; } +bool DynamicPrintConfig::is_custom_defined() +{ + auto* is_custom_defined = dynamic_cast(this->option("is_custom_defined")); + if (!is_custom_defined || is_custom_defined->empty()) + return false; + if (is_custom_defined->get_at(0) == "1") + return true; + return false; +} + //FIXME localize this function. std::string validate(const FullPrintConfig &cfg) { @@ -4166,7 +4490,7 @@ std::string validate(const FullPrintConfig &cfg) // config before exporting, leaving this check in would mean that config would be rejected before export // (although both the UI and the backend handle it). // --default-acceleration - //if ((cfg.perimeter_acceleration != 0. || cfg.infill_acceleration != 0. || cfg.bridge_acceleration != 0. || cfg.initial_layer_acceleration != 0.) && + //if ((cfg.outer_wall_acceleration != 0. || cfg.infill_acceleration != 0. || cfg.bridge_acceleration != 0. || cfg.initial_layer_acceleration != 0.) && // cfg.default_acceleration == 0.) // return "Invalid zero value for --default-acceleration when using other acceleration settings"; @@ -4299,6 +4623,18 @@ CLIActionsConfigDef::CLIActionsConfigDef() 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->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->cli_params = "slicing_data_directory"; + def->set_default_value(new ConfigOptionString("cached_data")); + /*def = this->add("export_amf", coBool); def->label = L("Export AMF"); def->tooltip = L("Export the model(s) as AMF."); @@ -4335,6 +4671,12 @@ CLIActionsConfigDef::CLIActionsConfigDef() 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->cli = "uptodate"; + def->set_default_value(new ConfigOptionBool(false)); + /*def = this->add("help_fff", coBool); def->label = L("Help (FFF options)"); def->tooltip = L("Show the full list of print/G-code configuration options."); @@ -4355,6 +4697,12 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->tooltip = L("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->cli_params = "pipename"; + def->set_default_value(new ConfigOptionString("cli_pipe")); } //BBS: remove unused command currently @@ -4433,10 +4781,10 @@ CLITransformConfigDef::CLITransformConfigDef() //def->cli = "orient|o"; def->set_default_value(new ConfigOptionBool(false)); - def = this->add("repair", coBool); + /*def = this->add("repair", coBool); def->label = L("Repair"); def->tooltip = L("Repair the model's meshes if it is non-manifold mesh"); - def->set_default_value(new ConfigOptionBool(false)); + def->set_default_value(new ConfigOptionBool(false));*/ /*def = this->add("rotate", coFloat); def->label = L("Rotate"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 637c12a294..82a1964693 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -50,14 +50,10 @@ enum AuthorizationType { atKeyPassword, atUserPassword }; -#define HAS_LIGHTNING_INFILL 1 - enum InfillPattern : int { ipConcentric, ipRectilinear, ipGrid, ipLine, ipCubic, ipTriangles, ipStars, ipGyroid, ipHoneycomb, ipAdaptiveCubic, ipMonotonic, ipMonotonicLine, ipAlignedRectilinear, ip3DHoneycomb, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSupportCubic, ipSupportBase, ipConcentricInternal, -#if HAS_LIGHTNING_INFILL - ipLightning, -#endif // HAS_LIGHTNING_INFILL + ipLightning, ipCount, }; @@ -96,10 +92,10 @@ enum class SlicingMode }; enum SupportMaterialPattern { + smpDefault, smpRectilinear, smpRectilinearGrid, smpHoneycomb, -#if HAS_LIGHTNING_INFILL smpLightning, -#endif // HAS_LIGHTNING_INFILL + smpNone, }; enum SupportMaterialStyle { @@ -153,18 +149,27 @@ enum BrimType { }; enum TimelapseType { - tlNone, - tlSmooth, - tlTraditional + tlTraditional, + tlSmooth }; enum DraftShield { dsDisabled, dsLimited, dsEnabled }; +enum class PerimeterGeneratorType +{ + // Classic perimeter generator using Clipper offsets with constant extrusion width. + Classic, + // Perimeter generator with variable extrusion width based on the paper + // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" ported from Cura. + Arachne +}; + // BBS enum OverhangFanThreshold { - Overhang_threshold_1_4 = 0, + Overhang_threshold_none = 0, + Overhang_threshold_1_4, Overhang_threshold_2_4, Overhang_threshold_3_4, Overhang_threshold_4_4, @@ -173,7 +178,8 @@ enum OverhangFanThreshold { // BBS enum BedType { - btPC = 0, + btDefault = 0, + btPC, btEP, btPEI, btPTE, @@ -198,13 +204,14 @@ static std::string bed_type_to_gcode_string(const BedType type) type_str = "cool_plate"; break; case btEP: - type_str = "engineering_plate"; + type_str = "eng_plate"; break; case btPEI: - type_str = "high_temp_plate"; + type_str = "hot_plate"; break; case btPTE: - type_str = "frosted_plate"; + type_str = "textured_plate"; + break; default: type_str = "unknown"; break; @@ -273,6 +280,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule) 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 @@ -346,6 +354,9 @@ public: const ConfigDef* def() const override { return &print_config_def; } void normalize_fdm(int used_filaments = 0); + void normalize_fdm_1(); + //return the changed param set + t_config_option_keys normalize_fdm_2(int used_filaments = 0); void set_num_extruders(unsigned int num_extruders); @@ -364,6 +375,8 @@ public: //BBS special case Support G/ Support W std::string get_filament_type(std::string &displayed_filament_type, int id = 0); + + bool is_custom_defined(); }; void handle_legacy_sla(DynamicPrintConfig &config); @@ -610,6 +623,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, raft_layers)) ((ConfigOptionEnum, seam_position)) ((ConfigOptionFloat, slice_closing_radius)) + ((ConfigOptionEnum, slicing_mode)) ((ConfigOptionBool, enable_support)) // Automatic supports (generated based on support_threshold_angle). ((ConfigOptionEnum, support_type)) @@ -618,6 +632,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBool, support_on_build_plate_only)) ((ConfigOptionBool, support_critical_regions_only)) ((ConfigOptionFloat, support_top_z_distance)) + ((ConfigOptionFloat, support_bottom_z_distance)) ((ConfigOptionInt, enforce_support_layers)) ((ConfigOptionInt, support_filament)) ((ConfigOptionFloat, support_line_width)) @@ -632,10 +647,11 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, support_interface_pattern)) // Spacing between support material lines (the hatching distance). ((ConfigOptionFloat, support_base_pattern_spacing)) + ((ConfigOptionFloat, support_expansion)) ((ConfigOptionFloat, support_speed)) ((ConfigOptionEnum, support_style)) // BBS - ((ConfigOptionBool, independent_support_layer_height)) + //((ConfigOptionBool, independent_support_layer_height)) ((ConfigOptionBool, thick_bridges)) // Overhang angle threshold. ((ConfigOptionInt, support_threshold_angle)) @@ -651,10 +667,17 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, tree_support_branch_diameter)) ((ConfigOptionFloat, tree_support_branch_angle)) ((ConfigOptionInt, tree_support_wall_count)) - ((ConfigOptionBool, tree_support_with_infill)) ((ConfigOptionBool, detect_narrow_internal_solid_infill)) - ((ConfigOptionBool, adaptive_layer_height)) + // ((ConfigOptionBool, adaptive_layer_height)) ((ConfigOptionFloat, support_bottom_interface_spacing)) + ((ConfigOptionFloat, internal_bridge_support_thickness)) + ((ConfigOptionEnum, wall_generator)) + ((ConfigOptionPercent, wall_transition_length)) + ((ConfigOptionPercent, wall_transition_filter_deviation)) + ((ConfigOptionFloat, wall_transition_angle)) + ((ConfigOptionInt, wall_distribution_count)) + ((ConfigOptionPercent, min_feature_size)) + ((ConfigOptionPercent, min_bead_width)) ) // This object is mapped to Perl as Slic3r::Config::PrintRegion. @@ -663,9 +686,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, bottom_shell_layers)) ((ConfigOptionFloat, bottom_shell_thickness)) + ((ConfigOptionFloat, bridge_angle)) ((ConfigOptionFloat, bridge_flow)) ((ConfigOptionFloat, bridge_speed)) - ((ConfigOptionFloat, bridge_angle)) + ((ConfigOptionBool, ensure_vertical_shell_thickness)) ((ConfigOptionEnum, top_surface_pattern)) ((ConfigOptionFloat, top_solid_infill_flow_ratio)) ((ConfigOptionFloat, bottom_solid_infill_flow_ratio)) @@ -769,8 +793,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionBools, filament_soluble)) ((ConfigOptionBools, filament_is_support)) ((ConfigOptionFloats, filament_cost)) + ((ConfigOptionStrings, default_filament_colour)) ((ConfigOptionInts, temperature_vitrification)) //BBS ((ConfigOptionFloats, filament_max_volumetric_speed)) + ((ConfigOptionInts, required_nozzle_HRC)) ((ConfigOptionFloat, machine_load_filament_time)) ((ConfigOptionFloat, machine_unload_filament_time)) ((ConfigOptionFloats, filament_minimal_purge_on_wipe_tower)) @@ -805,13 +831,14 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionString, template_custom_gcode)) //BBS ((ConfigOptionEnum, nozzle_type)) + ((ConfigOptionInt, nozzle_hrc)) ((ConfigOptionBool, auxiliary_fan)) ) // This object is mapped to Perl as Slic3r::Config::Print. PRINT_CONFIG_CLASS_DERIVED_DEFINE( - PrintConfig, + PrintConfig, (MachineEnvelopeConfig, GCodeConfig), //BBS @@ -918,6 +945,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, nozzle_volume)) ((ConfigOptionEnum, timelapse_type)) ((ConfigOptionPoints, thumbnails)) + // BBS: move from PrintObjectConfig + ((ConfigOptionBool, independent_support_layer_height)) ) // This object is mapped to Perl as Slic3r::Config::Full. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 957d42f3d3..d1e1e578e0 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -546,7 +546,7 @@ FillLightning::GeneratorPtr PrintObject::prepare_lightning_infill_data() break; } - return has_lightning_infill ? FillLightning::build_generator(std::as_const(*this)) : FillLightning::GeneratorPtr(); + return has_lightning_infill ? FillLightning::build_generator(std::as_const(*this), [this]() -> void { this->throw_if_canceled(); }) : FillLightning::GeneratorPtr(); } void PrintObject::clear_layers() @@ -665,6 +665,14 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "top_surface_speed") { // Brim is printed below supports, support invalidates brim and skirt. steps.emplace_back(posSupportMaterial); + if (opt_key == "brim_type") { + const auto* old_brim_type = old_config.option>(opt_key); + const auto* new_brim_type = new_config.option>(opt_key); + //BBS: When switch to manual brim, the object must have brim, then re-generate perimeter + //to make the wall order of first layer to be outer-first + if (old_brim_type->value == btOuterOnly || new_brim_type->value == btOuterOnly) + steps.emplace_back(posPerimeters); + } } else if ( opt_key == "wall_loops" || opt_key == "only_one_wall_top" @@ -695,15 +703,15 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posPerimeters); } else if ( opt_key == "layer_height" - //BBS - || opt_key == "adaptive_layer_height" || opt_key == "raft_layers" || opt_key == "raft_contact_distance" - || opt_key == "slice_closing_radius") { + || opt_key == "slice_closing_radius" + || opt_key == "slicing_mode") { steps.emplace_back(posSlice); } else if ( opt_key == "elefant_foot_compensation" || opt_key == "support_top_z_distance" + || opt_key == "support_bottom_z_distance" || opt_key == "xy_hole_compensation" || opt_key == "xy_contour_compensation") { steps.emplace_back(posSlice); @@ -735,7 +743,8 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "support_style" || opt_key == "support_object_xy_distance" || opt_key == "support_base_pattern_spacing" - || opt_key == "independent_support_layer_height" // BBS + || opt_key == "support_expansion" + //|| opt_key == "independent_support_layer_height" // BBS || opt_key == "support_threshold_angle" || opt_key == "raft_expansion" || opt_key == "raft_first_layer_density" @@ -746,7 +755,6 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "tree_support_branch_distance" || opt_key == "tree_support_branch_diameter" || opt_key == "tree_support_branch_angle" - || opt_key == "tree_support_with_infill" || opt_key == "tree_support_wall_count") { steps.emplace_back(posSupportMaterial); } else if (opt_key == "bottom_shell_layers") { @@ -767,7 +775,10 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "solid_infill_filament" || opt_key == "sparse_infill_line_width" || opt_key == "infill_direction" - || opt_key == "bridge_angle") { + || opt_key == "ensure_vertical_shell_thickness" + || opt_key == "bridge_angle" + //BBS + || opt_key == "internal_bridge_support_thickness") { steps.emplace_back(posPrepareInfill); } else if ( opt_key == "top_surface_pattern" @@ -779,7 +790,6 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posInfill); } else if (opt_key == "sparse_infill_pattern") { steps.emplace_back(posInfill); -#if HAS_LIGHTNING_INFILL const auto *old_fill_pattern = old_config.option>(opt_key); const auto *new_fill_pattern = new_config.option>(opt_key); assert(old_fill_pattern && new_fill_pattern); @@ -787,7 +797,6 @@ bool PrintObject::invalidate_state_by_config_options( // the Lightning infill to another infill or vice versa. if (PrintObject::infill_only_where_needed && (new_fill_pattern->value == ipLightning || old_fill_pattern->value == ipLightning)) steps.emplace_back(posPrepareInfill); -#endif } else if (opt_key == "sparse_infill_density") { // One likely wants to reslice only when switching between zero infill to simulate boolean difference (subtracting volumes), // normal infill and 100% (solid) infill. @@ -823,6 +832,15 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posInfill); steps.emplace_back(posSupportMaterial); } + } else if ( + opt_key == "wall_generator" + || opt_key == "wall_transition_length" + || opt_key == "wall_transition_filter_deviation" + || opt_key == "wall_transition_angle" + || opt_key == "wall_distribution_count" + || opt_key == "min_feature_size" + || opt_key == "min_bead_width") { + steps.emplace_back(posSlice); } else if ( opt_key == "seam_position" || opt_key == "support_speed" @@ -1223,9 +1241,7 @@ void PrintObject::discover_vertical_shells() bool has_extra_layers = false; for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id) { const PrintRegionConfig &config = this->printing_region(region_id).config(); - //BBS - //if (config.ensure_vertical_shell_thickness.value && has_extra_layers_fn(config)) { - if (PrintObject::ensure_vertical_shell_thickness && has_extra_layers_fn(config)) { + if (config.ensure_vertical_shell_thickness.value && has_extra_layers_fn(config)) { has_extra_layers = true; break; } @@ -1305,9 +1321,7 @@ void PrintObject::discover_vertical_shells() PROFILE_BLOCK(discover_vertical_shells_region); const PrintRegion ®ion = this->printing_region(region_id); - //BBS - //if (! region.config().ensure_vertical_shell_thickness.value) - if (! PrintObject::ensure_vertical_shell_thickness) + if (! region.config().ensure_vertical_shell_thickness.value) // This region will be handled by discover_horizontal_shells(). continue; if (! has_extra_layers_fn(region.config())) @@ -1614,6 +1628,7 @@ void PrintObject::bridge_over_infill() Layer *layer = *layer_it; LayerRegion *layerm = layer->m_regions[region_id]; + const PrintObjectConfig& object_config = layer->object()->config(); //BBS: enable thick bridge for internal bridge only Flow bridge_flow = layerm->bridging_flow(frSolidInfill, true); @@ -1645,6 +1660,10 @@ void PrintObject::bridge_over_infill() to_bridge_pp = intersection(to_bridge_pp, lower_internal); } + // BBS: expand to make avoid gap between bridge and inner wall + to_bridge_pp = expand(to_bridge_pp, bridge_flow.scaled_width()); + to_bridge_pp = intersection(to_bridge_pp, internal_solid); + // there's no point in bridging too thin/short regions //FIXME Vojtech: The offset2 function is not a geometric offset, // therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour. @@ -1677,8 +1696,43 @@ void PrintObject::bridge_over_infill() (layerm->fill_surfaces.surfaces.end() - 1)->bridge_angle = ibd.angle; } } + for (ExPolygon &ex : not_to_bridge) layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex)); + + //BBS: modify stInternal to be stInternalWithLoop to give better support to internal bridge + if (!to_bridge.empty()){ + float internal_loop_thickness = object_config.internal_bridge_support_thickness.value; + double bottom_z = layer->print_z - layer->height - internal_loop_thickness + EPSILON; + //BBS: lighting infill doesn't support this feature. Don't need to add loop when infill density is high than 50% + if (region.config().sparse_infill_pattern != InfillPattern::ipLightning && region.config().sparse_infill_density.value < 50) + for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) { + const Layer* lower_layer = m_layers[i]; + + if (lower_layer->print_z < bottom_z) break; + + for (LayerRegion* lower_layerm : lower_layer->m_regions) { + Polygons lower_internal; + lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); + ExPolygons internal_with_loop = intersection_ex(lower_internal, to_bridge); + ExPolygons internal = diff_ex(lower_internal, to_bridge); + if (internal_with_loop.empty()) { + //BBS: don't need to do anything + } + else if (internal.empty()) { + lower_layerm->fill_surfaces.change_to_new_type(stInternal, stInternalWithLoop); + } + else { + lower_layerm->fill_surfaces.remove_type(stInternal); + for (ExPolygon& ex : internal_with_loop) + lower_layerm->fill_surfaces.surfaces.push_back(Surface(stInternalWithLoop, ex)); + for (ExPolygon& ex : internal) + lower_layerm->fill_surfaces.surfaces.push_back(Surface(stInternal, ex)); + } + } + } + } + /* # exclude infill from the layers below if needed # see discussion at https://github.com/alexrj/Slic3r/issues/240 @@ -1895,8 +1949,7 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c { bool updated = false; - //BBS:annotate these part and will do adaptive layer height below - /*if (layer_height_profile.empty()) { + if (layer_height_profile.empty()) { // use the constructor because the assignement is crashing on ASAN OsX layer_height_profile = std::vector(model_object.layer_height_profile.get()); // layer_height_profile = model_object.layer_height_profile; @@ -1911,22 +1964,11 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max + slicing_parameters.object_print_z_min) > 1e-3)) layer_height_profile.clear(); - if (layer_height_profile.empty()) { + if (layer_height_profile.empty() || layer_height_profile[1] != slicing_parameters.first_object_layer_height) { //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); updated = true; - }*/ - - //BBS - if (slicing_parameters.adaptive_layer_height) { - layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object, 0.5); - HeightProfileSmoothingParams smoothing_params(5, true); - layer_height_profile = smooth_height_profile(layer_height_profile, slicing_parameters, smoothing_params); } - else { - layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); - } - updated = true; return updated; } @@ -2048,9 +2090,7 @@ void PrintObject::discover_horizontal_shells() #endif // If ensure_vertical_shell_thickness, then the rest has already been performed by discover_vertical_shells(). - //BBS - //if (region_config.ensure_vertical_shell_thickness.value) - if (PrintObject::ensure_vertical_shell_thickness) + if (region_config.ensure_vertical_shell_thickness.value) continue; coordf_t print_z = layer->print_z; @@ -2772,6 +2812,10 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index void PrintObject::project_and_append_custom_facets( bool seam, EnforcerBlockerType type, std::vector& out) const { + // BBS: Approve adding enforcer support on vertical faces + SlabSlicingConfig config; + config.isVertical = true; + for (const ModelVolume* mv : this->model_object()->volumes) if (mv->is_model_part()) { const indexed_triangle_set custom_facets = seam @@ -2785,7 +2829,7 @@ void PrintObject::project_and_append_custom_facets( else { std::vector projected; // Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane. - slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){}); + slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){}, config); // Merge these projections with the output, layer by layer. assert(! projected.empty()); assert(out.empty() || out.size() == projected.size()); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 5c5ea48d55..743f40d70f 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -18,7 +18,6 @@ namespace Slic3r { bool PrintObject::clip_multipart_objects = true; bool PrintObject::infill_only_where_needed = false; -bool PrintObject::ensure_vertical_shell_thickness = true; LayerPtrs new_layers( PrintObject *print_object, @@ -142,13 +141,11 @@ static std::vector slice_volumes_inner( //BBS: 0.0025mm is safe enough to simplify the data to speed slicing up for high-resolution model. //Also has on influence on arc fitting which has default resolution 0.0125mm. params_base.resolution = 0.0025; - //BBS: remove slice mode, always regular - //switch (print_object_config.slicing_mode.value) { - //case SlicingMode::Regular: params_base.mode = MeshSlicingParams::SlicingMode::Regular; break; - //case SlicingMode::EvenOdd: params_base.mode = MeshSlicingParams::SlicingMode::EvenOdd; break; - //case SlicingMode::CloseHoles: params_base.mode = MeshSlicingParams::SlicingMode::Positive; break; - //} - params_base.mode = MeshSlicingParams::SlicingMode::Regular; + switch (print_object_config.slicing_mode.value) { + case SlicingMode::Regular: params_base.mode = MeshSlicingParams::SlicingMode::Regular; break; + case SlicingMode::EvenOdd: params_base.mode = MeshSlicingParams::SlicingMode::EvenOdd; break; + case SlicingMode::CloseHoles: params_base.mode = MeshSlicingParams::SlicingMode::Positive; break; + } params_base.mode_below = params_base.mode; @@ -584,7 +581,7 @@ void PrintObject::slice() //BBS: send warning message to slicing callback if (!warning.empty()) { BOOST_LOG_TRIVIAL(info) << warning; - this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning+L(" Object:")+this->m_model_object->name, PrintStateBase::SlicingReplaceInitEmptyLayers); + this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning, PrintStateBase::SlicingReplaceInitEmptyLayers); } // Update bounding boxes, back up raw slices of complex models. tbb::parallel_for( @@ -938,8 +935,7 @@ void PrintObject::slice_volumes() //this->active_step_add_warning( // PrintStateBase::WarningLevel::CRITICAL, // L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size " - // "compensation cannot be combined with multi-material painting.") + - // "\n" + (L("Object")) + ": " + this->model_object()->name); + // "compensation cannot be combined with multi-material painting.")); BOOST_LOG_TRIVIAL(info) << "xy compensation will not work for object " << this->model_object()->name << " for multi filament."; } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f921d5977e..f5efaa4454 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -37,7 +37,7 @@ bool is_zero_elevation(const SLAPrintObjectConfig &c) sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::SupportTreeConfig scfg; - + scfg.enabled = c.supports_enable.getBool(); scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.getFloat(); double pillar_r = 0.5 * c.support_pillar_diameter.getFloat(); @@ -66,18 +66,18 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) scfg.pillar_base_safety_distance_mm = c.support_base_safety_distance.getFloat() < EPSILON ? scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); - + scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt()); - + return scfg; } sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig::EmbedObject ret; - + ret.enabled = is_zero_elevation(c); - + if(ret.enabled) { ret.everywhere = c.pad_around_object_everywhere.getBool(); ret.object_gap_mm = c.pad_object_gap.getFloat(); @@ -86,24 +86,24 @@ sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) ret.stick_penetration_mm = c.pad_object_connector_penetration .getFloat(); } - + return ret; } sla::PadConfig make_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig pcfg; - + pcfg.wall_thickness_mm = c.pad_wall_thickness.getFloat(); pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; - + pcfg.max_merge_dist_mm = c.pad_max_merge_distance.getFloat(); pcfg.wall_height_mm = c.pad_wall_height.getFloat(); pcfg.brim_size_mm = c.pad_brim_size.getFloat(); - + // set builtin pad implicitly ON pcfg.embed_object = builtin_pad_cfg(c); - + return pcfg; } @@ -174,8 +174,8 @@ static std::vector sla_instances(const ModelObject &mo return instances; } -std::vector SLAPrint::print_object_ids() const -{ +std::vector SLAPrint::print_object_ids() const +{ std::vector out; // Reserve one more for the caller to append the ID of the Print itself. out.reserve(m_objects.size() + 1); @@ -238,7 +238,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con m_material_config.apply_only(config, material_diff, true); // Handle changes to object config defaults m_default_object_config.apply_only(config, object_diff, true); - + if (m_printer) m_printer->apply(m_printer_config); struct ModelObjectStatus { @@ -429,7 +429,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con model_object.sla_support_points = model_object_new.sla_support_points; } model_object.sla_points_status = model_object_new.sla_points_status; - + // Invalidate hollowing if drain holes have changed if (model_object.sla_drain_holes != model_object_new.sla_drain_holes) { @@ -629,15 +629,15 @@ StringObjectException SLAPrint::validate(StringObjectException *exception, Polyg sla::SupportTreeConfig cfg = make_support_cfg(po->config()); double elv = cfg.object_elevation_mm; - + sla::PadConfig padcfg = make_pad_cfg(po->config()); sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object; - + if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth()) return {L( "Elevation is too low for object. Use the \"Pad around " "object\" feature to print the object without elevation."), po}; - + if(supports_en && builtinpad.enabled && cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { return {L( @@ -646,7 +646,7 @@ StringObjectException SLAPrint::validate(StringObjectException *exception, Polyg "distance' has to be greater than the 'Pad object gap' " "parameter to avoid this."), po}; } - + std::string pval = padcfg.validate(); if (!pval.empty()) return {pval, po}; } @@ -686,7 +686,7 @@ bool SLAPrint::invalidate_step(SLAPrintStep step) return invalidated; } -void SLAPrint::process() +void SLAPrint::process(bool use_cache) { if (m_objects.empty()) return; @@ -695,7 +695,7 @@ void SLAPrint::process() // Assumption: at this point the print objects should be populated only with // the model objects we have to process and the instances are also filtered - + Steps printsteps(this); // We want to first process all objects... @@ -709,7 +709,7 @@ void SLAPrint::process() }; SLAPrintStep print_steps[] = { slapsMergeSlicesAndEval, slapsRasterize }; - + double st = Steps::min_objstatus; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; @@ -749,7 +749,7 @@ void SLAPrint::process() throw_if_canceled(); po->set_done(step); } - + incr = printsteps.progressrange(step); } } @@ -760,7 +760,7 @@ void SLAPrint::process() // this would disable the rasterization step // std::fill(m_stepmask.begin(), m_stepmask.end(), false); - + st = Steps::max_objstatus; for(SLAPrintStep currentstep : print_steps) { throw_if_canceled(); @@ -774,7 +774,7 @@ void SLAPrint::process() throw_if_canceled(); set_done(currentstep); } - + st += printsteps.progressrange(currentstep); } @@ -1132,7 +1132,7 @@ const TriangleMesh& SLAPrintObject::support_mesh() const { if(m_config.supports_enable.getBool() && m_supportdata) return m_supportdata->tree_mesh; - + return EMPTY_MESH; } @@ -1149,7 +1149,7 @@ const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const if (m_hollowing_data && m_hollowing_data->interior && m_config.hollowing_enable.getBool()) return sla::get_mesh(*m_hollowing_data->interior); - + return EMPTY_TRIANGLE_SET; } @@ -1174,7 +1174,7 @@ sla::SupportPoints SLAPrintObject::transformed_support_points() const for (sla::SupportPoint& suppt : spts) { suppt.pos = tr * suppt.pos; } - + return spts; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 4652700e0c..0c5ea4a606 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -77,7 +77,7 @@ public: // Get a pad mesh centered around origin in XY, and with zero rotation around Z applied. // Support mesh is only valid if this->is_step_done(slaposPad) is true. const TriangleMesh& pad_mesh() const; - + // Ready after this->is_step_done(slaposDrillHoles) is true const indexed_triangle_set &hollowed_interior_mesh() const; @@ -201,7 +201,7 @@ private: { return level(r1) < level(r2); }); - + if(it == cont.end()) return it; T diff = std::abs(level(*it) - lvl); @@ -307,18 +307,18 @@ private: // Caching the transformed (m_trafo) raw mesh of the object mutable CachedObject m_transformed_rmesh; - + class SupportData : public sla::SupportableMesh { public: sla::SupportTree::UPtr support_tree_ptr; // the supports std::vector support_slices; // sliced supports TriangleMesh tree_mesh, pad_mesh, full_mesh; - + inline SupportData(const TriangleMesh &t) : sla::SupportableMesh{t.its, {}, {}} {} - + sla::SupportTree::UPtr &create_support_tree(const sla::JobController &ctl) { support_tree_ptr = sla::SupportTree::create(*this, ctl); @@ -335,9 +335,9 @@ private: pad_mesh = TriangleMesh{support_tree_ptr->retrieve_mesh(sla::MeshType::Pad)}; } }; - + std::unique_ptr m_supportdata; - + class HollowingData { public: @@ -346,7 +346,7 @@ private: mutable TriangleMesh hollow_mesh_with_holes; // caching the complete hollowed mesh mutable TriangleMesh hollow_mesh_with_holes_trimmed; }; - + std::unique_ptr m_hollowing_data; }; @@ -390,15 +390,15 @@ struct SLAPrintStatistics class SLAArchive { protected: std::vector m_layers; - + virtual std::unique_ptr create_raster() const = 0; virtual sla::RasterEncoder get_encoder() const = 0; - + public: virtual ~SLAArchive() = default; - + virtual void apply(const SLAPrinterConfig &cfg) = 0; - + // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); template void draw_layers( @@ -434,9 +434,9 @@ class SLAPrint : public PrintBaseWithState { private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; - + class Steps; // See SLAPrintSteps.cpp - + public: SLAPrint(): m_stepmask(slapsCount, true) {} @@ -451,7 +451,7 @@ public: std::vector print_object_ids() const override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void set_task(const TaskParams ¶ms) override; - void process() override; + void process(bool use_cache = false) override; void finalize() override; // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; @@ -501,11 +501,11 @@ public: { m_transformed_slices = std::forward(c); } - + friend class SLAPrint::Steps; public: - + explicit PrintLayer(coord_t lvl) : m_level(lvl) {} // for being sorted in their container (see m_printer_input) @@ -527,11 +527,11 @@ public: // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - + void set_printer(SLAArchive *archiver); - + private: - + // Implement same logic as in SLAPrintObject bool invalidate_step(SLAPrintStep st); @@ -548,24 +548,24 @@ private: // Ready-made data for rasterization. std::vector m_printer_input; - + // The archive object which collects the raster images after slicing SLAArchive *m_printer = nullptr; - + // Estimated print time, material consumed. SLAPrintStatistics m_print_statistics; - + class StatusReporter { double m_st = 0; - + public: void operator()(SLAPrint & p, double st, const std::string &msg, unsigned flags = SlicingStatus::DEFAULT, const std::string &logmsg = ""); - + double status() const { return m_st; } } m_report_status; diff --git a/src/libslic3r/Shape/TextShape.cpp b/src/libslic3r/Shape/TextShape.cpp index 9185c1b018..d13bcca98b 100644 --- a/src/libslic3r/Shape/TextShape.cpp +++ b/src/libslic3r/Shape/TextShape.cpp @@ -30,6 +30,17 @@ namespace Slic3r { +static std::map g_occt_fonts_maps; //map + +static const std::vector fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin", +"Semibold", "ExtraBold", "ExtraBold", "Semilight", "SemiLight", "ExtraLight", "Extralight", "Ultralight", +"Condensed", "Ultra", "Extra", "Expanded", "Extended", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Al Tarikh"}; + +std::map get_occt_fonts_maps() +{ + return g_occt_fonts_maps; +} + std::vector init_occt_fonts() { std::vector stdFontNames; @@ -41,9 +52,46 @@ std::vector init_occt_fonts() aFontMgr->GetAvailableFontsNames(availFontNames); stdFontNames.reserve(availFontNames.Size()); - for (auto afn : availFontNames) - stdFontNames.push_back(afn->ToCString()); + g_occt_fonts_maps.clear(); + BOOST_LOG_TRIVIAL(info) << "init_occt_fonts start"; +#ifdef __APPLE__ + //from resource + stdFontNames.push_back("HarmonyOS Sans SC"); + g_occt_fonts_maps.insert(std::make_pair("HarmoneyOS Sans SC", Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf")); +#endif + for (auto afn : availFontNames) { +#ifdef __APPLE__ + if(afn->String().StartsWith(".")) + continue; +#endif + if(afn->Search("Emoji") != -1 || afn->Search("emoji") != -1) + continue; + bool repeat = false; + for (size_t i = 0; i < fonts_suffix.size(); i++) { + if (afn->SearchFromEnd(fonts_suffix[i]) != -1) { + repeat = true; + break; + } + } + if (repeat) + continue; + + Handle(Font_SystemFont) sys_font = aFontMgr->GetFont(afn->ToCString()); + TCollection_AsciiString font_path = sys_font->FontPath(Font_FontAspect::Font_FontAspect_Regular); + if (!font_path.IsEmpty() && font_path.SearchFromEnd(".") != -1) { + auto file_type = font_path.SubString(font_path.SearchFromEnd(".") + 1, font_path.Length()); + file_type.LowerCase(); + if (file_type == "ttf" || file_type == "otf" || file_type == "ttc") { + g_occt_fonts_maps.insert(std::make_pair(afn->ToCString(), decode_path(font_path.ToCString()))); + } + } + } + BOOST_LOG_TRIVIAL(info) << "init_occt_fonts end"; + // in order + for (auto occt_font : g_occt_fonts_maps) { + stdFontNames.push_back(occt_font.first); + } return stdFontNames; } diff --git a/src/libslic3r/Shape/TextShape.hpp b/src/libslic3r/Shape/TextShape.hpp index 0da84bb957..b0817d7fc4 100644 --- a/src/libslic3r/Shape/TextShape.hpp +++ b/src/libslic3r/Shape/TextShape.hpp @@ -7,6 +7,8 @@ class TriangleMesh; extern std::vector init_occt_fonts(); extern void load_text_shape(const char* text, const char* font, const float text_height, const float thickness, bool is_bold, bool is_italic, TriangleMesh& text_mesh); +std::map get_occt_fonts_maps(); + }; // namespace Slic3r #endif // slic3r_Text_Shape_hpp_ \ No newline at end of file diff --git a/src/libslic3r/ShortestPath.hpp b/src/libslic3r/ShortestPath.hpp index e68c0b6293..e68e1c49d0 100644 --- a/src/libslic3r/ShortestPath.hpp +++ b/src/libslic3r/ShortestPath.hpp @@ -24,6 +24,19 @@ void chain_and_reorder_extrusion_paths(std::vect Polylines chain_polylines(Polylines &&src, const Point *start_near = nullptr); inline Polylines chain_polylines(const Polylines& src, const Point* start_near = nullptr) { Polylines tmp(src); return chain_polylines(std::move(tmp), start_near); } +template inline void reorder_by_shortest_traverse(std::vector &polylines_out) +{ + Points start_point; + start_point.reserve(polylines_out.size()); + for (const T contour : polylines_out) start_point.push_back(contour.points.front()); + + std::vector order = chain_points(start_point); + + std::vector Temp = polylines_out; + polylines_out.erase(polylines_out.begin(), polylines_out.end()); + + for (size_t i:order) polylines_out.emplace_back(std::move(Temp[i])); +} std::vector chain_clipper_polynodes(const Points &points, const std::vector &items); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 7747b46760..36c04a523b 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -84,8 +84,6 @@ SlicingParameters SlicingParameters::create_from_config( params.object_print_z_max = object_height; params.base_raft_layers = object_config.raft_layers.value; params.soluble_interface = soluble_interface; - //BBS - params.adaptive_layer_height = print_config.enable_prime_tower ? false : object_config.adaptive_layer_height; // Miniumum/maximum of the minimum layer height over all extruders. params.min_layer_height = MIN_LAYER_HEIGHT; @@ -115,13 +113,12 @@ SlicingParameters SlicingParameters::create_from_config( if (! soluble_interface) { params.gap_raft_object = object_config.raft_contact_distance.value; //BBS - //params.gap_object_support = object_config.support_bottom_z_distance.value; - params.gap_object_support = object_config.support_top_z_distance.value; + params.gap_object_support = object_config.support_bottom_z_distance.value; params.gap_support_object = object_config.support_top_z_distance.value; if (params.gap_object_support <= 0) params.gap_object_support = params.gap_support_object; - if (!object_config.independent_support_layer_height) { + if (!print_config.independent_support_layer_height) { params.gap_raft_object = std::round(params.gap_raft_object / object_config.layer_height + EPSILON) * object_config.layer_height; params.gap_object_support = std::round(params.gap_object_support / object_config.layer_height + EPSILON) * object_config.layer_height; params.gap_support_object = std::round(params.gap_support_object / object_config.layer_height + EPSILON) * object_config.layer_height; @@ -400,31 +397,32 @@ std::vector smooth_height_profile(const std::vector& profile, co }; //BBS: avoid the layer height change to be too steep - auto has_steep_height_change = [&slicing_params](const std::vector& profile, const double height_step) { - //BBS: skip first layer - size_t skip_count = slicing_params.first_object_layer_height_fixed() ? 4 : 0; - size_t size = profile.size(); - //BBS: not enough data to smmoth, return false directly - if ((int)size - (int)skip_count < 6) - return false; + //auto has_steep_height_change = [&slicing_params](const std::vector& profile, const double height_step) { + // //BBS: skip first layer + // size_t skip_count = slicing_params.first_object_layer_height_fixed() ? 4 : 0; + // size_t size = profile.size(); + // //BBS: not enough data to smmoth, return false directly + // if ((int)size - (int)skip_count < 6) + // return false; - //BBS: Don't need to check the difference between top layer and the last 2th layer - for (size_t i = skip_count; i < size - 6; i += 2) { - if (abs(profile[i + 1] - profile[i + 3]) > height_step) - return true; - } - return false; - }; + // //BBS: Don't need to check the difference between top layer and the last 2th layer + // for (size_t i = skip_count; i < size - 6; i += 2) { + // if (abs(profile[i + 1] - profile[i + 3]) > height_step) + // return true; + // } + // 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; + //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/Slicing.hpp b/src/libslic3r/Slicing.hpp index 9b8d21e1c4..db0be3b863 100644 --- a/src/libslic3r/Slicing.hpp +++ b/src/libslic3r/Slicing.hpp @@ -96,8 +96,6 @@ struct SlicingParameters // In case of a soluble interface, object_print_z_min == raft_contact_top_z, otherwise there is a gap between the raft and the 1st object layer. coordf_t object_print_z_min { 0 }; coordf_t object_print_z_max { 0 }; - //BBS - bool adaptive_layer_height{ false }; }; static_assert(IsTriviallyCopyable::value, "SlicingParameters class is not POD (and it should be - see constructor)."); diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 13282b90d4..78a156c989 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1512,11 +1512,22 @@ static inline Polygons detect_overhangs( 0.; const coordf_t max_bridge_length = scale_(object_config.max_bridge_length.value); const bool bridge_no_support = object_config.bridge_no_support.value; + const coordf_t xy_expansion = scale_(object_config.support_expansion.value); - if (layer_id == 0) + if (layer_id == 0) { // Don't fill in the holes. The user may apply a higher raft_expansion if one wants a better 1st layer adhesion. overhang_polygons = to_polygons(layer.lslices); + + for (auto& slice : layer.lslices) { + auto bbox_size = get_extents(slice).size(); + if (g_config_support_sharp_tails && + !(bbox_size.x() > length_thresh_well_supported && bbox_size.y() > length_thresh_well_supported)) + { + layer.sharp_tails.push_back(slice); + layer.sharp_tails_height.insert({ &slice, layer.height }); + } + } } else if (! layer.regions().empty()) { @@ -1567,9 +1578,9 @@ static inline Polygons detect_overhangs( // Offset the support regions back to a full overhang, restrict them to the full overhang. // This is done to increase size of the supporting columns below, as they are calculated by // propagating these contact surfaces downwards. - diff_polygons = diff( - intersection(expand(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), - lower_layer_polygons); + diff_polygons = + expand(diff(intersection(expand(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), lower_layer_polygons), + xy_expansion, SUPPORT_SURFACES_OFFSET_PARAMETERS); } //FIXME add user defined filtering here based on minimal area or minimum radius or whatever. @@ -1608,12 +1619,12 @@ static inline Polygons detect_overhangs( supported_area += temp.area(); bbox.merge(get_extents(temp)); } - +#if 0 if (supported_area > area_thresh_well_supported) { is_sharp_tail = false; break; } - +#endif if (bbox.size().x() > length_thresh_well_supported && bbox.size().y() > length_thresh_well_supported) { is_sharp_tail = false; break; @@ -1839,7 +1850,7 @@ static inline std::pairlower_layer->print_z; } else { print_z = layer.bottom_z() - slicing_params.gap_support_object; - height = object_config.independent_support_layer_height ? 0. : object_config.layer_height; + height = print_config.independent_support_layer_height ? 0. : object_config.layer_height; bottom_z = print_z - height; // Ignore this contact area if it's too low. // Don't want to print a layer below the first layer height as it may not stick well. @@ -1870,7 +1881,7 @@ static inline std::pairregion().bridging_height_avg(print_config); bridging_height /= coordf_t(layer.regions().size()); // BBS: align bridging height - if (!object_config.independent_support_layer_height) + if (!print_config.independent_support_layer_height) bridging_height = std::ceil(bridging_height / object_config.layer_height - EPSILON) * object_config.layer_height; coordf_t bridging_print_z = layer.print_z - bridging_height - slicing_params.gap_support_object; if (bridging_print_z >= min_print_z) { @@ -1890,7 +1901,7 @@ static inline std::pairheight = object_config.independent_support_layer_height ? 0. : object_config.layer_height; + bridging_layer->height = print_config.independent_support_layer_height ? 0. : object_config.layer_height; // Don't know the height yet. bridging_layer->bottom_z = bridging_print_z - bridging_layer->height; } @@ -2423,7 +2434,7 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts( // top shapes so this can be done here //FIXME calculate layer height based on the actual thickness of the layer: // If the layer is extruded with no bridging flow, support just the normal extrusions. - layer_new.height = slicing_params.soluble_interface || !object.config().independent_support_layer_height ? + layer_new.height = slicing_params.soluble_interface || !object.print()->config().independent_support_layer_height ? // Align the interface layer with the object's layer height. layer.upper_layer->height : // Place a bridge flow interface layer or the normal flow interface layer over the top surface. @@ -4517,9 +4528,13 @@ void PrintObjectSupportMaterial::generate_toolpaths( (m_object_config->support_interface_bottom_layers == 0 && &layer_ex == &bottom_contact_layer); //FIXME Bottom interfaces are extruded with the briding flow. Some bridging layers have its height slightly reduced, therefore // the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b) - auto interface_flow = layer_ex.layer->bridging ? - Flow::bridging_flow(layer_ex.layer->height, m_support_params.support_material_bottom_interface_flow.nozzle_diameter()) : - (interface_as_base ? &m_support_params.support_material_flow : &m_support_params.support_material_interface_flow)->with_height(float(layer_ex.layer->height)); + Flow interface_flow; + if (layer_ex.layer->bridging) + interface_flow = Flow::bridging_flow(layer_ex.layer->height, m_support_params.support_material_bottom_interface_flow.nozzle_diameter()); + else if (layer_ex.layer->bottom_z < EPSILON) { + interface_flow = m_support_params.first_layer_flow; + }else + interface_flow = (interface_as_base ? &m_support_params.support_material_flow : &m_support_params.support_material_interface_flow)->with_height(float(layer_ex.layer->height)); filler_interface->angle = interface_as_base ? // If zero interface layers are configured, use the same angle as for the base layers. angles[support_layer_id % angles.size()] : diff --git a/src/libslic3r/SupportMaterial.hpp b/src/libslic3r/SupportMaterial.hpp index 7bb60dd536..861126fcbd 100644 --- a/src/libslic3r/SupportMaterial.hpp +++ b/src/libslic3r/SupportMaterial.hpp @@ -136,6 +136,7 @@ public: float base_angle; float interface_angle; coordf_t interface_spacing; + coordf_t support_expansion; coordf_t interface_density; coordf_t support_spacing; coordf_t support_density; @@ -161,7 +162,7 @@ public: bool has_support() const { return m_object_config->enable_support.value || m_object_config->enforce_support_layers; } bool build_plate_only() const { return this->has_support() && m_object_config->support_on_build_plate_only.value; } // BBS - bool synchronize_layers() const { return /*m_slicing_params.soluble_interface && */!m_object_config->independent_support_layer_height.value; } + bool synchronize_layers() const { return /*m_slicing_params.soluble_interface && */!m_print_config->independent_support_layer_height.value; } bool has_contact_loops() const { return m_object_config->support_interface_loop_pattern.value; } // Generate support material for the object. diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index 4920efbbfd..9494a9dcf1 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -6,7 +6,7 @@ namespace Slic3r { -enum SurfaceType { +enum SurfaceType { // Top horizontal surface, visible from the top. stTop, // Bottom horizontal surface, visible from the bottom, printed with a normal extrusion flow. @@ -15,6 +15,8 @@ enum SurfaceType { stBottomBridge, // Normal sparse infill. stInternal, + // Normal sparse infill. + stInternalWithLoop, // Full infill, supporting the top surfaces and/or defining the verticall wall thickness. stInternalSolid, // 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow. @@ -37,10 +39,14 @@ public: unsigned short thickness_layers; // in layers double bridge_angle; // in radians, ccw, 0 = East, only 0+ (negative means undefined) unsigned short extra_perimeters; - + + Surface(SurfaceType _surface_type = stInternal) + : surface_type(_surface_type), + thickness(-1), thickness_layers(1), bridge_angle(-1), extra_perimeters(0) + {}; Surface(const Slic3r::Surface &rhs) : surface_type(rhs.surface_type), expolygon(rhs.expolygon), - thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), + thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), bridge_angle(rhs.bridge_angle), extra_perimeters(rhs.extra_perimeters) {}; @@ -50,12 +56,12 @@ public: {}; Surface(const Surface &other, const ExPolygon &_expolygon) : surface_type(other.surface_type), expolygon(_expolygon), - thickness(other.thickness), thickness_layers(other.thickness_layers), + thickness(other.thickness), thickness_layers(other.thickness_layers), bridge_angle(other.bridge_angle), extra_perimeters(other.extra_perimeters) {}; Surface(Surface &&rhs) : surface_type(rhs.surface_type), expolygon(std::move(rhs.expolygon)), - thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), + thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), bridge_angle(rhs.bridge_angle), extra_perimeters(rhs.extra_perimeters) {}; Surface(SurfaceType _surface_type, const ExPolygon &&_expolygon) @@ -64,7 +70,7 @@ public: {}; Surface(const Surface &other, const ExPolygon &&_expolygon) : surface_type(other.surface_type), expolygon(std::move(_expolygon)), - thickness(other.thickness), thickness_layers(other.thickness_layers), + thickness(other.thickness), thickness_layers(other.thickness_layers), bridge_angle(other.bridge_angle), extra_perimeters(other.extra_perimeters) {}; @@ -192,8 +198,8 @@ inline size_t number_polygons(const SurfacesPtr &surfaces) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const Surfaces &src) -{ +inline void polygons_append(Polygons &dst, const Surfaces &src) +{ dst.reserve(dst.size() + number_polygons(src)); for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(it->expolygon.contour); @@ -201,8 +207,8 @@ inline void polygons_append(Polygons &dst, const Surfaces &src) } } -inline void polygons_append(Polygons &dst, Surfaces &&src) -{ +inline void polygons_append(Polygons &dst, Surfaces &&src) +{ dst.reserve(dst.size() + number_polygons(src)); for (Surfaces::iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(std::move(it->expolygon.contour)); @@ -212,8 +218,8 @@ inline void polygons_append(Polygons &dst, Surfaces &&src) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const SurfacesPtr &src) -{ +inline void polygons_append(Polygons &dst, const SurfacesPtr &src) +{ dst.reserve(dst.size() + number_polygons(src)); for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back((*it)->expolygon.contour); @@ -221,8 +227,8 @@ inline void polygons_append(Polygons &dst, const SurfacesPtr &src) } } -inline void polygons_append(Polygons &dst, SurfacesPtr &&src) -{ +inline void polygons_append(Polygons &dst, SurfacesPtr &&src) +{ dst.reserve(dst.size() + number_polygons(src)); for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(std::move((*it)->expolygon.contour)); @@ -232,41 +238,41 @@ inline void polygons_append(Polygons &dst, SurfacesPtr &&src) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType) -{ +inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType) +{ dst.reserve(dst.size() + src.size()); for (const ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceType, expoly)); } -inline void surfaces_append(Surfaces &dst, const ExPolygons &src, const Surface &surfaceTempl) -{ +inline void surfaces_append(Surfaces &dst, const ExPolygons &src, const Surface &surfaceTempl) +{ dst.reserve(dst.size() + number_polygons(src)); for (const ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceTempl, expoly)); } -inline void surfaces_append(Surfaces &dst, const Surfaces &src) -{ +inline void surfaces_append(Surfaces &dst, const Surfaces &src) +{ dst.insert(dst.end(), src.begin(), src.end()); } -inline void surfaces_append(Surfaces &dst, ExPolygons &&src, SurfaceType surfaceType) -{ +inline void surfaces_append(Surfaces &dst, ExPolygons &&src, SurfaceType surfaceType) +{ dst.reserve(dst.size() + src.size()); for (ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceType, std::move(expoly))); src.clear(); } -inline void surfaces_append(Surfaces &dst, ExPolygons &&src, const Surface &surfaceTempl) -{ +inline void surfaces_append(Surfaces &dst, ExPolygons &&src, const Surface &surfaceTempl) +{ dst.reserve(dst.size() + number_polygons(src)); for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++ it) dst.emplace_back(Surface(surfaceTempl, std::move(*it))); src.clear(); } -inline void surfaces_append(Surfaces &dst, Surfaces &&src) -{ +inline void surfaces_append(Surfaces &dst, Surfaces &&src) +{ if (dst.empty()) { dst = std::move(src); } else { @@ -281,7 +287,7 @@ extern BoundingBox get_extents(const SurfacesPtr &surfaces); inline bool surfaces_could_merge(const Surface &s1, const Surface &s2) { - return + return s1.surface_type == s2.surface_type && s1.thickness == s2.thickness && s1.thickness_layers == s2.thickness_layers && diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 7e01a68dfb..50be3e97da 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -37,6 +37,12 @@ public: for (Surface &surface : this->surfaces) surface.surface_type = type; } + //BBS + void change_to_new_type(SurfaceType old_type, SurfaceType new_type) { + for (Surface& surface : this->surfaces) + if (surface.surface_type == old_type) + surface.surface_type = new_type; + } void clear() { surfaces.clear(); } bool empty() const { return surfaces.empty(); } diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 43f76edd1a..24fb7f65c8 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -29,7 +29,7 @@ #define TAU (2.0 * M_PI) #define NO_INDEX (std::numeric_limits::max()) -#define SUPPORT_TREE_DEBUG_TO_SVG +//#define SUPPORT_TREE_DEBUG_TO_SVG namespace Slic3r { @@ -687,12 +687,11 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p SupportMaterialPattern support_pattern = m_object_config->support_base_pattern; m_support_params.base_fill_pattern = -#if HAS_LIGHTNING_INFILL support_pattern == smpLightning ? ipLightning : -#endif support_pattern == smpHoneycomb ? ipHoneycomb : m_support_params.support_density > 0.95 || m_support_params.with_sheath ? ipRectilinear : ipSupportBase; + m_support_params.interface_fill_pattern = (m_support_params.interface_density > 0.95 ? ipRectilinear : ipSupportBase); m_support_params.contact_fill_pattern = (m_object_config->support_interface_pattern == smipAuto && m_slicing_params.soluble_interface) || m_object_config->support_interface_pattern == smipConcentric ? @@ -708,7 +707,7 @@ void TreeSupport::detect_object_overhangs() if (m_object->tree_support_layer_count() >= m_object->layer_count()) return; - // Create Tree Support Layers + // Clear and create Tree Support Layers m_object->clear_tree_support_layers(); m_object->clear_tree_support_preview_cache(); @@ -721,11 +720,11 @@ void TreeSupport::detect_object_overhangs() const coordf_t extrusion_width = config.line_width.value; const coordf_t extrusion_width_scaled = scale_(extrusion_width); const coordf_t max_bridge_length = scale_(config.max_bridge_length.value); - const bool bridge_no_support = max_bridge_length > 0;// config.bridge_no_support.value; + const bool bridge_no_support = max_bridge_length > 0; const bool support_critical_regions_only = config.support_critical_regions_only.value; const int enforce_support_layers = config.enforce_support_layers.value; - const double area_thresh_well_supported = SQ(scale_(6)); // min: 6x6=36mm^2 - const double length_thresh_well_supported = scale_(6); // min: 6mm + const double area_thresh_well_supported = SQ(scale_(6)); + const double length_thresh_well_supported = scale_(6); static const double sharp_tail_max_support_height = 8.f; // a region is considered well supported if the number of layers below it exceeds this threshold const int thresh_layers_below = 10 / config.layer_height; @@ -822,20 +821,18 @@ void TreeSupport::detect_object_overhangs() region2clusterInd.emplace(®ion, regionClusters.size() - 1); } }; - - has_sharp_tail = false; + // main part of sharptail detections if (std::set{stTreeAuto, stHybridAuto, stTree}.count(stype))// == stTreeAuto || stype == stHybridAuto || stype == stTree) { double threshold_rad = (config.support_threshold_angle.value < EPSILON ? 30 : config.support_threshold_angle.value+1) * M_PI / 180.; - ExPolygons regions_well_supported; // regions on buildplate or well supported - std::map region_layers_below; // regions and the number of layers below - ExPolygons lower_overhang_dilated; // for small overhang - - for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) - { + ExPolygons regions_well_supported; + std::map region_layers_below; + ExPolygons lower_overhang_dilated; + + for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++){ if (m_object->print()->canceled()) break; - + if (!is_auto && layer_nr > enforce_support_layers) continue; @@ -846,9 +843,13 @@ void TreeSupport::detect_object_overhangs() if (layer->lower_layer == nullptr) { for (auto& slice : layer->lslices) { auto bbox_size = get_extents(slice).size(); - if (slice.area() > area_thresh_well_supported - || (bbox_size.x()>length_thresh_well_supported && bbox_size.y()>length_thresh_well_supported)) + if (/*slice.area() > area_thresh_well_supported || */ + (bbox_size.x()>length_thresh_well_supported && bbox_size.y()>length_thresh_well_supported)) regions_well_supported.emplace_back(slice); + else if(g_config_support_sharp_tails){ + layer->sharp_tails.push_back(slice); + layer->sharp_tails_height.insert({ &slice, layer->height }); + } } continue; } @@ -873,7 +874,7 @@ void TreeSupport::detect_object_overhangs() // normal overhang ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS); ExPolygons overhang_areas = std::move(diff_ex(curr_polys, lower_layer_offseted)); - // overhang_areas = std::move(offset2_ex(overhang_areas, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled)); + overhang_areas.erase(std::remove_if(overhang_areas.begin(), overhang_areas.end(), [extrusion_width_scaled](ExPolygon &area) { return offset_ex(area, -0.1 * extrusion_width_scaled).empty(); }), overhang_areas.end()); @@ -903,7 +904,6 @@ void TreeSupport::detect_object_overhangs() overhangs_sharp_tail = diff_ex(overhangs_sharp_tail, overhang_areas); } if (!overhangs_sharp_tail.empty()) { - has_sharp_tail = true; append(layer->sharp_tails, overhangs_sharp_tail); overhang_areas = union_ex(overhang_areas, overhangs_sharp_tail); } @@ -935,12 +935,13 @@ void TreeSupport::detect_object_overhangs() // 2.2 If sharp tail below, check whether it support this region enough. float supported_area = area(supported_by_lower); BoundingBox bbox = get_extents(supported_by_lower); - +#if 0 + // judge by area isn't reliable, failure cases include 45 degree rotated cube if (supported_area > area_thresh_well_supported) { is_sharp_tail = false; break; } - +#endif if (bbox.size().x() > length_thresh_well_supported && bbox.size().y() > length_thresh_well_supported) { is_sharp_tail = false; break; @@ -953,7 +954,6 @@ void TreeSupport::detect_object_overhangs() break; } } - if (accum_height >= sharp_tail_max_support_height) { is_sharp_tail = false; break; @@ -961,7 +961,7 @@ void TreeSupport::detect_object_overhangs() // 2.4 if the area grows fast than threshold, it get connected to other part or // it has a sharp slop and will be auto supported. - ExPolygons new_overhang_expolys = diff_ex({ expoly }, lower_layer_sharptails); + ExPolygons new_overhang_expolys = diff_ex({expoly}, lower_layer_sharptails); if (!offset_ex(new_overhang_expolys, -5.0 * extrusion_width_scaled).empty()) { is_sharp_tail = false; break; @@ -972,7 +972,6 @@ void TreeSupport::detect_object_overhangs() } while (0); if (is_sharp_tail) { - has_sharp_tail = true; ExPolygons overhang = diff_ex({expoly}, lower_layer->lslices); layer->sharp_tails.push_back(expoly); layer->sharp_tails_height.insert({ &expoly, accum_height }); @@ -1065,7 +1064,7 @@ void TreeSupport::detect_object_overhangs() } dist_max = std::max(dist_max, dist_pt); } - if (dist_max > scale_(5)) { // this cluster is cantilever, add all expolygons to sharp tail + if (dist_max > scale_(3)) { // this cluster is cantilever if the farmost point is larger than 3mm away from base for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) { int layer_nr = it->first; auto p_overhang = it->second; @@ -1133,10 +1132,10 @@ void TreeSupport::detect_object_overhangs() // if (erode1.empty() && !inter_with_others.empty()) // blockers[layer_nr].push_back(p_overhang->contour); } - } } + has_overhangs = false; for (int layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { if (m_object->print()->canceled()) break; @@ -1144,7 +1143,12 @@ void TreeSupport::detect_object_overhangs() TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers); if (support_critical_regions_only) { auto layer = m_object->get_layer(layer_nr); - ts_layer->overhang_areas = layer->sharp_tails; + auto lower_layer = layer->lower_layer; + if (lower_layer == nullptr) + ts_layer->overhang_areas = layer->sharp_tails; + else + ts_layer->overhang_areas = diff_ex(layer->sharp_tails, lower_layer->lslices); + append(ts_layer->overhang_areas, layer->cantilevers); } @@ -1156,17 +1160,20 @@ void TreeSupport::detect_object_overhangs() for (auto &area : ts_layer->overhang_areas) { ts_layer->overhang_types.emplace(&area, TreeSupportLayer::Detected); } - + // enforcers if (layer_nr < enforcers.size()) { Polygons& enforcer = enforcers[layer_nr]; // coconut: enforcer can't do offset2_ex, otherwise faces with angle near 90 degrees can't have enforcers, which // is not good. For example: tails of animals needs extra support except the lowest tip. //enforcer = std::move(offset2_ex(enforcer, -0.1 * extrusion_width_scaled, 0.1 * extrusion_width_scaled)); + enforcer = offset(enforcer, 0.1 * extrusion_width_scaled); for (const Polygon& poly : enforcer) { ts_layer->overhang_areas.emplace_back(poly); ts_layer->overhang_types.emplace(&ts_layer->overhang_areas.back(), TreeSupportLayer::Enforced); } } + + if (!ts_layer->overhang_areas.empty()) has_overhangs = true; } #ifdef SUPPORT_TREE_DEBUG_TO_SVG @@ -1296,7 +1303,7 @@ static void make_perimeter_and_inner_brim(ExtrusionEntitiesPtr &dst, const Print float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); } -static void make_perimeter_and_infill(ExtrusionEntitiesPtr& dst, const Print& print, const ExPolygon& support_area, size_t wall_count, const Flow& flow, ExtrusionRole role, Fill* filler_support, double support_density) +static void make_perimeter_and_infill(ExtrusionEntitiesPtr& dst, const Print& print, const ExPolygon& support_area, size_t wall_count, const Flow& flow, ExtrusionRole role, Fill* filler_support, double support_density, bool infill_first=true) { Polygons loops; ExPolygons support_area_new = offset_ex(support_area, -0.5f * float(flow.scaled_spacing()), jtSquare); @@ -1357,20 +1364,29 @@ static void make_perimeter_and_infill(ExtrusionEntitiesPtr& dst, const Print& pr expoly_list.erase(first_iter); } - extrusion_entities_append_loops(dst, std::move(loops), role, - float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); + if (infill_first) + extrusion_entities_append_loops(dst, std::move(loops), role, + float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); + else { // loops first + ExtrusionEntitiesPtr loops_entities; + extrusion_entities_append_loops(loops_entities, std::move(loops), role, + float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); + loops_entities.insert(loops_entities.end(), dst.begin(), dst.end()); + dst = std::move(loops_entities); + } + } + if (infill_first) { + // sort regions to reduce travel + Points ordering_points; + for (const auto& area : dst) + ordering_points.push_back(area->first_point()); + std::vector order = chain_points(ordering_points); + ExtrusionEntitiesPtr new_dst; + new_dst.reserve(ordering_points.size()); + for (size_t i : order) + new_dst.emplace_back(dst[i]); + dst = new_dst; } - - // sort regions to reduce travel - Points ordering_points; - for (const auto& area : dst) - ordering_points.push_back(area->first_point()); - std::vector order = chain_points(ordering_points); - ExtrusionEntitiesPtr new_dst; - new_dst.reserve(ordering_points.size()); - for (size_t i : order) - new_dst.emplace_back(dst[i]); - dst = new_dst; } void TreeSupport::generate_toolpaths() @@ -1379,10 +1395,10 @@ void TreeSupport::generate_toolpaths() const PrintObjectConfig &object_config = m_object->config(); coordf_t support_extrusion_width = object_config.support_line_width.value > 0 ? object_config.support_line_width : object_config.line_width; coordf_t nozzle_diameter = print_config.nozzle_diameter.get_at(object_config.support_filament - 1); + coordf_t layer_height = object_config.layer_height.value; const size_t wall_count = object_config.tree_support_wall_count.value; - const bool with_infill = object_config.tree_support_with_infill.value; - const bool contact_loops = object_config.support_interface_loop_pattern.value; + const bool with_infill = object_config.support_base_pattern != smpNone && object_config.support_base_pattern != smpDefault; auto m_support_material_flow = support_material_flow(m_object, float(m_slicing_params.layer_height)); // coconut: use same intensity settings as SupportMaterial.cpp @@ -1502,20 +1518,20 @@ void TreeSupport::generate_toolpaths() TreeSupportLayer* ts_layer = m_object->get_tree_support_layer(layer_id); Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); - + ts_layer->support_fills.no_sort = false; for (auto& area_group : ts_layer->area_groups) { - ExPolygon& poly = *area_group.first; + ExPolygon& poly = *area_group.area; ExPolygons polys; FillParams fill_params; - if (area_group.second != TreeSupportLayer::BaseType) { + if (area_group.type != TreeSupportLayer::BaseType) { // interface if (layer_id == 0) { Flow flow = m_raft_layers == 0 ? m_object->print()->brim_flow() : support_flow; make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, wall_count, flow, - area_group.second == TreeSupportLayer::RoofType); + area_group.type == TreeSupportLayer::RoofType); polys = std::move(offset_ex(poly, -flow.scaled_spacing())); - } else if (area_group.second == TreeSupportLayer::Roof1stLayer) { + } else if (area_group.type == TreeSupportLayer::Roof1stLayer) { polys = std::move(offset_ex(poly, 0.5*support_flow.scaled_width())); } else { @@ -1524,73 +1540,61 @@ void TreeSupport::generate_toolpaths() fill_params.density = interface_density; fill_params.dont_adjust = true; } - if (area_group.second == TreeSupportLayer::Roof1stLayer) { + if (area_group.type == TreeSupportLayer::Roof1stLayer) { // roof_1st_layer fill_params.density = interface_density; // Note: spacing means the separation between two lines as if they are tightly extruded filler_Roof1stLayer->spacing = m_support_material_interface_flow.spacing(); - fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(polys), filler_Roof1stLayer.get(), fill_params, erSupportMaterial, - m_support_material_interface_flow); - } else if (area_group.second == TreeSupportLayer::FloorType) { + // generate a perimeter first to support interface better + ExtrusionEntityCollection* temp_support_fills = new ExtrusionEntityCollection(); + make_perimeter_and_infill(temp_support_fills->entities, *m_object->print(), poly, 1, m_support_material_interface_flow, erSupportMaterial, + filler_Roof1stLayer.get(), interface_density, false); + temp_support_fills->no_sort = true; // make sure loops are first + if (!temp_support_fills->entities.empty()) + ts_layer->support_fills.entities.push_back(temp_support_fills); + else + delete temp_support_fills; + } else if (area_group.type == TreeSupportLayer::FloorType) { // floor_areas fill_params.density = bottom_interface_density; filler_interface->spacing = m_support_material_interface_flow.spacing(); fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(polys), filler_interface.get(), fill_params, erSupportMaterialInterface, m_support_material_interface_flow); - } else if (area_group.second == TreeSupportLayer::RoofType) { + } else if (area_group.type == TreeSupportLayer::RoofType) { // roof_areas - fill_params.density = interface_density; + fill_params.density = interface_density; filler_interface->spacing = m_support_material_interface_flow.spacing(); - /*if (contact_loops) { - make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, - std::numeric_limits::max(), m_support_material_interface_flow, true); - } - else*/ { - fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(polys), - filler_interface.get(), fill_params, erSupportMaterialInterface, m_support_material_interface_flow); - } + fill_expolygons_generate_paths(ts_layer->support_fills.entities, std::move(polys), filler_interface.get(), fill_params, erSupportMaterialInterface, + m_support_material_interface_flow); } else { // base_areas filler_support->spacing = m_support_material_flow.spacing(); - ExtrusionRole role; Flow flow = (layer_id == 0 && m_raft_layers == 0) ? m_object->print()->brim_flow() : (m_support_params.base_fill_pattern == ipRectilinear && (layer_id % num_layers_to_change_infill_direction == 0) ? support_transition_flow(m_object) : support_flow); - if (with_infill && layer_id > 0 && m_support_params.base_fill_pattern != ipLightning) { - if (m_support_params.base_fill_pattern == ipRectilinear) { - role = erSupportMaterial;// layer_id% num_layers_to_change_infill_direction == 0 ? erSupportTransition : erSupportMaterial; - filler_support->angle = Geometry::deg2rad(object_config.support_angle.value);// obj_is_vertical* M_PI_2;// (obj_is_vertical + int(layer_id / num_layers_to_change_infill_direction))* M_PI_2; - } - else { - role = erSupportMaterial; - filler_support->angle = Geometry::deg2rad(object_config.support_angle.value);// obj_is_vertical * M_PI_2 + (float)layer_id / num_layers_to_change_infill_direction * M_PI_4; - } - // only wall at the top of tree branch - if (offset(poly, -branch_radius_scaled*1.5).empty()) - { + if (area_group.dist_to_top < 10 / layer_height) { + // extra 2 walls for the top tips + make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, wall_count + 2, flow, false); + } else { + if (with_infill && layer_id > 0 && m_support_params.base_fill_pattern != ipLightning) { + filler_support->angle = Geometry::deg2rad(object_config.support_angle.value); + + // allow infill-only mode if support is thick enough + if (offset(poly, -scale_(support_spacing * 1.5)).empty() == false) { + make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, wall_count, flow, erSupportMaterial, + filler_support.get(), support_density); + } else { // otherwise must draw 1 wall + make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, std::max(size_t(1), wall_count), flow, + erSupportMaterial, filler_support.get(), support_density); + } + } else { make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, - wall_count, flow, false); + layer_id > 0 ? wall_count : std::numeric_limits::max(), flow, false); } - // allow infill-only mode if support is thick enough - else if (offset(poly, -scale_(support_spacing * 1.5)).empty() == false) - { - make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, wall_count, flow, role, filler_support.get(), support_density); - } - else { // otherwise must draw 1 wall - //if (m_support_params.base_fill_pattern == ipRectilinear) - make_perimeter_and_infill(ts_layer->support_fills.entities, *m_object->print(), poly, 1, flow, role, filler_support.get(), support_density); - //else - // make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, 1, flow, false); - } - } - else - { - make_perimeter_and_inner_brim(ts_layer->support_fills.entities, *m_object->print(), poly, - layer_id > 0 ? wall_count : std::numeric_limits::max(), flow, false); } } } - if (with_infill && m_support_params.base_fill_pattern == ipLightning) + if (m_support_params.base_fill_pattern == ipLightning) { double print_z = ts_layer->print_z; if (printZ_to_lightninglayer.find(print_z) == printZ_to_lightninglayer.end()) @@ -1603,11 +1607,7 @@ void TreeSupport::generate_toolpaths() // strengthen lightnings while it may make support harder. decide to enable it or not. if yes, proper values for params are remained to be tested auto& lightning_layer = generator->getTreesForLayer(printZ_to_lightninglayer[print_z]); - Flow flow = (layer_id == 0 && m_raft_layers == 0) ? - m_object->print()->brim_flow() : - (m_support_params.base_fill_pattern == ipRectilinear && (layer_id % num_layers_to_change_infill_direction == 0) ? - support_transition_flow(m_object) : - support_flow); + Flow flow = (layer_id == 0 && m_raft_layers == 0) ? m_object->print()->brim_flow() :support_flow; ExPolygons areas = offset_ex(ts_layer->base_areas, -flow.scaled_spacing()); for (auto& area : areas) @@ -1636,24 +1636,21 @@ void TreeSupport::generate_toolpaths() float(flow.mm3_per_mm()), float(flow.width()), float(flow.height())); #ifdef SUPPORT_TREE_DEBUG_TO_SVG - std::string prefix = "./SVG/"; - std::string suffix = ".svg"; - std::string name = prefix + "trees_polyline" + "_" + std::to_string(ts_layer->print_z) /*+ "_" + std::to_string(rand_num)*/ + suffix; + std::string name = "./SVG/trees_polyline_" + std::to_string(ts_layer->print_z) /*+ "_" + std::to_string(rand_num)*/ + ".svg"; BoundingBox bbox = get_extents(ts_layer->base_areas); SVG svg(name, bbox); - - svg.draw(ts_layer->base_areas, "blue"); - svg.draw(generator->Overhangs()[printZ_to_lightninglayer[print_z]], "red"); - for (auto& line : opt_polylines) - { - svg.draw(line, "yellow"); + if (svg.is_opened()) { + svg.draw(ts_layer->base_areas, "blue"); + svg.draw(generator->Overhangs()[printZ_to_lightninglayer[print_z]], "red"); + for (auto &line : opt_polylines) svg.draw(line, "yellow"); } #endif } } // sort extrusions to reduce travel, also make sure walls go before infills - chain_and_reorder_extrusion_entities(ts_layer->support_fills.entities); + if(ts_layer->support_fills.no_sort==false) + chain_and_reorder_extrusion_entities(ts_layer->support_fills.entities); } } ); @@ -1871,7 +1868,7 @@ void TreeSupport::generate_support_areas() if (!tree_support_enable) return; - std::vector> contact_nodes(m_object->layers().size()); //Generate empty layers to store the points in. + std::vector> contact_nodes(m_object->layers().size()); profiler.stage_start(STAGE_total); @@ -1881,6 +1878,8 @@ void TreeSupport::generate_support_areas() detect_object_overhangs(); profiler.stage_finish(STAGE_DETECT_OVERHANGS); + if (!has_overhangs) return; + // Generate contact points of tree support profiler.stage_start(STAGE_GENERATE_CONTACT_NODES); m_object->print()->set_status(56, _L("Support: generate contact points")); @@ -1963,8 +1962,9 @@ ExPolygons avoid_object_remove_extra_small_parts(ExPolygons &expolys, const ExPo void TreeSupport::draw_circles(const std::vector>& contact_nodes) { const PrintObjectConfig &config = m_object->config(); - bool has_brim = m_object->print()->has_brim(); - bool has_infill = config.tree_support_with_infill.value; + const Print* print = m_object->print(); + bool has_brim = print->has_brim(); + bool has_infill = config.support_base_pattern.value != smpNone && config.support_base_pattern != smpDefault; int bottom_gap_layers = round(m_slicing_params.gap_object_support / m_slicing_params.layer_height); const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2; const coordf_t branch_radius_scaled = scale_(branch_radius); @@ -1988,7 +1988,6 @@ void TreeSupport::draw_circles(const std::vector>& contact_no // Performance optimization. Only generate lslices for brim and skirt. size_t brim_skirt_layers = has_brim ? 1 : 0; - const Print* print = m_object->print(); const PrintConfig& print_config = print->config(); for (const PrintObject* object : print->objects()) { @@ -2005,7 +2004,7 @@ void TreeSupport::draw_circles(const std::vector>& contact_no const coordf_t line_width = config.support_line_width; const coordf_t line_width_scaled = scale_(line_width); - const bool with_lightning_infill = config.tree_support_with_infill.value && config.support_base_pattern.value == smpLightning; + const bool with_lightning_infill = m_support_params.base_fill_pattern == ipLightning; coordf_t support_extrusion_width = config.support_line_width.value > 0 ? config.support_line_width : config.line_width; const size_t wall_count = config.tree_support_wall_count.value; @@ -2013,6 +2012,7 @@ void TreeSupport::draw_circles(const std::vector>& contact_no auto m_support_material_flow = support_material_flow(m_object, float(m_slicing_params.layer_height)); coordf_t support_spacing = object_config.support_base_pattern_spacing.value + m_support_material_flow.spacing(); coordf_t support_density = std::min(1., m_support_material_flow.spacing() / support_spacing); + BOOST_LOG_TRIVIAL(info) << "draw_circles for object: " << m_object->model_object()->name; // coconut: previously std::unordered_map in m_collision_cache is not multi-thread safe which may cause programs stuck, here we change to tbb::concurrent_unordered_map tbb::parallel_for( @@ -2042,6 +2042,10 @@ void TreeSupport::draw_circles(const std::vector>& contact_no ExPolygons& roof_areas = ts_layer->roof_areas; ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer; ExPolygons& floor_areas = ts_layer->floor_areas; + ExPolygons& roof_gap_areas = ts_layer->roof_gap_areas; + int max_layers_above_base = 0; + int max_layers_above_roof = 0; + int max_layers_above_roof1 = 0; BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << contact_nodes[layer_nr].size(); //Draw the support areas and add the roofs appropriately to the support roof instead of normal areas. @@ -2053,14 +2057,24 @@ void TreeSupport::draw_circles(const std::vector>& contact_no const Node& node = *p_node; ExPolygon area; - if (node.type == ePolygon) { - area = offset_ex({ *node.overhang }, scale_(m_ts_data->m_xy_distance))[0]; + // 直接从overhang多边形生成,如果�? + // 1) 是混合支撑里的普通部分, + // 2) 启用了顶部接触层�? + // 3) 是顶部空�? + if (node.type == ePolygon || (top_interface_layers>0 &&node.support_roof_layers_below > 0) || node.distance_to_top<0) { + if (node.overhang->contour.size() > 100 || node.overhang->holes.size()>1) + area = *node.overhang; + else { + auto tmp = offset_ex({ *node.overhang }, scale_(m_ts_data->m_xy_distance)); + if(!tmp.empty()) // 对于有缺陷的模型,overhang膨胀以后可能是空的! + area = tmp[0]; + } } else { Polygon circle; size_t layers_to_top = node.distance_to_top; double scale; - if (top_interface_layers>0) { // if has infill, branch circles should be larger + if (top_interface_layers>0) { // if has interface, branch circles should be larger scale = static_cast(layers_to_top + 1) / tip_layers; scale = layers_to_top < tip_layers ? (0.5 + scale / 2) : (1 + static_cast(layers_to_top - tip_layers) * diameter_angle_scale_factor); } else { @@ -2080,17 +2094,22 @@ void TreeSupport::draw_circles(const std::vector>& contact_no area = ExPolygon(circle); } - if (node.support_roof_layers_below == 1) + if (node.distance_to_top < 0) + roof_gap_areas.emplace_back(area); + else if (node.support_roof_layers_below == 1) { roof_1st_layer.emplace_back(area); + max_layers_above_roof1 = std::max(max_layers_above_roof1, node.distance_to_top); } else if (node.support_roof_layers_below > 0) { roof_areas.emplace_back(area); + max_layers_above_roof = std::max(max_layers_above_roof, node.distance_to_top); } else { base_areas.emplace_back(area); + max_layers_above_base = std::max(max_layers_above_base, node.distance_to_top); } if (layer_nr < brim_skirt_layers) @@ -2129,6 +2148,7 @@ void TreeSupport::draw_circles(const std::vector>& contact_no base_areas = avoid_object_remove_extra_small_parts(base_areas, avoid_region); base_areas = std::move(diff_ex(base_areas, roof_areas)); base_areas = std::move(diff_ex(base_areas, roof_1st_layer)); + base_areas = std::move(diff_ex(base_areas, roof_gap_areas)); if (SQUARE_SUPPORT) { // simplify support contours @@ -2142,9 +2162,12 @@ void TreeSupport::draw_circles(const std::vector>& contact_no { if (layer_nr >= bottom_interface_layers + bottom_gap_layers) { - const Layer* below_layer = m_object->get_layer(layer_nr - bottom_interface_layers); - ExPolygons bottom_interface = std::move(intersection_ex(base_areas, below_layer->lslices)); - floor_areas.insert(floor_areas.end(), bottom_interface.begin(), bottom_interface.end()); + for (size_t i = 0; i <= bottom_gap_layers; i++) + { + const Layer* below_layer = m_object->get_layer(layer_nr - bottom_interface_layers - i); + ExPolygons bottom_interface = std::move(intersection_ex(base_areas, below_layer->lslices)); + floor_areas.insert(floor_areas.end(), bottom_interface.begin(), bottom_interface.end()); + } } if (floor_areas.empty() == false) { floor_areas = std::move(diff_ex(floor_areas, avoid_region_interface)); @@ -2159,15 +2182,14 @@ void TreeSupport::draw_circles(const std::vector>& contact_no floor_areas = std::move(diff_ex(floor_areas, bottom_gap)); } } - auto &area_groups = ts_layer->area_groups; - for (auto &area : ts_layer->base_areas) area_groups.emplace_back(&area, TreeSupportLayer::BaseType); - for (auto &area : ts_layer->roof_areas) area_groups.emplace_back(&area, TreeSupportLayer::RoofType); - for (auto &area : ts_layer->floor_areas) area_groups.emplace_back(&area, TreeSupportLayer::FloorType); - for (auto &area : ts_layer->roof_1st_layer) area_groups.emplace_back(&area, TreeSupportLayer::Roof1stLayer); + for (auto &area : ts_layer->base_areas) area_groups.emplace_back(&area, TreeSupportLayer::BaseType, max_layers_above_base); + for (auto &area : ts_layer->roof_areas) area_groups.emplace_back(&area, TreeSupportLayer::RoofType, max_layers_above_roof); + for (auto &area : ts_layer->floor_areas) area_groups.emplace_back(&area, TreeSupportLayer::FloorType, 10000); + for (auto &area : ts_layer->roof_1st_layer) area_groups.emplace_back(&area, TreeSupportLayer::Roof1stLayer, max_layers_above_roof1); for (auto &area_group : area_groups) { - auto expoly = area_group.first; + auto& expoly = area_group.area; expoly->holes.erase(std::remove_if(expoly->holes.begin(), expoly->holes.end(), [](auto &hole) { auto bbox_size = get_extents(hole).size(); @@ -2242,7 +2264,7 @@ void TreeSupport::draw_circles(const std::vector>& contact_no #endif } - generator = std::make_unique(m_object, contours, overhangs, support_density); + generator = std::make_unique(m_object, contours, overhangs, []() {}, support_density); } else if (!has_infill) { @@ -2294,13 +2316,13 @@ void TreeSupport::draw_circles(const std::vector>& contact_no auto& area_groups_lower = m_object->get_tree_support_layer(layer_nr_lower + m_raft_layers)->area_groups; for (const auto& area_group : ts_layer->area_groups) { - if (area_group.second != TreeSupportLayer::BaseType) continue; - const auto area = area_group.first; + if (area_group.type != TreeSupportLayer::BaseType) continue; + const auto& area = area_group.area; for (const auto& hole : area->holes) { // auto hole_bbox = get_extents(hole).polygon(); for (auto& area_group_lower : area_groups_lower) { - if (area_group.second != TreeSupportLayer::BaseType) continue; - auto& base_area_lower = *area_group_lower.first; + if (area_group.type != TreeSupportLayer::BaseType) continue; + auto& base_area_lower = *area_group_lower.area; Point pt_on_poly, pt_on_expoly, pt_far_on_poly; // if a hole doesn't intersect with lower layer's contours, add a hole to lower layer and move it slightly to the contour if (base_area_lower.contour.contains(hole.points.front()) && !intersects_contour(hole, base_area_lower, pt_on_poly, pt_on_expoly, pt_far_on_poly)) { @@ -2391,8 +2413,9 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down. const coordf_t layer_height = config.layer_height.value; const double angle = config.tree_support_branch_angle.value * M_PI / 180.; + const int wall_count = std::max(1, config.tree_support_wall_count.value); const double tan_angle = tan(angle); - const coordf_t max_move_distance = (angle < M_PI / 2) ? (coordf_t)(tan_angle * layer_height) : std::numeric_limits::max(); + const coordf_t max_move_distance = (angle < M_PI / 2) ? (coordf_t)(tan_angle * layer_height)*wall_count : std::numeric_limits::max(); const double max_move_distance2 = max_move_distance * max_move_distance; const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2; const size_t tip_layers = branch_radius / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle. @@ -2410,7 +2433,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) //m_object->print()->set_status(59, "Support: preparing avoidance regions "); // get all the possible radiis std::vector > all_layer_radius(m_highest_overhang_layer+1); - std::vector > all_layer_node_dist(m_highest_overhang_layer+1); + std::vector > all_layer_node_dist(m_highest_overhang_layer+1); for (size_t layer_nr = m_highest_overhang_layer; layer_nr > 0; layer_nr--) { auto& layer_contact_nodes = contact_nodes[layer_nr]; @@ -2486,6 +2509,13 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) { const Node& node = *p_node; + if (node.distance_to_top < 0) { + // virtual node do not merge or move + Node* next_node = new Node(p_node->position, p_node->distance_to_top + 1, p_node->skin_direction, p_node->support_roof_layers_below - 1, p_node->to_buildplate, p_node, + m_object->get_layer(layer_nr - 1)->print_z, m_object->get_layer(layer_nr - 1)->height); + contact_nodes[layer_nr - 1].emplace_back(next_node); + continue; + } if (support_on_buildplate_only && !node.to_buildplate) //Can't rest on model and unable to reach the build plate. Then we must drop the node and leave parts unsupported. { unsupported_branch_leaves.push_front({ layer_nr, p_node }); @@ -2664,13 +2694,18 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) // 1. do not merge neighbors under 5mm // 2. Only merge node with single neighbor in distance between [max_move_distance, 10mm/layer_height] float dist2_to_first_neighbor = neighbours.empty() ? 0 : vsize2_with_unscale(neighbours[0] - node.position); + float max_dist_to_move = 10.0*tan_angle; // don't move if moving down by 10mm and they still can't merge if (ts_layer->print_z > DO_NOT_MOVER_UNDER_MM && - (neighbours.size() > 1 || (neighbours.size() == 1 && dist2_to_first_neighbor >= max_move_distance2 && dist2_to_first_neighbor < SQ(10/layer_height)*max_move_distance2))) //Only nodes that aren't about to collapse. + (neighbours.size() > 1 || (neighbours.size() == 1 && dist2_to_first_neighbor >= max_move_distance2))) //Only nodes that aren't about to collapse. { //Move towards the average position of all neighbours. Point sum_direction(0, 0); for (const Point& neighbour : neighbours) { + // do not move to neighbor that's too far away + float dist2_to_neighbor = vsize2_with_unscale(neighbour - node.position); + if (dist2_to_neighbor > SQ(max_dist_to_move)) continue; + Point direction = neighbour - node.position; Node *neighbour_node = nodes_per_part[group_index][neighbour]; coordf_t branch_bottom_radius = calc_branch_radius(branch_radius, node.distance_to_top + layer_nr, tip_layers, diameter_angle_scale_factor); @@ -2707,7 +2742,6 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) #endif auto avoid_layer = m_ts_data->get_avoidance(branch_radius_node, layer_nr - 1); -#if 1 Point to_outside = projection_onto_ex(avoid_layer, node.position); Point movement = to_outside - node.position; double movelength2 = vsize2_with_unscale(movement); @@ -2726,14 +2760,12 @@ void TreeSupport::drop_nodes(std::vector>& contact_nodes) if (movement.dot(move_to_neighbor_center) >= 0) movement = movement + move_to_neighbor_center; // Cant do this. Otherwise we'll get a lot of supports in-the-air (nodes terminated too early) - //else - // movement = move_to_neighbor_center; // otherwise move to neighbor center first + else + movement = move_to_neighbor_center; // otherwise move to neighbor center first if (vsize2_with_unscale(movement) > max_move_distance2) movement = normal(movement, scale_(max_move_distance)); -#else - Point movement = move_to_neighbor_center; -#endif + next_layer_vertex += movement; @@ -2815,8 +2847,9 @@ void TreeSupport::adjust_layer_heights(std::vector>& contact_ if (contact_nodes.empty()) return; + const PrintConfig& print_config = m_object->print()->config(); const PrintObjectConfig& config = m_object->config(); - if (!config.independent_support_layer_height) { + if (!print_config.independent_support_layer_height) { for (int layer_nr = 0; layer_nr < contact_nodes.size(); layer_nr++) { std::vector& curr_layer_nodes = contact_nodes[layer_nr]; for (Node* node : curr_layer_nodes) { @@ -2936,7 +2969,7 @@ void TreeSupport::generate_contact_points(std::vectorthick_bridges) { z_distance_top += m_object->layers()[0]->regions()[0]->region().bridging_height_avg(m_object->print()->config()) - layer_height; } - const size_t z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; //Support must always be 1 layer below overhang. + const int z_distance_top_layers = round_up_divide(scale_(z_distance_top), scale_(layer_height)) + 1; //Support must always be 1 layer below overhang. const size_t support_roof_layers = config.support_interface_top_layers.value + 1; // BBS: add a normal support layer below interface coordf_t thresh_angle = config.support_threshold_angle.value < EPSILON ? 30.f : config.support_threshold_angle.value; @@ -2949,11 +2982,11 @@ void TreeSupport::generate_contact_points(std::vector all_nodes; - for (size_t layer_nr = 1; layer_nr < m_object->layers().size() - z_distance_top_layers; layer_nr++) + for (size_t layer_nr = 1; layer_nr < m_object->layers().size(); layer_nr++) { if (m_object->print()->canceled()) break; - auto ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers + z_distance_top_layers); + auto ts_layer = m_object->get_tree_support_layer(layer_nr + m_raft_layers); const ExPolygons &overhang = ts_layer->overhang_areas; auto & curr_nodes = contact_nodes[layer_nr]; if (overhang.empty()) @@ -2970,7 +3003,7 @@ void TreeSupport::generate_contact_points(std::vectortype = ePolygon; contact_node->overhang = &overhang_part; curr_nodes.emplace_back(contact_node); @@ -2996,9 +3029,9 @@ void TreeSupport::generate_contact_points(std::vectorget_collision(0, layer_nr), candidate)) { - constexpr size_t distance_to_top = 0; constexpr bool to_buildplate = true; - Node* contact_node = new Node(candidate, distance_to_top, (layer_nr + z_distance_top_layers) % 2, support_roof_layers, to_buildplate, Node::NO_PARENT,print_z,height); + Node* contact_node = new Node(candidate, -z_distance_top_layers, (layer_nr) % 2, support_roof_layers+ z_distance_top_layers, to_buildplate, Node::NO_PARENT,print_z,height); + contact_node->overhang = &overhang_part; curr_nodes.emplace_back(contact_node); added = true; } @@ -3018,9 +3051,9 @@ void TreeSupport::generate_contact_points(std::vectoroverhang = &overhang_part; curr_nodes.emplace_back(contact_node); } } @@ -3032,7 +3065,8 @@ void TreeSupport::generate_contact_points(std::vector -0.7) { - Node *contact_node = new Node(pt, 0, layer_nr % 2, support_roof_layers, true, Node::NO_PARENT, print_z, height); + Node *contact_node = new Node(pt, -z_distance_top_layers, layer_nr % 2, support_roof_layers+ z_distance_top_layers, true, Node::NO_PARENT, print_z, height); + contact_node->overhang = &overhang_part; curr_nodes.emplace_back(contact_node); } } diff --git a/src/libslic3r/TreeSupport.hpp b/src/libslic3r/TreeSupport.hpp index 610908ac1b..b5f25a507b 100644 --- a/src/libslic3r/TreeSupport.hpp +++ b/src/libslic3r/TreeSupport.hpp @@ -223,7 +223,7 @@ public: , height(0.0) {} - Node(const Point position, const size_t distance_to_top, const bool skin_direction, const int support_roof_layers_below, const bool to_buildplate, Node* parent, + Node(const Point position, const int distance_to_top, const bool skin_direction, const int support_roof_layers_below, const bool to_buildplate, Node* parent, coordf_t print_z_, coordf_t height_) : distance_to_top(distance_to_top) , position(position) @@ -252,8 +252,9 @@ public: /*! * \brief The number of layers to go to the top of this branch. + * Negative value means it's a virtual node between support and overhang, which doesn't need to be extruded. */ - size_t distance_to_top; + int distance_to_top; /*! * \brief The position of this node on the layer. @@ -350,7 +351,7 @@ public: int avg_node_per_layer = 0; float nodes_angle = 0; - bool has_sharp_tail; + bool has_overhangs = false; std::unique_ptr generator; std::unordered_map printZ_to_lightninglayer; diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 6182dfe641..63b739e8e2 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -399,7 +399,7 @@ struct SlabLines { std::vector at_slice; // Projections of triangle set boundary lines into layer below (for projection from the top) // or into layer above (for projection from the bottom). - // In both cases the intersection liens are CCW oriented. + // In both cases the intersection lines are CCW oriented. std::vector between_slices; }; @@ -753,7 +753,9 @@ inline std::pair slice_slabs_make_lines( const std::vector &zs, bool top, bool bottom, - const ThrowOnCancel throw_on_cancel_fn) + const ThrowOnCancel throw_on_cancel_fn, + // BBS: solve conflicts (see declaration) and most elegant way I can get + SlabSlicingConfig config) { std::pair out; SlabLines &lines_top = out.first; @@ -772,7 +774,7 @@ inline std::pair slice_slabs_make_lines( tbb::parallel_for( tbb::blocked_range(0, int(indices.size())), - [&vertices, &indices, &face_neighbors, &face_edge_ids, num_edges, &face_orientation, &zs, top, bottom, &lines_top, &lines_bottom, &lines_mutex_top, &lines_mutex_bottom, throw_on_cancel_fn] + [&vertices, &indices, &face_neighbors, &face_edge_ids, num_edges, &face_orientation, &zs, top, bottom, &lines_top, &lines_bottom, &lines_mutex_top, &lines_mutex_bottom, throw_on_cancel_fn, &config] (const tbb::blocked_range &range) { for (int face_idx = range.begin(); face_idx < range.end(); ++ face_idx) { if ((face_idx & 0x0ffff) == 0) @@ -790,7 +792,8 @@ inline std::pair slice_slabs_make_lines( } slice_facet_with_slabs(vertices, indices, face_idx, neighbors, edge_ids, num_edges, zs, lines_top, lines_mutex_top); } - if (bottom && (fo == FaceOrientation::Down || fo == FaceOrientation::Degenerate)) { + // BBS: add vertical faces option + if (bottom && (fo == FaceOrientation::Down || (config.isVertical && fo == FaceOrientation::Vertical) || fo == FaceOrientation::Degenerate)) { Vec3i neighbors = face_neighbors[face_idx]; // Reset neighborship of this triangle in case the other triangle is oriented backwards from this one. for (int i = 0; i < 3; ++ i) @@ -1895,7 +1898,8 @@ void slice_mesh_slabs( const Transform3d &trafo, std::vector *out_top, std::vector *out_bottom, - std::function throw_on_cancel) + std::function throw_on_cancel, + SlabSlicingConfig config) { BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons"; @@ -1974,7 +1978,7 @@ void slice_mesh_slabs( std::vector face_edge_ids = its_face_edge_ids(mesh, face_neighbors, true, &num_edges); std::pair lines = slice_slabs_make_lines( vertices_transformed, mesh.indices, face_neighbors, face_edge_ids, num_edges, face_orientation, zs, - out_top != nullptr, out_bottom != nullptr, throw_on_cancel); + out_top != nullptr, out_bottom != nullptr, throw_on_cancel, config); throw_on_cancel(); diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 1a8b643629..603e95e78e 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -46,6 +46,19 @@ struct MeshSlicingParamsEx : public MeshSlicingParams double resolution { 0 }; }; +// BBS: MusangKing - NEW: add paint-on support on vertical-faces +// this SlabSlicingConfig aiming to distinguish if slice_slabs_make_lines() outputs lines by slab_slicing on vertical faces +// e.g., for support enforcer operation: isVertical = true; for other color painting operations: isVertical = false (default). +// solve conflicts STUDIO-1183/970/1285 +struct SlabSlicingConfig +{ + SlabSlicingConfig() + : isVertical(false) + {} + + bool isVertical; +}; + // All the following slicing functions shall produce consistent results with the same mesh, same transformation matrix and slicing parameters. // Namely, slice_mesh_slabs() shall produce consistent results with slice_mesh() and slice_mesh_ex() in the sense, that projections made by // slice_mesh_slabs() shall fall onto slicing planes produced by slice_mesh(). @@ -107,7 +120,9 @@ void slice_mesh_slabs( const Transform3d &trafo, std::vector *out_top, std::vector *out_bottom, - std::function throw_on_cancel); + std::function throw_on_cancel, + // BBS: MusangKing + SlabSlicingConfig config = SlabSlicingConfig()); // Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons. void project_mesh( diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 08119e22a3..2bbb075d84 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -13,6 +13,42 @@ #include "libslic3r.h" +//define CLI errors + +#define CLI_SUCCESS 0 +#define CLI_ENVIRONMENT_ERROR -1 +#define CLI_INVALID_PARAMS -2 +#define CLI_FILE_NOTFOUND -3 +#define CLI_FILELIST_INVALID_ORDER -4 +#define CLI_CONFIG_FILE_ERROR -5 +#define CLI_DATA_FILE_ERROR -6 +#define CLI_INVALID_PRINTER_TECH -7 +#define CLI_UNSUPPORTED_OPERATION -8 + +#define CLI_COPY_OBJECTS_ERROR -9 +#define CLI_SCALE_TO_FIT_ERROR -10 +#define CLI_EXPORT_STL_ERROR -11 +#define CLI_EXPORT_OBJ_ERROR -12 +#define CLI_EXPORT_3MF_ERROR -13 +#define CLI_OUT_OF_MEMORY -14 +#define CLI_3MF_NOT_SUPPORT_MACHINE_CHANGE -15 +#define CLI_3MF_NEW_MACHINE_NOT_SUPPORTED -16 +#define CLI_PROCESS_NOT_COMPATIBLE -17 + + +#define CLI_NO_SUITABLE_OBJECTS -50 +#define CLI_VALIDATE_ERROR -51 +#define CLI_OBJECTS_PARTLY_INSIDE -52 +#define CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED -53 +#define CLI_EXPORT_CACHE_WRITE_FAILED -54 +#define CLI_IMPORT_CACHE_NOT_FOUND -55 +#define CLI_IMPORT_CACHE_DATA_CAN_NOT_USE -56 +#define CLI_IMPORT_CACHE_LOAD_FAILED -57 + + +#define CLI_SLICING_ERROR -100 + + namespace boost { namespace filesystem { class directory_entry; }} namespace Slic3r { @@ -161,11 +197,11 @@ namespace PerlUtils { std::string string_printf(const char *format, ...); -// Standard "generated by Slic3r version xxx timestamp xxx" header string, +// Standard "generated by Slic3r version xxx timestamp xxx" header string, // to be placed at the top of Slic3r generated files. std::string header_slic3r_generated(); -// Standard "generated by PrusaGCodeViewer version xxx timestamp xxx" header string, +// Standard "generated by PrusaGCodeViewer version xxx timestamp xxx" header string, // to be placed at the top of Slic3r generated files. std::string header_gcodeviewer_generated(); @@ -247,38 +283,38 @@ inline INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count) } template -inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ return prev_idx_modulo(idx, container.size()); } template inline typename CONTAINER_TYPE::size_type next_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return next_idx_modulo(idx, container.size()); } template inline const typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return container[prev_idx_modulo(idx, container.size())]; } template -inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) -{ +inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) +{ return container[prev_idx_modulo(idx, container.size())]; } template inline const typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return container[next_idx_modulo(idx, container.size())]; } template inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) -{ +{ return container[next_idx_modulo(idx, container.size())]; } @@ -300,7 +336,7 @@ template struct IsTriviallyCopyable : public std::is_trivially_copya struct FilePtr { FilePtr(FILE *f) : f(f) {} ~FilePtr() { this->close(); } - void close() { + void close() { if (this->f) { ::fclose(this->f); this->f = nullptr; @@ -347,16 +383,19 @@ inline std::string short_time(const std::string &time) int hours = 0; int minutes = 0; int seconds = 0; + float f_seconds = 0.0; if (time.find('d') != std::string::npos) ::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds); else if (time.find('h') != std::string::npos) ::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds); else if (time.find('m') != std::string::npos) ::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds); - else if (time.find('s') != std::string::npos) - ::sscanf(time.c_str(), "%ds", &seconds); + else if (time.find('s') != std::string::npos) { + ::sscanf(time.c_str(), "%fs", &f_seconds); + seconds = int(f_seconds); + } // Round to full minutes. - if (days + hours + minutes > 0 && seconds >= 30) { + if (days + hours > 0 && seconds >= 30) { if (++minutes == 60) { minutes = 0; if (++hours == 24) { @@ -372,9 +411,13 @@ inline std::string short_time(const std::string &time) else if (hours > 0) ::sprintf(buffer, "%dh%dm", hours, minutes); else if (minutes > 0) - ::sprintf(buffer, "%dm%ds", minutes, seconds); - else - ::sprintf(buffer, "%ds", seconds); + ::sprintf(buffer, "%dm%ds", minutes, (int)seconds); + else if (seconds >= 1) + ::sprintf(buffer, "%ds", (int)seconds); + else if (f_seconds > 0 && f_seconds < 1) + ::sprintf(buffer, "<1s"); + else if (seconds == 0) + ::sprintf(buffer, "0s"); return buffer; } @@ -395,8 +438,10 @@ inline std::string get_time_dhms(float time_in_secs) ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs); else if (minutes > 0) ::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs); - else + else if (time_in_secs > 1) ::sprintf(buffer, "%ds", (int)time_in_secs); + else + ::sprintf(buffer, "%fs", time_in_secs); return buffer; } diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 8e85567131..887931e244 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -75,6 +75,7 @@ static constexpr double BRIDGE_INFILL_MARGIN = 1; //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) +#define unscale_(val) ((val) * SCALING_FACTOR) //BBS: BBS only support relative E and can't been changed by user at the moment. because //BBS need to support skip object when printing. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 0e1565117e..5951b2217c 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -818,7 +818,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s if (ec) { error_message = ec.message(); BOOST_LOG_TRIVIAL(error) << boost::format("###copy_file from %1% to %2% failed, error: %3% ") - %source.string() %target.string() << error_message; + %source.string() %target.string() % error_message; return FAIL_COPY_FILE; } ec.clear(); diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index c55d867649..59dbd936b6 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -56,6 +56,8 @@ set(SLIC3R_GUI_SOURCES GUI/Widgets/TempInput.hpp GUI/Widgets/AMSControl.cpp GUI/Widgets/AMSControl.hpp + GUI/Widgets/FanControl.cpp + GUI/Widgets/FanControl.hpp GUI/Widgets/Scrollbar.cpp GUI/Widgets/Scrollbar.hpp GUI/Widgets/ScrolledWindow.cpp @@ -169,6 +171,8 @@ set(SLIC3R_GUI_SOURCES GUI/MainFrame.hpp GUI/BBLTopbar.cpp GUI/BBLTopbar.hpp + GUI/BedShapeDialog.cpp + GUI/BedShapeDialog.hpp GUI/Plater.cpp GUI/Plater.hpp GUI/PartPlate.cpp @@ -247,8 +251,6 @@ set(SLIC3R_GUI_SOURCES GUI/ConfigManipulation.hpp GUI/Field.cpp GUI/Field.hpp - GUI/ConfirmHintDialog.cpp - GUI/ConfirmHintDialog.hpp GUI/OptionsGroup.cpp GUI/OptionsGroup.hpp GUI/OG_CustomCtrl.cpp @@ -269,6 +271,8 @@ set(SLIC3R_GUI_SOURCES GUI/RemovableDriveManager.hpp GUI/SendSystemInfoDialog.cpp GUI/SendSystemInfoDialog.hpp + GUI/SetBedTypeDialog.cpp + GUI/SetBedTypeDialog.hpp GUI/ImGuiWrapper.hpp GUI/ImGuiWrapper.cpp GUI/DeviceManager.hpp @@ -362,6 +366,8 @@ set(SLIC3R_GUI_SOURCES GUI/BonjourDialog.hpp GUI/BindDialog.cpp GUI/BindDialog.hpp + GUI/ModelMall.hpp + GUI/ModelMall.cpp GUI/SelectMachine.hpp GUI/SelectMachine.cpp GUI/SendToPrinter.hpp @@ -427,6 +433,16 @@ set(SLIC3R_GUI_SOURCES Utils/Repetier.hpp ) +if (WIN32) + list(APPEND SLIC3R_GUI_SOURCES + GUI/dark_mode/dark_mode.hpp + GUI/dark_mode/IatHook.hpp + GUI/dark_mode/UAHMenuBar.hpp + GUI/dark_mode.hpp + GUI/dark_mode.cpp + ) +endif () + if (APPLE) list(APPEND SLIC3R_GUI_SOURCES Utils/RetinaHelperImpl.mm diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 31f34e263b..1ef1e0f1ff 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -22,6 +22,7 @@ static const float GROUND_Z = -0.04f; static const std::array DEFAULT_MODEL_COLOR = { 0.3255f, 0.337f, 0.337f, 1.0f }; +static const std::array DEFAULT_MODEL_COLOR_DARK = { 0.255f, 0.255f, 0.283f, 1.0f }; static const std::array PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f }; namespace Slic3r { @@ -251,7 +252,7 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig m_extended_bounding_box = this->calc_extended_bounding_box(false); //BBS: add part plate logic - + //BBS add default bed #if 1 ExPolygon poly{ Polygon::new_scale(printable_area) }; @@ -264,10 +265,11 @@ bool Bed3D::set_shape(const Pointfs& printable_area, const double printable_heig calc_triangles(poly); - const BoundingBox& bed_bbox = poly.contour.bounding_box(); - calc_gridlines(poly, bed_bbox); + //no need gridline for 3dbed + //const BoundingBox& bed_bbox = poly.contour.bounding_box(); + //calc_gridlines(poly, bed_bbox); - m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0]; + //m_polygon = offset(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0]; if (with_reset) { this->release_VBOs(); @@ -313,6 +315,11 @@ Point Bed3D::point_projection(const Point& point) const return m_polygon.point_projection(point); }*/ +void Bed3D::on_change_color_mode(bool is_dark) +{ + m_is_dark = is_dark; +} + void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes) { render_internal(canvas, bottom, scale_factor, show_axes); @@ -334,7 +341,7 @@ void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, glsafe(::glEnable(GL_DEPTH_TEST)); - m_model.set_color(-1, DEFAULT_MODEL_COLOR); + m_model.set_color(-1, m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); switch (m_type) { @@ -385,7 +392,7 @@ void Bed3D::calc_triangles(const ExPolygon& poly) void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) { - Polylines axes_lines; + /*Polylines axes_lines; for (coord_t x = bed_bbox.min.x(); x <= bed_bbox.max.x(); x += scale_(10.0)) { Polyline line; line.append(Point(x, bed_bbox.min.y())); @@ -407,7 +414,7 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) - BOOST_LOG_TRIVIAL(error) << "Unable to create bed grid lines\n"; + BOOST_LOG_TRIVIAL(error) << "Unable to create bed grid lines\n";*/ } // Try to match the print bed shape with the shape of an active profile. If such a match exists, @@ -651,7 +658,7 @@ void Bed3D::render_model() const GLModel* model = const_cast(&m_model); if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) { - model->set_color(-1, DEFAULT_MODEL_COLOR); + model->set_color(-1, m_is_dark ? DEFAULT_MODEL_COLOR_DARK : DEFAULT_MODEL_COLOR); update_model_offset(); } @@ -710,7 +717,7 @@ void Bed3D::render_default(bool bottom) const glsafe(::glDepthMask(GL_TRUE)); } - if (!picking) { + /*if (!picking) { // draw grid glsafe(::glLineWidth(1.5f * m_scale_factor)); if (has_model && !bottom) @@ -719,7 +726,7 @@ void Bed3D::render_default(bool bottom) const glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.6f)); glsafe(::glVertexPointer(3, GL_FLOAT, default_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data())); glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count())); - } + }*/ glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 984c4f7de8..af3f22591f 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -90,9 +90,9 @@ private: // Print volume bounding box exteded with axes and model. BoundingBoxf3 m_extended_bounding_box; // Slightly expanded print bed polygon, for collision detection. - Polygon m_polygon; + //Polygon m_polygon; GeometryBuffer m_triangles; - GeometryBuffer m_gridlines; + //GeometryBuffer m_gridlines; GLTexture m_texture; // temporary texture shown until the main texture has still no levels compressed //GLTexture m_temp_texture; @@ -105,6 +105,7 @@ private: //BBS: add part plate related logic Vec2d m_position{ Vec2d::Zero() }; std::vector m_bed_shape; + bool m_is_dark = false; public: Bed3D() = default; @@ -141,6 +142,8 @@ public: void render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes); //void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor); + void on_change_color_mode(bool is_dark); + private: //BBS: add partplate related logic // Calculate an extended bounding box from axes and current model for visualization purposes. diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index a6ea563e11..e8786bf86f 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -869,10 +869,6 @@ void GLVolume::render(bool with_outline) const std::array body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red shader->set_uniform("uniform_color", body_color); - //if (GUI::wxGetApp().plater()->is_show_wireframe()) - // shader->set_uniform("show_wireframe", true); - //else - // shader->set_uniform("show_wireframe", false); shader->set_uniform("is_outline", true); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); @@ -1054,7 +1050,8 @@ int GLVolumeCollection::load_object_volume( int volume_idx, int instance_idx, const std::string &color_by, - bool opengl_initialized) + bool opengl_initialized, + bool in_assemble_view) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; const int extruder_id = model_volume->extruder_id(); @@ -1082,7 +1079,12 @@ int GLVolumeCollection::load_object_volume( } v.is_modifier = !model_volume->is_model_part(); v.shader_outside_printer_detection_enabled = model_volume->is_model_part(); - v.set_instance_transformation(instance->get_transformation()); + if (in_assemble_view) { + v.set_instance_transformation(instance->get_assemble_transformation()); + v.set_offset_to_assembly(instance->get_offset_to_assembly()); + } + else + v.set_instance_transformation(instance->get_transformation()); v.set_volume_transformation(model_volume->get_transformation()); return int(this->volumes.size() - 1); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index b1ad7671de..23ef575cb5 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -632,7 +632,8 @@ public: int volume_idx, int instance_idx, const std::string &color_by, - bool opengl_initialized); + bool opengl_initialized, + bool in_assemble_view = false); // Load SLA auxiliary GLVolumes (for support trees or pad). void load_object_auxiliary( diff --git a/src/slic3r/GUI/AMSMaterialsSetting.cpp b/src/slic3r/GUI/AMSMaterialsSetting.cpp index cd91cf6711..f509a2681a 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.cpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.cpp @@ -15,17 +15,13 @@ AMSMaterialsSetting::AMSMaterialsSetting(wxWindow *parent, wxWindowID id) : DPIDialog(parent, id, _L("AMS Materials Setting"), wxDefaultPosition, wxDefaultSize, wxBORDER_NONE) { create(); + wxGetApp().UpdateDlgDarkUI(this); } void AMSMaterialsSetting::create() { SetBackgroundColour(*wxWHITE); wxBoxSizer *m_sizer_main = new wxBoxSizer(wxVERTICAL); - SetSize(wxSize(AMS_MATERIALS_SETTING_BODY_WIDTH, -1)); - SetMinSize(wxSize(AMS_MATERIALS_SETTING_BODY_WIDTH, -1)); - SetMaxSize(wxSize(AMS_MATERIALS_SETTING_BODY_WIDTH, -1)); - - wxBoxSizer *m_sizer_filament = new wxBoxSizer(wxHORIZONTAL); @@ -104,7 +100,7 @@ void AMSMaterialsSetting::create() sizer_tempinput->Add(m_input_nozzle_max, 1, wxALIGN_CENTER, 0); sizer_tempinput->Add(bitmap_min_degree, 0, wxALIGN_CENTER, 0); - sizer_tempinput->Add(FromDIP(10), 0, wxEXPAND, 0); + sizer_tempinput->Add(FromDIP(10), 0, 0, 0); sizer_tempinput->Add(m_input_nozzle_min, 1, wxALIGN_CENTER, 0); sizer_tempinput->Add(bitmap_max_degree, 0, wxALIGN_CENTER, 0); @@ -116,8 +112,8 @@ void AMSMaterialsSetting::create() m_title_min->SetForegroundColour(AMS_MATERIALS_SETTING_GREY800); m_title_min->SetFont(::Label::Body_13); sizer_temp_txt->Add(m_title_max, 1, wxALIGN_CENTER, 0); - sizer_temp_txt->Add(FromDIP(10), 0, wxEXPAND, 0); - sizer_temp_txt->Add(m_title_min, 1, wxALIGN_CENTER|wxRIGHT, FromDIP(16)); + sizer_temp_txt->Add(FromDIP(10), 0, 0, 0); + sizer_temp_txt->Add(m_title_min, 1, wxALIGN_CENTER | wxRIGHT, FromDIP(16)); sizer_other->Add(sizer_temp_txt, 0, wxALIGN_CENTER, 0); @@ -188,7 +184,13 @@ void AMSMaterialsSetting::create() m_panel_SN->Layout(); m_panel_SN->Fit(); + wxBoxSizer* m_tip_sizer = new wxBoxSizer(wxHORIZONTAL); + m_tip_readonly = new wxStaticText(this, wxID_ANY, _L("Setting AMS slot information while printing is not supported"), wxDefaultPosition, wxSize(-1, AMS_MATERIALS_SETTING_INPUT_SIZE.y)); + m_tip_readonly->Hide(); + m_tip_sizer->Add(m_tip_readonly, 0, wxALIGN_CENTER | wxRIGHT, FromDIP(20)); + wxBoxSizer *m_sizer_button = new wxBoxSizer(wxHORIZONTAL); + m_sizer_button->Add(0, 0, 1, wxEXPAND, 0); m_button_confirm = new Button(this, _L("Confirm")); @@ -196,7 +198,7 @@ void AMSMaterialsSetting::create() std::pair(wxColour(0, 174, 66), StateColor::Normal)); m_button_confirm->SetBackgroundColor(m_btn_bg_green); m_button_confirm->SetBorderColor(wxColour(0, 174, 66)); - m_button_confirm->SetTextColor(AMS_MATERIALS_SETTING_GREY200); + m_button_confirm->SetTextColor(wxColour("#FFFFFE")); m_button_confirm->SetMinSize(AMS_MATERIALS_SETTING_BUTTON_SIZE); m_button_confirm->SetCornerRadius(FromDIP(12)); m_button_confirm->Bind(wxEVT_BUTTON, &AMSMaterialsSetting::on_select_ok, this); @@ -225,6 +227,7 @@ void AMSMaterialsSetting::create() m_sizer_main->Add(warning_text, 0, wxLEFT | wxRIGHT, FromDIP(20)); m_sizer_main->Add(m_panel_SN, 0, wxLEFT, FromDIP(20)); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(24)); + m_sizer_main->Add(m_tip_sizer, 0, wxLEFT, FromDIP(20)); m_sizer_main->Add(m_sizer_button, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(20)); m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(16)); @@ -240,7 +243,7 @@ void AMSMaterialsSetting::paintEvent(wxPaintEvent &evt) { auto size = GetSize(); wxPaintDC dc(this); - dc.SetPen(wxPen(wxColour(38, 46, 48), 1, wxSOLID)); + dc.SetPen(wxPen(StateColor::darkModeColorFor(wxColour("#000000")), 1, wxSOLID)); dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH)); dc.DrawRectangle(0, 0, size.x, size.y); } @@ -294,11 +297,14 @@ void AMSMaterialsSetting::update() void AMSMaterialsSetting::enable_confirm_button(bool en) { - if (!m_is_third) return; + if (!m_is_third) { + m_tip_readonly->Hide(); + } else { m_button_confirm->Show(en); COMBOBOX_FILAMENT->Show(en); m_readonly_filament->Show(!en); + m_tip_readonly->Show(!en); } } @@ -386,9 +392,9 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi m_input_nozzle_min->GetTextCtrl()->SetValue(temp_min); m_input_nozzle_max->GetTextCtrl()->SetValue(temp_max); + update(); Layout(); Fit(); - update(); ShowModal(); return; } @@ -397,8 +403,6 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi m_panel_SN->Hide(); COMBOBOX_FILAMENT->Show(); m_readonly_filament->Hide(); - Layout(); - Fit(); int selection_idx = -1, idx = 0; @@ -468,6 +472,8 @@ void AMSMaterialsSetting::Popup(wxString filament, wxString sn, wxString temp_mi } update(); + Layout(); + Fit(); ShowModal(); } diff --git a/src/slic3r/GUI/AMSMaterialsSetting.hpp b/src/slic3r/GUI/AMSMaterialsSetting.hpp index 7324e79ece..8b950bf8e0 100644 --- a/src/slic3r/GUI/AMSMaterialsSetting.hpp +++ b/src/slic3r/GUI/AMSMaterialsSetting.hpp @@ -81,8 +81,9 @@ protected: TextInput * m_input_nozzle_min; TextInput* m_input_nozzle_max; Button * m_button_confirm; + wxStaticText* m_tip_readonly; Button * m_button_close; - Button * m_clr_picker; + Button * m_clr_picker; wxColourData * m_clrData; #ifdef __APPLE__ wxComboBox *m_comboBox_filament_mac; diff --git a/src/slic3r/GUI/AMSSetting.cpp b/src/slic3r/GUI/AMSSetting.cpp index 8048b92cb7..020f115ee8 100644 --- a/src/slic3r/GUI/AMSSetting.cpp +++ b/src/slic3r/GUI/AMSSetting.cpp @@ -1,4 +1,5 @@ #include "AMSSetting.hpp" +#include "GUI_App.hpp" #include "I18N.hpp" namespace Slic3r { namespace GUI { @@ -7,6 +8,7 @@ AMSSetting::AMSSetting(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons : DPIDialog(parent, id, wxEmptyString, pos, size, style) { create(); + wxGetApp().UpdateDlgDarkUI(this); } AMSSetting::~AMSSetting() {} @@ -14,15 +16,17 @@ void AMSSetting::create() { wxBoxSizer *m_sizer_main; m_sizer_main = new wxBoxSizer(wxVERTICAL); + SetBackgroundColour(*wxWHITE); auto m_static_ams_settings = new wxStaticText(this, wxID_ANY, _L("AMS Settings"), wxDefaultPosition, wxDefaultSize, 0); m_static_ams_settings->SetFont(::Label::Head_14); m_static_ams_settings->SetForegroundColour(AMS_SETTING_GREY800); + m_sizer_main->Add(0,0,0,wxTOP,FromDIP(10)); m_sizer_main->Add(m_static_ams_settings, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(24)); m_panel_body = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, -1), wxTAB_TRAVERSAL); - wxBoxSizer *m_sizerl_body; - m_sizerl_body = new wxBoxSizer(wxVERTICAL); + m_panel_body->SetBackgroundColour(*wxWHITE); + wxBoxSizer *m_sizerl_body = new wxBoxSizer(wxVERTICAL); // checkbox area 1 @@ -41,8 +45,7 @@ void AMSSetting::create() m_title_Insert_material_auto_read->Wrap(AMS_SETTING_BODY_WIDTH); m_sizer_Insert_material->Add(m_title_Insert_material_auto_read, 1, wxALL | wxEXPAND, 0); - m_sizerl_body->Add(m_sizer_Insert_material, 0, wxEXPAND, 0); - m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + wxBoxSizer *m_sizer_Insert_material_tip = new wxBoxSizer(wxHORIZONTAL); m_sizer_Insert_material_tip_inline = new wxBoxSizer(wxVERTICAL); @@ -84,31 +87,23 @@ void AMSSetting::create() m_sizer_Insert_material_tip_inline->Add(m_tip_Insert_material_line3, 0, wxEXPAND, 0); m_sizer_Insert_material_tip->Add(m_sizer_Insert_material_tip_inline, 1, wxALIGN_CENTER, 0); - m_sizerl_body->Add(m_sizer_Insert_material_tip, 0, wxEXPAND | wxLEFT, 18); + // checkbox area 2 - m_sizerl_body->Add(0, 0, 0, wxTOP, 15); wxBoxSizer *m_sizer_starting = new wxBoxSizer(wxHORIZONTAL); - m_checkbox_starting_auto_read = new ::CheckBox(m_panel_body); m_checkbox_starting_auto_read->Bind(wxEVT_TOGGLEBUTTON, &AMSSetting::on_starting_read, this); m_sizer_starting->Add(m_checkbox_starting_auto_read, 0, wxTOP, 1); - m_sizer_starting->Add(0, 0, 0, wxLEFT, 12); - - m_title_starting_auto_read = new wxStaticText(m_panel_body, wxID_ANY, _L("Power on update"), wxDefaultPosition, - wxDefaultSize, 0); + m_title_starting_auto_read = new wxStaticText(m_panel_body, wxID_ANY, _L("Power on update"), wxDefaultPosition,wxDefaultSize, 0); m_title_starting_auto_read->SetFont(::Label::Head_13); m_title_starting_auto_read->SetForegroundColour(AMS_SETTING_GREY800); m_title_starting_auto_read->Wrap(AMS_SETTING_BODY_WIDTH); m_sizer_starting->Add(m_title_starting_auto_read, 1, wxEXPAND, 0); - m_sizerl_body->Add(m_sizer_starting, 0, wxEXPAND|wxTOP, FromDIP(8)); - - m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + wxBoxSizer *m_sizer_starting_tip = new wxBoxSizer(wxHORIZONTAL); - m_sizer_starting_tip->Add(0, 0, 0, wxLEFT, 10); // tip line @@ -131,51 +126,98 @@ void AMSSetting::create() m_tip_starting_line2->SetSize(wxSize(AMS_SETTING_BODY_WIDTH, -1)); m_tip_starting_line2->Wrap(AMS_SETTING_BODY_WIDTH); m_sizer_starting_tip_inline->Add(m_tip_starting_line2, 0, wxEXPAND,0); - m_sizer_starting_tip->Add(m_sizer_starting_tip_inline, 1, wxALIGN_CENTER, 0); - m_sizerl_body->Add(m_sizer_starting_tip, 0, wxLEFT, 18); + // checkbox area 3 + wxBoxSizer* m_sizer_remain = new wxBoxSizer(wxHORIZONTAL); + m_checkbox_remain = new ::CheckBox(m_panel_body); + m_checkbox_remain->Bind(wxEVT_TOGGLEBUTTON, &AMSSetting::on_remain, this); + m_sizer_remain->Add(m_checkbox_remain, 0, wxTOP, 1); + m_sizer_remain->Add(0, 0, 0, wxLEFT, 12); + m_title_remain = new wxStaticText(m_panel_body, wxID_ANY, _L("Update remaining capacity"), wxDefaultPosition, wxDefaultSize, 0); + m_title_remain->SetFont(::Label::Head_13); + m_title_remain->SetForegroundColour(AMS_SETTING_GREY800); + m_title_remain->Wrap(AMS_SETTING_BODY_WIDTH); + m_sizer_remain->Add(m_title_remain, 1, wxEXPAND, 0); - m_sizerl_body->Add(0, 0, 0, wxTOP, 6); + + + wxBoxSizer* m_sizer_remain_tip = new wxBoxSizer(wxHORIZONTAL); + m_sizer_remain_tip->Add(0, 0, 0, wxLEFT, 10); + + // tip line + m_sizer_remain_inline = new wxBoxSizer(wxVERTICAL); + + m_tip_remain_line1 = new wxStaticText(m_panel_body, wxID_ANY, + _L("The AMS will estimate Bambu filament's remaining capacity after the filament info is updated. During printing, remaining capacity will be updated automatically."), + wxDefaultPosition, wxDefaultSize, 0); + m_tip_remain_line1->SetFont(::Label::Body_13); + m_tip_remain_line1->SetForegroundColour(AMS_SETTING_GREY700); + m_tip_remain_line1->SetSize(wxSize(AMS_SETTING_BODY_WIDTH, -1)); + m_tip_remain_line1->Wrap(AMS_SETTING_BODY_WIDTH); + m_sizer_remain_inline->Add(m_tip_remain_line1, 0, wxEXPAND, 0); + m_sizer_remain_tip->Add(m_sizer_remain_inline, 1, wxALIGN_CENTER, 0); + + // checkbox area 4 + wxBoxSizer* m_sizer_switch_filament = new wxBoxSizer(wxHORIZONTAL); + m_checkbox_switch_filament = new ::CheckBox(m_panel_body); + m_checkbox_switch_filament->Bind(wxEVT_TOGGLEBUTTON, &AMSSetting::on_switch_filament, this); + m_sizer_switch_filament->Add(m_checkbox_switch_filament, 0, wxTOP, 1); + m_sizer_switch_filament->Add(0, 0, 0, wxLEFT, 12); + m_title_switch_filament = new wxStaticText(m_panel_body, wxID_ANY, _L("AMS auto switch filament"), wxDefaultPosition, wxDefaultSize, 0); + m_title_switch_filament->SetFont(::Label::Head_13); + m_title_switch_filament->SetForegroundColour(AMS_SETTING_GREY800); + m_title_switch_filament->Wrap(AMS_SETTING_BODY_WIDTH); + m_sizer_switch_filament->Add(m_title_switch_filament, 1, wxEXPAND, 0); + + + + wxBoxSizer* m_sizer_switch_filament_tip = new wxBoxSizer(wxHORIZONTAL); + m_sizer_switch_filament_tip->Add(0, 0, 0, wxLEFT, 10); + + // tip line + m_sizer_switch_filament_inline = new wxBoxSizer(wxVERTICAL); + + m_tip_switch_filament_line1 = new wxStaticText(m_panel_body, wxID_ANY, + _L("AMS will continue to another spool with the same properties of filament automatically when current filament runs out"), + wxDefaultPosition, wxDefaultSize, 0); + m_tip_switch_filament_line1->SetFont(::Label::Body_13); + m_tip_switch_filament_line1->SetForegroundColour(AMS_SETTING_GREY700); + m_tip_switch_filament_line1->SetSize(wxSize(AMS_SETTING_BODY_WIDTH, -1)); + m_tip_switch_filament_line1->Wrap(AMS_SETTING_BODY_WIDTH); + m_sizer_switch_filament_inline->Add(m_tip_switch_filament_line1, 0, wxEXPAND, 0); + m_sizer_switch_filament_tip->Add(m_sizer_switch_filament_inline, 1, wxALIGN_CENTER, 0); + // panel img - m_panel_img = new wxPanel(m_panel_body, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + 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); - auto img = new wxStaticBitmap(m_panel_img, wxID_ANY, create_scaled_bitmap("ams_icon", nullptr, 126), wxDefaultPosition, wxDefaultSize); m_sizer_img->Add(img, 0, wxALIGN_CENTER | wxTOP, 26); - m_sizer_img->Add(0, 0, 0, wxTOP, 18); - - /* wxBoxSizer *m_sizer_ams_img_tip = new wxBoxSizer(wxVERTICAL); - m_tip_ams_img = new wxStaticText(m_panel_img, wxID_ANY, _L("Click the automatic calibration button to enter the AMS initialization setup program"), wxDefaultPosition, - wxDefaultSize, 0); - m_tip_ams_img->SetFont(::Label::Body_13); - m_tip_ams_img->SetForegroundColour(AMS_SETTING_GREY700); - m_tip_ams_img->Wrap(AMS_SETTING_BODY_WIDTH); - m_sizer_ams_img_tip->Add(m_tip_ams_img, 0, wxALIGN_CENTER, 0); - - m_button_auto_demarcate = new Button(m_panel_img, _L("Auto Calibration")); - StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), - std::pair(wxColour(0, 174, 66), StateColor::Normal)); - m_button_auto_demarcate->SetBackgroundColor(btn_bg_green); - m_button_auto_demarcate->SetBorderColor(wxColour(0, 174, 66)); - m_button_auto_demarcate->SetTextColor(AMS_SETTING_GREY200); - m_button_auto_demarcate->SetMinSize(AMS_SETTING_BUTTON_SIZE); - m_button_auto_demarcate->SetCornerRadius(12); - m_button_auto_demarcate->Bind(wxEVT_LEFT_DOWN, &AMSSetting::on_select_ok, this); - - m_sizer_img->Add(m_sizer_ams_img_tip, 1, wxALIGN_CENTER, 0); - m_sizer_img->Add(0, 0, 0, wxTOP, 12); - m_sizer_img->Add(m_button_auto_demarcate, 0, wxALIGN_CENTER, 0); - m_sizer_img->Add(0, 0, 0, wxBOTTOM, 17);*/ - m_panel_img->SetSizer(m_sizer_img); m_panel_img->Layout(); m_sizer_img->Fit(m_panel_img); - m_sizerl_body->Add(0,0,0,wxTOP, FromDIP(5)); + + + m_sizerl_body->Add(m_sizer_Insert_material, 0, wxEXPAND, 0); + m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + m_sizerl_body->Add(m_sizer_Insert_material_tip, 0, wxEXPAND | wxLEFT, 18); + m_sizerl_body->Add(0, 0, 0, wxTOP, 15); + m_sizerl_body->Add(m_sizer_starting, 0, wxEXPAND | wxTOP, FromDIP(8)); + m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + m_sizerl_body->Add(m_sizer_starting_tip, 0, wxLEFT, 18); + m_sizerl_body->Add(0, 0, 0, wxTOP, 15); + m_sizerl_body->Add(m_sizer_remain, 0, wxEXPAND | wxTOP, FromDIP(8)); + m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + m_sizerl_body->Add(m_sizer_remain_tip, 0, wxLEFT, 18); + m_sizerl_body->Add(0, 0, 0, wxTOP, 15); + m_sizerl_body->Add(m_sizer_switch_filament, 0, wxEXPAND | wxTOP, FromDIP(8)); + m_sizerl_body->Add(0, 0, 0, wxTOP, 8); + m_sizerl_body->Add(m_sizer_switch_filament_tip, 0, wxLEFT, 18); + m_sizerl_body->Add(0, 0, 0, wxTOP, 6); + m_sizerl_body->Add(0, 0, 0, wxTOP, FromDIP(5)); m_sizerl_body->Add(m_panel_img, 1, wxEXPAND | wxALL, FromDIP(5)); m_panel_body->SetSizer(m_sizerl_body); @@ -188,6 +230,7 @@ void AMSSetting::create() m_sizer_main->Fit(this); this->Centre(wxBOTH); + wxGetApp().UpdateDlgDarkUI(this); } void AMSSetting::update_insert_material_read_mode(bool selected) @@ -222,6 +265,28 @@ void AMSSetting::update_starting_read_mode(bool selected) Fit(); } +void AMSSetting::update_remain_mode(bool selected) +{ + m_checkbox_remain->SetValue(selected); +} + +void AMSSetting::update_switch_filament(bool selected) +{ + if (obj->is_function_supported(PrinterFunction::FUNC_AUTO_SWITCH_FILAMENT)) { + m_checkbox_switch_filament->Show(); + m_title_switch_filament->Show(); + m_tip_switch_filament_line1->Show(); + Layout(); + } else { + m_checkbox_switch_filament->Hide(); + m_title_switch_filament->Hide(); + m_tip_switch_filament_line1->Hide(); + Layout(); + } + m_checkbox_switch_filament->SetValue(selected); +} + + void AMSSetting::on_select_ok(wxMouseEvent &event) { if (obj) { @@ -247,8 +312,9 @@ void AMSSetting::on_insert_material_read(wxCommandEvent &event) bool start_read_opt = m_checkbox_starting_auto_read->GetValue(); bool tray_read_opt = m_checkbox_Insert_material_auto_read->GetValue(); + bool remain_opt = m_checkbox_remain->GetValue(); - obj->command_ams_user_settings(ams_id, start_read_opt, tray_read_opt); + obj->command_ams_user_settings(ams_id, start_read_opt, tray_read_opt, remain_opt); m_sizer_Insert_material_tip_inline->Layout(); Layout(); @@ -272,8 +338,9 @@ void AMSSetting::on_starting_read(wxCommandEvent &event) bool start_read_opt = m_checkbox_starting_auto_read->GetValue(); bool tray_read_opt = m_checkbox_Insert_material_auto_read->GetValue(); + bool remain_opt = m_checkbox_remain->GetValue(); - obj->command_ams_user_settings(ams_id, start_read_opt, tray_read_opt); + obj->command_ams_user_settings(ams_id, start_read_opt, tray_read_opt, remain_opt); m_sizer_starting_tip_inline->Layout(); Layout(); @@ -282,6 +349,22 @@ void AMSSetting::on_starting_read(wxCommandEvent &event) event.Skip(); } +void AMSSetting::on_remain(wxCommandEvent& event) +{ + bool start_read_opt = m_checkbox_starting_auto_read->GetValue(); + bool tray_read_opt = m_checkbox_Insert_material_auto_read->GetValue(); + bool remain_opt = m_checkbox_remain->GetValue(); + obj->command_ams_user_settings(ams_id, start_read_opt, tray_read_opt, remain_opt); + event.Skip(); +} + +void AMSSetting::on_switch_filament(wxCommandEvent& event) +{ + bool switch_filament = m_checkbox_switch_filament->GetValue(); + obj->command_ams_switch_filament(switch_filament); + event.Skip(); +} + wxString AMSSetting::append_title(wxString text) { wxString lab; @@ -303,7 +386,7 @@ wxStaticText *AMSSetting::append_text(wxString text) void AMSSetting::on_dpi_changed(const wxRect &suggested_rect) { - m_button_auto_demarcate->SetMinSize(AMS_SETTING_BUTTON_SIZE); + //m_button_auto_demarcate->SetMinSize(AMS_SETTING_BUTTON_SIZE); } }} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/AMSSetting.hpp b/src/slic3r/GUI/AMSSetting.hpp index fdb0950d5d..7958fa1a0e 100644 --- a/src/slic3r/GUI/AMSSetting.hpp +++ b/src/slic3r/GUI/AMSSetting.hpp @@ -29,9 +29,13 @@ public: void update_insert_material_read_mode(bool selected); void update_starting_read_mode(bool selected); - void on_select_ok(wxMouseEvent &event); + void update_remain_mode(bool selected); + void update_switch_filament(bool selected); + void on_select_ok(wxMouseEvent& event); void on_insert_material_read(wxCommandEvent &event); void on_starting_read(wxCommandEvent &event); + void on_remain(wxCommandEvent& event); + void on_switch_filament(wxCommandEvent& event); wxString append_title(wxString text); wxStaticText *append_text(wxString text); MachineObject *obj{nullptr}; @@ -47,16 +51,27 @@ protected: wxStaticText *m_tip_Insert_material_line1; wxStaticText *m_tip_Insert_material_line2; wxStaticText *m_tip_Insert_material_line3; + CheckBox * m_checkbox_starting_auto_read; wxStaticText *m_title_starting_auto_read; wxStaticText *m_tip_starting_line1; wxStaticText *m_tip_starting_line2; - wxPanel * m_panel_img; + + CheckBox * m_checkbox_remain; + wxStaticText *m_title_remain; + wxStaticText *m_tip_remain_line1; + + CheckBox* m_checkbox_switch_filament; + wxStaticText* m_title_switch_filament; + wxStaticText* m_tip_switch_filament_line1; + wxStaticText *m_tip_ams_img; Button * m_button_auto_demarcate; wxBoxSizer *m_sizer_Insert_material_tip_inline; wxBoxSizer *m_sizer_starting_tip_inline; + wxBoxSizer *m_sizer_remain_inline; + wxBoxSizer *m_sizer_switch_filament_inline; }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 9b03cfe15b..d771924f3b 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -47,11 +47,7 @@ CopyrightsDialog::CopyrightsDialog() wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { this->SetFont(wxGetApp().normal_font()); -#ifdef _WIN32 - wxGetApp().UpdateDarkUI(this); -#else - this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); -#endif + this->SetBackgroundColour(*wxWHITE); std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); @@ -66,6 +62,7 @@ CopyrightsDialog::CopyrightsDialog() m_html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * em_unit(), 20 * em_unit()), wxHW_SCROLLBAR_AUTO); m_html->SetMinSize(wxSize(FromDIP(870),FromDIP(520))); + m_html->SetBackgroundColour(*wxWHITE); wxFont font = get_default_font(this); const int fs = font.GetPointSize(); const int fs2 = static_cast(1.2f*fs); @@ -81,6 +78,7 @@ CopyrightsDialog::CopyrightsDialog() SetSizer(sizer); sizer->SetSizeHints(this); CenterOnParent(); + wxGetApp().UpdateDlgDarkUI(this); } void CopyrightsDialog::fill_entries() @@ -214,9 +212,7 @@ AboutDialog::AboutDialog() wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); - - wxColour bgr_clr = wxGetApp().get_window_default_clr();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - SetBackgroundColour(bgr_clr); + SetBackgroundColour(*wxWHITE); std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); @@ -244,8 +240,8 @@ AboutDialog::AboutDialog() // version { vesizer->Add(0, FromDIP(165), 1, wxEXPAND, FromDIP(5)); - - auto version_string = _L("SoftFever Version") + " " + std::string(SoftFever_VERSION); + auto version_text = GUI_App::format_display_version(); + auto version_string = _L("SoftFever Version") + " " + std::string(version_text); wxStaticText* version = new wxStaticText(this, wxID_ANY, version_string.c_str(), wxDefaultPosition, wxDefaultSize); wxFont version_font = GetFont(); #ifdef __WXMSW__ @@ -255,8 +251,8 @@ AboutDialog::AboutDialog() #endif version_font.SetPointSize(FromDIP(16)); version->SetFont(version_font); - version->SetForegroundColour(wxColour(255, 255, 255)); - version->SetBackgroundColour(wxColour(0, 174, 66)); + version->SetForegroundColour(wxColour("#FFFFFE")); + version->SetBackgroundColour(wxColour("#00AF42")); vesizer->Add(version, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, FromDIP(5)); vesizer->Add(0, 0, 1, wxEXPAND, FromDIP(5)); } @@ -278,6 +274,7 @@ AboutDialog::AboutDialog() { auto staticText = new wxStaticText( this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxSize(FromDIP(520), -1), wxALIGN_LEFT ); staticText->SetForegroundColour(wxColour(107, 107, 107)); + staticText->SetBackgroundColour(*wxWHITE); staticText->SetMinSize(wxSize(FromDIP(520), -1)); staticText->SetFont(Label::Body_12); if (is_zh) { @@ -362,6 +359,7 @@ AboutDialog::AboutDialog() ver_sizer->Add( 0, 0, 0, wxTOP, FromDIP(30)); button_portions->Bind(wxEVT_BUTTON, &AboutDialog::onCopyrightBtn, this); + wxGetApp().UpdateDlgDarkUI(this); SetSizer(main_sizer); Layout(); Fit(); @@ -389,7 +387,6 @@ void AboutDialog::on_dpi_changed(const wxRect &suggested_rect) SetMinSize(size); Fit(); - Refresh(); } @@ -413,7 +410,7 @@ void AboutDialog::onCopyrightBtn(wxEvent &) void AboutDialog::onCopyToClipboard(wxEvent&) { wxTheClipboard->Open(); - wxTheClipboard->SetData(new wxTextDataObject(_L("Version") + " " + std::string(SLIC3R_VERSION))); + wxTheClipboard->SetData(new wxTextDataObject(_L("Version") + " " + GUI_App::format_display_version())); wxTheClipboard->Close(); } diff --git a/src/slic3r/GUI/AmsMappingPopup.cpp b/src/slic3r/GUI/AmsMappingPopup.cpp index 6999ce0658..8e0448e82e 100644 --- a/src/slic3r/GUI/AmsMappingPopup.cpp +++ b/src/slic3r/GUI/AmsMappingPopup.cpp @@ -28,6 +28,10 @@ wxDEFINE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent); MaterialItem::MaterialItem(wxWindow *parent, wxColour mcolour, wxString mname) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { + m_arraw_bitmap_gray = ScalableBitmap(this, "drop_down", FromDIP(12)); + m_arraw_bitmap_white = ScalableBitmap(this, "topbar_dropdown", FromDIP(12)); + + m_material_coloul = mcolour; m_material_name = mname; m_ams_coloul = wxColour(0xEE,0xEE,0xEE); @@ -42,6 +46,7 @@ wxDEFINE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent); SetBackgroundColour(*wxWHITE); Bind(wxEVT_PAINT, &MaterialItem::paintEvent, this); + wxGetApp().UpdateDarkUI(this); } MaterialItem::~MaterialItem() {} @@ -163,6 +168,19 @@ void MaterialItem::doRender(wxDC &dc) dc.DrawRectangle(FromDIP(1), FromDIP(18), MATERIAL_ITEM_REAL_SIZE.x, FromDIP(8)); ////border +#if __APPLE__ + if (m_material_coloul == *wxWHITE || m_ams_coloul == *wxWHITE) { + dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 1, MATERIAL_ITEM_SIZE.y - 1, 5); + } + + if (m_selected) { + dc.SetPen(wxColour(0x00, 0xAE, 0x42)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(1, 1, MATERIAL_ITEM_SIZE.x - 1, MATERIAL_ITEM_SIZE.y - 1, 5); + } +#else if (m_material_coloul == *wxWHITE || m_ams_coloul == *wxWHITE) { dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); dc.SetBrush(*wxTRANSPARENT_BRUSH); @@ -174,6 +192,18 @@ void MaterialItem::doRender(wxDC &dc) dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(0, 0, MATERIAL_ITEM_SIZE.x, MATERIAL_ITEM_SIZE.y, 5); } +#endif + //arrow + + if ( (m_ams_coloul.Red() > 160 && m_ams_coloul.Green() > 160 && m_ams_coloul.Blue() > 160) && + (m_ams_coloul.Red() < 180 && m_ams_coloul.Green() < 180 && m_ams_coloul.Blue() < 180)) { + dc.DrawBitmap(m_arraw_bitmap_white.bmp(), GetSize().x - m_arraw_bitmap_white.GetBmpSize().x - FromDIP(7), GetSize().y - m_arraw_bitmap_white.GetBmpSize().y); + } + else { + dc.DrawBitmap(m_arraw_bitmap_gray.bmp(), GetSize().x - m_arraw_bitmap_gray.GetBmpSize().x - FromDIP(7), GetSize().y - m_arraw_bitmap_gray.GetBmpSize().y); + } + + } AmsMapingPopup::AmsMapingPopup(wxWindow *parent) @@ -334,14 +364,57 @@ void AmsMapingPopup::update_ams_data(std::map amsList) Fit(); } +std::vector AmsMapingPopup::parse_ams_mapping(std::map amsList) +{ + std::vector m_tray_data; + std::map::iterator ams_iter; + + for (ams_iter = amsList.begin(); ams_iter != amsList.end(); ams_iter++) { + + BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams id " << ams_iter->first.c_str(); + + auto ams_indx = atoi(ams_iter->first.c_str()); + Ams* ams_group = ams_iter->second; + std::vector tray_datas; + std::map::iterator tray_iter; + + for (tray_iter = ams_group->trayList.begin(); tray_iter != ams_group->trayList.end(); tray_iter++) { + AmsTray* tray_data = tray_iter->second; + TrayData td; + + td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str()); + + if (!tray_data->is_exists) { + td.type = EMPTY; + } + else { + if (!tray_data->is_tray_info_ready()) { + td.type = THIRD; + } + else { + td.type = NORMAL; + td.colour = AmsTray::decode_color(tray_data->color); + td.name = tray_data->get_display_filament_type(); + td.filament_type = tray_data->get_filament_type(); + } + } + + m_tray_data.push_back(td); + } + } + + return m_tray_data; +} + void AmsMapingPopup::add_ams_mapping(std::vector tray_data) { auto sizer_mapping_list = new wxBoxSizer(wxHORIZONTAL); + for (auto i = 0; i < tray_data.size(); i++) { wxBoxSizer *sizer_mapping_item = new wxBoxSizer(wxVERTICAL); // set number - auto number = new wxStaticText(this, wxID_ANY, wxString::Format("%02d",tray_data[i].id + 1), wxDefaultPosition, wxDefaultSize, 0); + auto number = new wxStaticText(this, wxID_ANY, wxGetApp().transition_tridid(tray_data[i].id), wxDefaultPosition, wxDefaultSize, 0); number->SetFont(::Label::Body_13); number->SetForegroundColour(wxColour(0X6B, 0X6B, 0X6B)); number->Wrap(-1); @@ -423,7 +496,7 @@ void AmsMapingPopup::paintEvent(wxPaintEvent &evt) #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ - SetBackgroundColour(*wxWHITE); + SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); Bind(wxEVT_PAINT, &MappingItem::paintEvent, this); } @@ -434,9 +507,11 @@ void AmsMapingPopup::paintEvent(wxPaintEvent &evt) void MappingItem::send_event(int fliament_id) { + auto number = wxGetApp().transition_tridid(m_tray_data.id); wxCommandEvent event(EVT_SET_FINISH_MAPPING); event.SetInt(m_tray_data.id); - wxString param = wxString::Format("%d|%d|%d|%02d|%d", m_coloul.Red(), m_coloul.Green(), m_coloul.Blue(), m_tray_data.id + 1, fliament_id); + + wxString param = wxString::Format("%d|%d|%d|%s|%d", m_coloul.Red(), m_coloul.Green(), m_coloul.Blue(), number, fliament_id); event.SetString(param); event.SetEventObject(this->GetParent()->GetParent()); wxPostEvent(this->GetParent()->GetParent(), event); @@ -510,7 +585,13 @@ void MappingItem::doRender(wxDC &dc) dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y,5); if (m_coloul == *wxWHITE) { dc.SetPen(wxPen(wxColour(0xAC, 0xAC, 0xAC),1)); - dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 5); +#ifdef __APPLE__ + dc.DrawRoundedRectangle(1, 1, GetSize().x - 1, GetSize().y - 1, 5); +#else + dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 5); +#endif // __APPLE__ + + } } @@ -613,4 +694,107 @@ void AmsMapingTipPopup::OnDismiss() {} bool AmsMapingTipPopup::ProcessLeftDown(wxMouseEvent &event) { return wxPopupTransientWindow::ProcessLeftDown(event); } +AmsTutorialPopup::AmsTutorialPopup(wxWindow* parent) +:wxPopupTransientWindow(parent, wxBORDER_NONE) +{ + Bind(wxEVT_PAINT, &AmsTutorialPopup::paintEvent, this); + SetBackgroundColour(*wxWHITE); + + wxBoxSizer* sizer_main; + sizer_main = new wxBoxSizer(wxVERTICAL); + + text_title = new Label(this, Label::Head_14, _L("Config which AMS slot should be used for a filament used in the print job")); + text_title->SetSize(wxSize(FromDIP(350), -1)); + text_title->Wrap(FromDIP(350)); + sizer_main->Add(text_title, 0, wxALIGN_CENTER | wxTOP, 18); + + + sizer_main->Add(0, 0, 0, wxTOP, 30); + + wxBoxSizer* sizer_top; + sizer_top = new wxBoxSizer(wxHORIZONTAL); + + img_top = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_item_examples", this, 30), wxDefaultPosition, wxSize(FromDIP(50), FromDIP(30)), 0); + sizer_top->Add(img_top, 0, wxALIGN_CENTER, 0); + + + sizer_top->Add(0, 0, 0, wxLEFT, 10); + + wxBoxSizer* sizer_top_tips = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* sizer_tip_top = new wxBoxSizer(wxHORIZONTAL); + + arrows_top = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_arrow", this, 8), wxDefaultPosition, wxSize(FromDIP(24), FromDIP(8)), 0); + sizer_tip_top->Add(arrows_top, 0, wxALIGN_CENTER, 0); + + tip_top = new wxStaticText(this, wxID_ANY, _L("Filament used in this print job"), wxDefaultPosition, wxDefaultSize, 0); + tip_top->SetForegroundColour(wxColour("#686868")); + + sizer_tip_top->Add(tip_top, 0, wxALL, 0); + + + sizer_top_tips->Add(sizer_tip_top, 0, wxEXPAND, 0); + + + sizer_top_tips->Add(0, 0, 0, wxTOP, 6); + + wxBoxSizer* sizer_tip_bottom = new wxBoxSizer(wxHORIZONTAL); + + arrows_bottom = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_arrow", this, 8), wxDefaultPosition, wxSize(FromDIP(24), FromDIP(8)), 0); + tip_bottom = new wxStaticText(this, wxID_ANY, _L("AMS slot used for this filament"), wxDefaultPosition, wxDefaultSize, 0); + tip_bottom->SetForegroundColour(wxColour("#686868")); + + + sizer_tip_bottom->Add(arrows_bottom, 0, wxALIGN_CENTER, 0); + sizer_tip_bottom->Add(tip_bottom, 0, wxALL, 0); + + + sizer_top_tips->Add(sizer_tip_bottom, 0, wxEXPAND, 0); + + + sizer_top->Add(sizer_top_tips, 0, wxALIGN_CENTER, 0); + + + + + wxBoxSizer* sizer_middle = new wxBoxSizer(wxHORIZONTAL); + + img_middle= new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_item_examples", this, 30), wxDefaultPosition, wxSize(FromDIP(50), FromDIP(30)), 0); + sizer_middle->Add(img_middle, 0, wxALIGN_CENTER, 0); + + tip_middle = new wxStaticText(this, wxID_ANY, _L("Click to select AMS slot manually"), wxDefaultPosition, wxDefaultSize, 0); + tip_middle->SetForegroundColour(wxColour("#686868")); + sizer_middle->Add(0, 0, 0,wxLEFT, 15); + sizer_middle->Add(tip_middle, 0, wxALIGN_CENTER, 0); + + + sizer_main->Add(sizer_top, 0, wxLEFT, 40); + sizer_main->Add(0, 0, 0, wxTOP, 10); + sizer_main->Add(sizer_middle, 0, wxLEFT, 40); + sizer_main->Add(0, 0, 0, wxTOP, 10); + + + img_botton = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("ams_mapping_examples", this, 87), wxDefaultPosition, wxDefaultSize, 0); + sizer_main->Add(img_botton, 0, wxLEFT | wxRIGHT, 40); + sizer_main->Add(0, 0, 0, wxTOP, 12); + + SetSizer(sizer_main); + Layout(); + Fit(); +} + +void AmsTutorialPopup::paintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawRoundedRectangle(0, 0, GetSize().x, GetSize().y, 0); +} + +void AmsTutorialPopup::OnDismiss() {} + +bool AmsTutorialPopup::ProcessLeftDown(wxMouseEvent& event) { + return wxPopupTransientWindow::ProcessLeftDown(event); +} + + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/AmsMappingPopup.hpp b/src/slic3r/GUI/AmsMappingPopup.hpp index a81883d193..b1f9ae3433 100644 --- a/src/slic3r/GUI/AmsMappingPopup.hpp +++ b/src/slic3r/GUI/AmsMappingPopup.hpp @@ -70,6 +70,9 @@ public: wxColour m_ams_coloul; wxString m_ams_name; + ScalableBitmap m_arraw_bitmap_gray; + ScalableBitmap m_arraw_bitmap_white; + bool m_selected {false}; bool m_warning{false}; @@ -134,7 +137,8 @@ public: void on_left_down(wxMouseEvent &evt); virtual void OnDismiss() wxOVERRIDE; virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; - void paintEvent(wxPaintEvent &evt); + void paintEvent(wxPaintEvent &evt); + std::vector parse_ams_mapping(std::map amsList); }; class AmsMapingTipPopup : public wxPopupTransientWindow @@ -157,6 +161,27 @@ public: wxStaticText * m_tip_disable_ams; }; +class AmsTutorialPopup : public wxPopupTransientWindow +{ +public: + Label* text_title; + wxStaticBitmap* img_top; + wxStaticBitmap* arrows_top; + wxStaticText* tip_top; + wxStaticBitmap* arrows_bottom; + wxStaticText* tip_bottom; + wxStaticBitmap* img_middle; + wxStaticText* tip_middle; + wxStaticBitmap* img_botton; + + AmsTutorialPopup(wxWindow* parent); + ~AmsTutorialPopup() {}; + + void paintEvent(wxPaintEvent& evt); + virtual void OnDismiss() wxOVERRIDE; + virtual bool ProcessLeftDown(wxMouseEvent& event) wxOVERRIDE; +}; + wxDECLARE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent); diff --git a/src/slic3r/GUI/Auxiliary.cpp b/src/slic3r/GUI/Auxiliary.cpp index 6b2bca8079..e3d9f5560d 100644 --- a/src/slic3r/GUI/Auxiliary.cpp +++ b/src/slic3r/GUI/Auxiliary.cpp @@ -52,7 +52,7 @@ AuFile::AuFile(wxWindow *parent, fs::path file_path, wxString file_name, Auxilia wxSize panel_size = m_type == MODEL_PICTURE ? AUFILE_PICTURES_PANEL_SIZE : AUFILE_PANEL_SIZE; wxPanel::Create(parent, id, pos, panel_size, style); - SetBackgroundColour(AUFILE_GREY300); + SetBackgroundColour(StateColor::darkModeColorFor(AUFILE_GREY300)); wxBoxSizer *sizer_body = new wxBoxSizer(wxVERTICAL); SetSize(panel_size); @@ -96,26 +96,38 @@ AuFile::AuFile(wxWindow *parent, fs::path file_path, wxString file_name, Auxilia cover_text_right = _L("Rename"); cover_text_cover = _L("Cover"); - m_file_cover = ScalableBitmap(this, "auxiliary_cover", 50); - m_file_edit_mask = ScalableBitmap(this, "auxiliary_edit_mask", 43); - m_file_delete = ScalableBitmap(this, "auxiliary_delete", 28); + m_file_cover = ScalableBitmap(this, "auxiliary_cover", 40); + m_file_edit_mask = ScalableBitmap(this, "auxiliary_edit_mask", 30); + m_file_delete = ScalableBitmap(this, "auxiliary_delete", 20); + auto m_text_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(panel_size.x, AUFILE_TEXT_HEIGHT), wxTAB_TRAVERSAL); - m_text_panel->SetBackgroundColour(AUFILE_GREY300); + m_text_panel->SetBackgroundColour(StateColor::darkModeColorFor(AUFILE_GREY300)); + - wxBoxSizer *m_text_sizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *m_text_sizer = new wxBoxSizer(wxHORIZONTAL); m_text_name = new wxStaticText(m_text_panel, wxID_ANY, m_file_name, wxDefaultPosition, wxSize(panel_size.x, -1), wxST_ELLIPSIZE_END); m_text_name->Wrap(panel_size.x - FromDIP(10)); m_text_name->SetFont(::Label::Body_14); + m_text_name->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK)); - m_input_name = new ::TextInput(m_text_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(panel_size.x, FromDIP(35)), wxTE_PROCESS_ENTER); + m_input_name = new ::TextInput(m_text_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxSize(panel_size.x - FromDIP(28), FromDIP(32)), wxTE_PROCESS_ENTER); m_input_name->GetTextCtrl()->SetFont(::Label::Body_13); m_input_name->SetFont(::Label::Body_14); m_input_name->Hide(); + m_file_exit_rename = new wxStaticBitmap(m_text_panel, wxID_ANY, create_scaled_bitmap("auxiliary_delete", this, 20), wxDefaultPosition, wxSize(FromDIP(20), FromDIP(20)), 0); + + m_file_exit_rename->Bind(wxEVT_LEFT_UP, [this](auto& e) { + exit_rename_mode(); + }); + m_text_sizer->Add(0, 0, 1, wxEXPAND, 0); - m_text_sizer->Add(m_text_name, 0, 0, 0); - m_text_sizer->Add(m_input_name, 0, 0, 0); + m_text_sizer->Add(m_text_name, 0, wxALIGN_CENTER, 0); + m_text_sizer->Add(m_input_name, 0, wxALIGN_CENTER, 0); + m_text_sizer->Add( 0, 0, 1, wxEXPAND, 0 ); + m_text_sizer->Add(m_file_exit_rename, 0, wxALIGN_CENTER, 0); + m_file_exit_rename->Hide(); m_text_panel->SetSizer(m_text_sizer); m_text_panel->Layout(); @@ -138,6 +150,7 @@ AuFile::AuFile(wxWindow *parent, fs::path file_path, wxString file_name, Auxilia void AuFile::enter_rename_mode() { m_input_name->Show(); + m_file_exit_rename->Show(); m_text_name->Hide(); auto name = m_file_name.SubString(0, (m_file_name.Find(".") - 1)); m_input_name->GetTextCtrl()->SetLabelText(name); @@ -147,6 +160,7 @@ void AuFile::enter_rename_mode() void AuFile::exit_rename_mode() { m_input_name->Hide(); + m_file_exit_rename->Hide(); m_text_name->Show(); Layout(); } @@ -193,7 +207,7 @@ void AuFile::PaintBackground(wxDC &dc) { auto pen_width = FromDIP(2); dc.SetPen(wxPen(AUFILE_GREY500, pen_width)); - dc.SetBrush(AUFILE_GREY200); + dc.SetBrush(StateColor::darkModeColorFor(AUFILE_GREY200)); dc.DrawRoundedRectangle(pen_width / 2, pen_width / 2, size.x - pen_width / 2, size.y - pen_width / 2, AUFILE_ROUNDING); auto line_length = FromDIP(50); @@ -226,7 +240,7 @@ void AuFile::PaintForeground(wxDC &dc) if (m_type == AddFileButton) { auto pen_width = FromDIP(2); dc.SetPen(wxPen(AUFILE_BRAND, pen_width)); - dc.SetBrush(AUFILE_BRAND_TRANSPARENT); + dc.SetBrush(StateColor::darkModeColorFor(AUFILE_BRAND_TRANSPARENT)); dc.DrawRoundedRectangle(pen_width / 2, pen_width / 2, size.x - pen_width / 2, size.y - pen_width / 2, AUFILE_ROUNDING); auto line_length = FromDIP(50); @@ -247,7 +261,7 @@ void AuFile::PaintForeground(wxDC &dc) } - dc.SetFont(Label::Body_14); + dc.SetFont(Label::Body_12); dc.SetTextForeground(*wxWHITE); if (m_type == MODEL_PICTURE) { // left text @@ -265,12 +279,12 @@ void AuFile::PaintForeground(wxDC &dc) dc.DrawText(cover_text_right, pos); // Split - dc.SetPen(AUFILE_GREY700); - dc.SetBrush(AUFILE_GREY700); + dc.SetPen(*wxWHITE); + dc.SetBrush(*wxWHITE); pos = wxPoint(0, 0); pos.x = size.x / 2 - 1; - pos.y = size.y - FromDIP(30) - (m_file_edit_mask.GetBmpSize().y - FromDIP(30)) / 2; - dc.DrawRectangle(pos.x, pos.y, 2, FromDIP(30)); + pos.y = size.y - FromDIP(24) - (m_file_edit_mask.GetBmpSize().y - FromDIP(24)) / 2; + dc.DrawRectangle(pos.x, pos.y, 2, FromDIP(24)); } else { // right text /* auto sizet = dc.GetTextExtent(cover_text_right); @@ -292,7 +306,7 @@ void AuFile::PaintForeground(wxDC &dc) dc.DrawText(cover_text_cover, pos); } - if (m_hover) { dc.DrawBitmap(m_file_delete.bmp(), size.x - m_file_delete.GetBmpSize().x - FromDIP(15), FromDIP(15)); } + if (m_hover) { dc.DrawBitmap(m_file_delete.bmp(), size.x - m_file_delete.GetBmpSize().x - FromDIP(10), FromDIP(10)); } } void AuFile::on_mouse_enter(wxMouseEvent &evt) @@ -365,12 +379,12 @@ void AuFile::on_input_enter(wxCommandEvent &evt) fs::path newPath(new_dir_path); fs::rename(oldPath, newPath); } else { - MessageDialog msg_wingow(nullptr, info_line, wxEmptyString, + /*MessageDialog msg_wingow(nullptr, info_line, "", wxICON_WARNING | wxOK); if (msg_wingow.ShowModal() == wxID_CANCEL) { m_input_name->GetTextCtrl()->SetValue(wxEmptyString); return; - } + }*/ return; } @@ -407,7 +421,7 @@ void AuFile::on_mouse_left_up(wxMouseEvent &evt) auto pos = evt.GetPosition(); // set cover - auto mask_size = m_file_edit_mask.GetBmpSize(); + auto mask_size = wxSize(GetSize().x, m_file_edit_mask.GetBmpSize().y); auto cover_left = 0; auto cover_top = size.y - mask_size.y; auto cover_right = mask_size.x / 2; @@ -429,10 +443,10 @@ void AuFile::on_mouse_left_up(wxMouseEvent &evt) if (pos.x > rename_left && pos.x < rename_right && pos.y > rename_top && pos.y < rename_bottom) { on_set_rename(); return; } // close - auto close_left = size.x - m_file_delete.GetBmpSize().x - FromDIP(15); - auto close_top = FromDIP(15); - auto close_right = size.x - FromDIP(15); - auto close_bottom = m_file_delete.GetBmpSize().y + FromDIP(15); + auto close_left = size.x - m_file_delete.GetBmpSize().x - FromDIP(10); + auto close_top = FromDIP(10); + auto close_right = size.x - FromDIP(10); + auto close_bottom = m_file_delete.GetBmpSize().y + FromDIP(10); if (pos.x > close_left && pos.x < close_right && pos.y > close_top && pos.y < close_bottom) { on_set_delete(); return; } exit_rename_mode(); @@ -442,7 +456,7 @@ void AuFile::on_set_cover() { if (wxGetApp().plater()->model().model_info == nullptr) { wxGetApp().plater()->model().model_info = std::make_shared(); } - wxGetApp().plater()->model().model_info->cover_file = std::string(m_file_name.ToUTF8().data()); + wxGetApp().plater()->model().model_info->cover_file = m_file_name.ToStdString(); auto full_path = m_file_path.branch_path(); auto full_root_path = full_path.branch_path(); @@ -528,9 +542,9 @@ AuFile::~AuFile() {} void AuFile::msw_rescale() { - m_file_cover = ScalableBitmap(this, "auxiliary_cover", 50); - m_file_edit_mask = ScalableBitmap(this, "auxiliary_edit_mask", 43); - m_file_delete = ScalableBitmap(this, "auxiliary_delete", 28); + m_file_cover = ScalableBitmap(this, "auxiliary_cover", 40); + m_file_edit_mask = ScalableBitmap(this, "auxiliary_edit_mask", FromDIP(30)); + m_file_delete = ScalableBitmap(this, "auxiliary_delete", 20); if (m_type == MODEL_PICTURE) { if (m_file_path.empty()) { return;} @@ -577,12 +591,12 @@ AuFolderPanel::AuFolderPanel(wxWindow *parent, AuxiliaryFolderType type, wxWindo std::pair(AMS_CONTROL_WHITE_COLOUR, StateColor::Normal)); StateColor btn_bd_white(std::pair(AMS_CONTROL_WHITE_COLOUR, StateColor::Disabled), std::pair(wxColour(38, 46, 48), StateColor::Enabled)); - m_button_add = new Button(m_scrolledWindow, _L("Add"), "auxiliary_add_file", 12, 12); - m_button_add->SetBackgroundColor(btn_bg_white); + //m_button_add = new AuFile(m_scrolledWindow, fs::path(), "", AddFileButton, -1); + /*m_button_add->SetBackgroundColor(btn_bg_white); m_button_add->SetBorderColor(btn_bd_white); m_button_add->SetMinSize(wxSize(-1, FromDIP(24))); m_button_add->SetCornerRadius(FromDIP(12)); - m_button_add->SetFont(Label::Body_14); + m_button_add->SetFont(Label::Body_14);*/ m_big_button_add = new AuFile(m_scrolledWindow, fs::path(), "", AddFileButton, -1); @@ -596,14 +610,14 @@ AuFolderPanel::AuFolderPanel(wxWindow *parent, AuxiliaryFolderType type, wxWindo sizer_top->Add(0, 0, 0, wxLEFT, FromDIP(10)); m_gsizer_content = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS); - if (m_type == MODEL_PICTURE) { - sizer_top->Add(m_button_add, 0, wxALL, 0); - m_big_button_add->Hide(); - } - else { + //if (m_type == MODEL_PICTURE) { + // //sizer_top->Add(m_button_add, 0, wxALL, 0); + // //m_big_button_add->Hide(); + //} + //else { m_gsizer_content->Add(m_big_button_add, 0, wxALL, FromDIP(8)); - m_button_add->Hide(); - } + //m_button_add->Hide(); + //} // sizer_top->Add(m_button_del, 0, wxALL, 0); sizer_body->Add(sizer_top, 0, wxEXPAND | wxTOP, FromDIP(35)); sizer_body->AddSpacer(FromDIP(14)); @@ -622,7 +636,7 @@ AuFolderPanel::AuFolderPanel(wxWindow *parent, AuxiliaryFolderType type, wxWindo evt.SetEventObject(m_parent); wxPostEvent(m_parent, evt); }); - m_button_add->Bind(wxEVT_BUTTON, &AuFolderPanel::on_add, this); + //m_button_add->Bind(wxEVT_LEFT_UP, &AuFolderPanel::on_add, this); } void AuFolderPanel::clear() @@ -640,8 +654,8 @@ void AuFolderPanel::update(std::vector paths) { clear(); for (auto i = 0; i < paths.size(); i++) { - std::string temp_name = fs::path(paths[i].c_str()).filename().string(); - auto name = encode_path(temp_name.c_str()); + std::string temp_name = fs::path(paths[i].c_str()).filename().string(); + auto name = encode_path(temp_name.c_str()); auto aufile = new AuFile(m_scrolledWindow, paths[i], name, m_type, wxID_ANY); m_gsizer_content->Add(aufile, 0, wxALL, FromDIP(8)); @@ -656,14 +670,14 @@ void AuFolderPanel::update(std::vector paths) void AuFolderPanel::msw_rescale() { - m_button_add->SetMinSize(wxSize(-1, FromDIP(24))); + //m_button_add->SetMinSize(wxSize(-1, FromDIP(24))); for (auto i = 0; i < m_aufiles_list.GetCount(); i++) { AuFiles *aufile = m_aufiles_list[i]; aufile->file->msw_rescale(); } } -void AuFolderPanel::on_add(wxCommandEvent& event) +void AuFolderPanel::on_add(wxMouseEvent& event) { auto evt = wxCommandEvent(EVT_AUXILIARY_IMPORT); evt.SetString(s_default_folders[m_type]); @@ -806,7 +820,7 @@ void AuxiliaryPanel::init_tabpanel() wxBoxSizer *sizer_side_tools = new wxBoxSizer(wxVERTICAL); sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0); m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); - m_tabpanel->SetBackgroundColour(*wxWHITE); + m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF")); m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent &e) { ; }); m_designer_panel = new DesignerPanel(m_tabpanel, AuxiliaryFolderType::DESIGNER); @@ -921,7 +935,8 @@ void AuxiliaryPanel::on_import_file(wxCommandEvent &event) strftime(ch1, sizeof(ch1), "%T", localtime(&t1)); std::string time_text = ch1; - auto before_name = replaceSpace(src_bfs_path.filename().string(), src_bfs_path.extension().string(), ""); + wxString name = src_bfs_path.filename().generic_wstring(); + auto before_name = replaceSpace(name.ToStdString(), src_bfs_path.extension().string(), ""); time_text = replaceSpace(time_text, ":", "_"); dir_path += "/" + before_name + "_" + time_text + src_bfs_path.extension().wstring(); } @@ -1185,7 +1200,6 @@ void DesignerPanel::on_input_enter_model(wxCommandEvent &evt) } } - void DesignerPanel::update_info() { if (wxGetApp().plater()->model().design_info != nullptr) { diff --git a/src/slic3r/GUI/Auxiliary.hpp b/src/slic3r/GUI/Auxiliary.hpp index b9ef3332dd..731c612257 100644 --- a/src/slic3r/GUI/Auxiliary.hpp +++ b/src/slic3r/GUI/Auxiliary.hpp @@ -53,8 +53,10 @@ #define AUFILE_GREY200 wxColour(248, 248, 248) #define AUFILE_BRAND wxColour(0, 174, 66) #define AUFILE_BRAND_TRANSPARENT wxColour(215, 232, 222) -#define AUFILE_PICTURES_SIZE wxSize(FromDIP(300), FromDIP(300)) -#define AUFILE_PICTURES_PANEL_SIZE wxSize(FromDIP(300), FromDIP(340)) +//#define AUFILE_PICTURES_SIZE wxSize(FromDIP(300), FromDIP(300)) +//#define AUFILE_PICTURES_PANEL_SIZE wxSize(FromDIP(300), FromDIP(340)) +#define AUFILE_PICTURES_SIZE wxSize(FromDIP(168), FromDIP(168)) +#define AUFILE_PICTURES_PANEL_SIZE wxSize(FromDIP(168), FromDIP(208)) #define AUFILE_SIZE wxSize(FromDIP(168), FromDIP(168)) #define AUFILE_PANEL_SIZE wxSize(FromDIP(168), FromDIP(208)) #define AUFILE_TEXT_HEIGHT FromDIP(40) @@ -95,6 +97,7 @@ public: ScalableBitmap m_file_cover; ScalableBitmap m_file_edit_mask; ScalableBitmap m_file_delete; + wxStaticBitmap* m_file_exit_rename; ScalableBitmap m_bitmap_excel; ScalableBitmap m_bitmap_pdf; @@ -110,7 +113,7 @@ public: void PaintForeground(wxDC &dc); void on_mouse_enter(wxMouseEvent &evt); void on_mouse_leave(wxMouseEvent &evt); - void on_input_enter(wxCommandEvent &evt); + void on_input_enter(wxCommandEvent& evt); void on_dclick(wxMouseEvent &evt); void on_mouse_left_up(wxMouseEvent &evt); @@ -156,12 +159,12 @@ public: AuxiliaryFolderType m_type; wxScrolledWindow * m_scrolledWindow{nullptr}; wxWrapSizer * m_gsizer_content{nullptr}; - Button * m_button_add{nullptr}; + //AuFile * m_button_add{nullptr}; Button * m_button_del{nullptr}; AuFile * m_big_button_add{ nullptr }; AuFilesHash m_aufiles_list; - void on_add(wxCommandEvent& event); + void on_add(wxMouseEvent& event); void on_delete(wxCommandEvent &event); }; diff --git a/src/slic3r/GUI/BBLStatusBar.cpp b/src/slic3r/GUI/BBLStatusBar.cpp index e0cde171cc..9e755c356c 100644 --- a/src/slic3r/GUI/BBLStatusBar.cpp +++ b/src/slic3r/GUI/BBLStatusBar.cpp @@ -117,6 +117,11 @@ void BBLStatusBar::set_range(int val) } } +void BBLStatusBar::clear_percent() +{ + +} + void BBLStatusBar::show_progress(bool show) { if (show) { diff --git a/src/slic3r/GUI/BBLStatusBar.hpp b/src/slic3r/GUI/BBLStatusBar.hpp index 09bd20139e..ec3864193b 100644 --- a/src/slic3r/GUI/BBLStatusBar.hpp +++ b/src/slic3r/GUI/BBLStatusBar.hpp @@ -44,6 +44,7 @@ public: void set_progress(int) override; int get_range() const override; void set_range(int = 100) override; + void clear_percent() override; void show_progress(bool); void start_busy(int = 100); void stop_busy(); diff --git a/src/slic3r/GUI/BBLStatusBarBind.cpp b/src/slic3r/GUI/BBLStatusBarBind.cpp index 878cfb25ec..2117e60794 100644 --- a/src/slic3r/GUI/BBLStatusBarBind.cpp +++ b/src/slic3r/GUI/BBLStatusBarBind.cpp @@ -27,7 +27,7 @@ BBLStatusBarBind::BBLStatusBarBind(wxWindow *parent, int id) //wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL); - /* m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, 0); + /* m_status_text = new wxStaticText(m_self, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0); m_status_text->SetForegroundColour(wxColour(107, 107, 107)); m_status_text->SetFont(::Label::Body_13); m_status_text->Wrap(-1); @@ -37,7 +37,7 @@ BBLStatusBarBind::BBLStatusBarBind(wxWindow *parent, int id) m_prog->SetValue(0); - m_stext_percent = new wxStaticText(m_self, wxID_ANY, _L(""), wxDefaultPosition, wxDefaultSize, 0); + m_stext_percent = new wxStaticText(m_self, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0); m_stext_percent->SetForegroundColour(wxColour(107, 107, 107)); m_stext_percent->SetFont(::Label::Body_13); m_stext_percent->Wrap(-1); @@ -92,6 +92,11 @@ void BBLStatusBarBind::set_range(int val) } } +void BBLStatusBarBind::clear_percent() +{ + +} + void BBLStatusBarBind::show_progress(bool show) { if (show) { diff --git a/src/slic3r/GUI/BBLStatusBarBind.hpp b/src/slic3r/GUI/BBLStatusBarBind.hpp index 37755aaec1..e30fff085c 100644 --- a/src/slic3r/GUI/BBLStatusBarBind.hpp +++ b/src/slic3r/GUI/BBLStatusBarBind.hpp @@ -47,6 +47,7 @@ public: void set_progress(int) override; int get_range() const override; void set_range(int = 100) override; + void clear_percent() override; void show_progress(bool); void start_busy(int = 100); void stop_busy(); diff --git a/src/slic3r/GUI/BBLStatusBarSend.cpp b/src/slic3r/GUI/BBLStatusBarSend.cpp index 4694d11e88..16d58c9398 100644 --- a/src/slic3r/GUI/BBLStatusBarSend.cpp +++ b/src/slic3r/GUI/BBLStatusBarSend.cpp @@ -26,11 +26,11 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL); wxBoxSizer *m_sizer_bottom = new wxBoxSizer(wxHORIZONTAL); - m_status_text = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxSize(m_self->FromDIP(280), -1), 0); + m_status_text = new wxStaticText(m_self, wxID_ANY, wxEmptyString); m_status_text->SetForegroundColour(wxColour(107, 107, 107)); m_status_text->SetFont(::Label::Body_13); - m_status_text->Wrap(m_self->FromDIP(280)); - + m_status_text->SetSize(wxSize(m_self->FromDIP(280), m_self->FromDIP(46))); + m_status_text->SetMaxSize(wxSize(m_self->FromDIP(280), m_self->FromDIP(46))); m_prog = new wxGauge(m_self, wxID_ANY, 100, wxDefaultPosition, wxSize(-1, m_self->FromDIP(6)), wxGA_HORIZONTAL); m_prog->SetValue(0); @@ -42,10 +42,12 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) m_sizer_bottom->Add(m_prog, 1, wxALIGN_CENTER, 0); + StateColor btn_bd_white(std::pair(*wxWHITE, StateColor::Disabled), std::pair(wxColour(38, 46, 48), StateColor::Enabled)); + m_cancelbutton = new Button(m_self, _L("Cancel")); m_cancelbutton->SetMinSize(wxSize(m_self->FromDIP(64), m_self->FromDIP(24))); - m_cancelbutton->SetTextColor(wxColour(107, 107, 107)); m_cancelbutton->SetBackgroundColor(wxColour(255, 255, 255)); + m_cancelbutton->SetBorderColor(btn_bd_white); m_cancelbutton->SetCornerRadius(m_self->FromDIP(12)); m_cancelbutton->Bind(wxEVT_BUTTON, [this](wxCommandEvent &evt) { @@ -54,7 +56,7 @@ BBLStatusBarSend::BBLStatusBarSend(wxWindow *parent, int id) m_cancel_cb_fina(); }); - m_stext_percent = new wxStaticText(m_self, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, 0); + m_stext_percent = new wxStaticText(m_self, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, 0); m_stext_percent->SetForegroundColour(wxColour(107, 107, 107)); m_stext_percent->SetFont(::Label::Body_13); m_stext_percent->Wrap(-1); @@ -99,6 +101,7 @@ void BBLStatusBarSend::set_progress(int val) } m_prog->SetValue(val); set_percent_text(wxString::Format("%d%%", val)); + m_sizer->Layout(); } @@ -114,6 +117,11 @@ void BBLStatusBarSend::set_range(int val) } } +void BBLStatusBarSend::clear_percent() +{ + set_percent_text(wxEmptyString); +} + void BBLStatusBarSend::show_progress(bool show) { if (show) { @@ -168,15 +176,66 @@ wxPanel* BBLStatusBarSend::get_panel() return m_self; } +bool BBLStatusBarSend::is_english_text(wxString str) +{ + std::regex reg("^[0-9a-zA-Z]+$"); + std::smatch matchResult; + + std::string pattern_Special = "{}[]<>~!@#$%^&*(),.?/ :"; + for (auto i = 0; i < str.Length(); i++) { + std::string regex_str = wxString(str[i]).ToStdString(); + if (std::regex_match(regex_str, matchResult, reg)) { + continue; + } + else { + int result = pattern_Special.find(regex_str.c_str()); + if (result < 0 || result > pattern_Special.length()) { + return false; + } + } + } + return true; +} + +bool BBLStatusBarSend::format_text(wxStaticText* dc, int width, const wxString& text, wxString& multiline_text) +{ + bool multiline = false; + multiline_text = text; + if (width > 0 && dc->GetTextExtent(text).x > width) { + size_t start = 0; + while (true) { + size_t idx = size_t(-1); + for (size_t i = start; i < multiline_text.Len(); i++) { + if (multiline_text[i] == ' ') { + if (dc->GetTextExtent(multiline_text.SubString(start, i)).x < width) + idx = i; + else { + if (idx == size_t(-1)) idx = i; + break; + } + } + } + if (idx == size_t(-1)) break; + multiline = true; + multiline_text[idx] = '\n'; + start = idx + 1; + if (dc->GetTextExtent(multiline_text.Mid(start)).x < width) break; + } + } + return multiline; + //return dc->GetTextExtent(multiline_text); +} + + void BBLStatusBarSend::set_status_text(const wxString& txt) { //auto txtss = "Sending the printing task has timed out.\nPlease try again!"; //auto txtss = "The printing project is being uploaded... 25%%"; //m_status_text->SetLabelText(txtss); - m_status_text->SetLabelText(txt); - m_status_text->SetSize(wxSize(m_self->FromDIP(280), -1)); - m_status_text->SetMaxSize(wxSize(m_self->FromDIP(280), -1)); - m_status_text->Wrap(m_self->FromDIP(280)); + wxString str; + format_text(m_status_text, m_self->FromDIP(280), txt, str); + m_status_text->SetLabelText(str); + //if (is_english_text(str)) m_status_text->Wrap(m_self->FromDIP(280)); } void BBLStatusBarSend::set_percent_text(const wxString &txt) @@ -206,6 +265,7 @@ wxString BBLStatusBarSend::get_status_text() const bool BBLStatusBarSend::update_status(wxString &msg, bool &was_cancel, int percent, bool yield) { + //auto test_txt = _L("Unkown Error.") + _L("status=150, body=Timeout was reached: Connection timed out after 10009 milliseconds [Error 28]"); set_status_text(msg); if (percent >= 0) @@ -225,7 +285,6 @@ void BBLStatusBarSend::reset() set_percent_text(wxString::Format("%d%%", 0)); } - void BBLStatusBarSend::set_font(const wxFont &font) { m_self->SetFont(font); diff --git a/src/slic3r/GUI/BBLStatusBarSend.hpp b/src/slic3r/GUI/BBLStatusBarSend.hpp index e938308fcd..1abe97ee74 100644 --- a/src/slic3r/GUI/BBLStatusBarSend.hpp +++ b/src/slic3r/GUI/BBLStatusBarSend.hpp @@ -48,6 +48,7 @@ public: void set_progress(int) override; int get_range() const override; void set_range(int = 100) override; + void clear_percent() override; void show_progress(bool); void start_busy(int = 100); void stop_busy(); @@ -56,7 +57,9 @@ public: void set_cancel_callback(CancelFn = CancelFn()) override; inline void reset_cancel_callback() { set_cancel_callback(); } wxPanel * get_panel(); - void set_status_text(const wxString &txt); + bool is_english_text(wxString str); + bool format_text(wxStaticText* dc, int width, const wxString& text, wxString& multiline_text); + void set_status_text(const wxString& txt); void set_percent_text(const wxString &txt); void msw_rescale(); void set_status_text(const std::string &txt); @@ -69,7 +72,6 @@ public: bool is_slice_info_shown(); bool update_status(wxString &msg, bool &was_cancel, int percent = -1, bool yield = true); void reset(); - // Temporary methods to satisfy Perl side void show_cancel_button(); void hide_cancel_button(); diff --git a/src/slic3r/GUI/BBLTopbar.cpp b/src/slic3r/GUI/BBLTopbar.cpp index b7b02be750..9505e1d95d 100644 --- a/src/slic3r/GUI/BBLTopbar.cpp +++ b/src/slic3r/GUI/BBLTopbar.cpp @@ -250,13 +250,12 @@ void BBLTopbar::Init(wxFrame* parent) this->AddSpacer(FromDIP(10)); this->AddStretchSpacer(1); -// #if !BBL_RELEASE_TO_PUBLIC - /*wxBitmap m_publish_bitmap = create_scaled_bitmap("topbar_publish", nullptr, TOPBAR_ICON_SIZE); - m_publish_item = this->AddTool(ID_PUBLISH, "", m_publish_bitmap); - wxBitmap m_publish_disable_bitmap = create_scaled_bitmap("topbar_publish_disable", nullptr, TOPBAR_ICON_SIZE); + m_publish_bitmap = create_scaled_bitmap("topbar_publish", nullptr, TOPBAR_ICON_SIZE); + m_publish_item = this->AddTool(ID_PUBLISH, "", m_publish_bitmap); + m_publish_disable_bitmap = create_scaled_bitmap("topbar_publish_disable", nullptr, TOPBAR_ICON_SIZE); m_publish_item->SetDisabledBitmap(m_publish_disable_bitmap); - this->AddSpacer(FromDIP(12));*/ -// #endif + this->EnableTool(m_publish_item->GetId(), false); + this->AddSpacer(FromDIP(12)); /*wxBitmap model_store_bitmap = create_scaled_bitmap("topbar_store", nullptr, TOPBAR_ICON_SIZE); m_model_store_item = this->AddTool(ID_MODEL_STORE, "", model_store_bitmap); @@ -310,7 +309,7 @@ void BBLTopbar::Init(wxFrame* parent) this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnRedo, this, wxID_REDO); this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnUndo, this, wxID_UNDO); //this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnModelStoreClicked, this, ID_MODEL_STORE); - //this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnPublishClicked, this, ID_PUBLISH); + this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnPublishClicked, this, ID_PUBLISH); } BBLTopbar::~BBLTopbar() @@ -320,6 +319,12 @@ BBLTopbar::~BBLTopbar() m_file_menu = nullptr; } +void BBLTopbar::show_publish_button(bool show) +{ + this->EnableTool(m_publish_item->GetId(), show); + Refresh(); +} + void BBLTopbar::OnOpenProject(wxAuiToolBarEvent& event) { MainFrame* main_frame = dynamic_cast(m_frame); @@ -374,11 +379,21 @@ void BBLTopbar::OnModelStoreClicked(wxAuiToolBarEvent& event) void BBLTopbar::OnPublishClicked(wxAuiToolBarEvent& event) { - if (GUI::wxGetApp().plater()->model().objects.empty()) return; + if (!wxGetApp().getAgent()) { + BOOST_LOG_TRIVIAL(info) << "publish: no agent"; + return; + } - if (!wxGetApp().is_user_login()) return; + //no more check + //if (GUI::wxGetApp().plater()->model().objects.empty()) return; + if (!wxGetApp().check_login()) + return; + +#ifdef ENABLE_PUBLISHING wxGetApp().plater()->show_publish_dialog(); +#endif + wxGetApp().open_publish_page_dialog(); } void BBLTopbar::SetFileMenu(wxMenu* file_menu) @@ -539,7 +554,7 @@ void BBLTopbar::OnFileToolItem(wxAuiToolBarEvent& evt) tb->SetToolSticky(evt.GetId(), true); if (!m_skip_popup_file_menu) { - this->PopupMenu(m_file_menu, wxPoint(0, this->GetSize().GetHeight() - 2)); + this->PopupMenu(m_file_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); } else { m_skip_popup_file_menu = false; @@ -556,7 +571,7 @@ void BBLTopbar::OnDropdownToolItem(wxAuiToolBarEvent& evt) tb->SetToolSticky(evt.GetId(), true); if (!m_skip_popup_dropdown_menu) { - PopupMenu(&m_top_menu, wxPoint(0, this->GetSize().GetHeight() - 2)); + PopupMenu(&m_top_menu, wxPoint(FromDIP(1), this->GetSize().GetHeight() - 2)); } else { m_skip_popup_dropdown_menu = false; diff --git a/src/slic3r/GUI/BBLTopbar.hpp b/src/slic3r/GUI/BBLTopbar.hpp index 2bf4e4288d..c825c79132 100644 --- a/src/slic3r/GUI/BBLTopbar.hpp +++ b/src/slic3r/GUI/BBLTopbar.hpp @@ -16,6 +16,7 @@ public: BBLTopbar(wxFrame* parent); void Init(wxFrame *parent); ~BBLTopbar(); + void show_publish_button(bool show); void UpdateToolbarWidth(int width); void Rescale(); void OnIconize(wxAuiToolBarEvent& event); @@ -63,11 +64,14 @@ private: wxAuiToolBarItem* m_account_item; wxAuiToolBarItem* m_model_store_item; - //wxAuiToolBarItem *m_publish_item; + wxAuiToolBarItem *m_publish_item; wxAuiToolBarItem* m_undo_item; wxAuiToolBarItem* m_redo_item; wxAuiToolBarItem* maximize_btn; + wxBitmap m_publish_bitmap; + wxBitmap m_publish_disable_bitmap; + wxBitmap maximize_bitmap; wxBitmap window_bitmap; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 55ce786201..0541ba2c97 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -69,10 +69,10 @@ bool SlicingProcessCompletedEvent::invalidate_plater() const return false; } -std::pair SlicingProcessCompletedEvent::format_error_message() const +std::pair SlicingProcessCompletedEvent::format_error_message() const { std::string error; - bool monospace = false; + size_t monospace = 0; try { this->rethrow_exception(); } catch (const std::bad_alloc &ex) { @@ -84,7 +84,10 @@ std::pair SlicingProcessCompletedEvent::format_error_message( _u8L("Please save project and restart the program. "); } catch (PlaceholderParserError &ex) { error = ex.what(); - monospace = true; + monospace = 1; + } catch (SlicingError &ex) { + error = ex.what(); + monospace = ex.objectId(); } catch (std::exception &ex) { error = ex.what(); } catch (...) { @@ -661,7 +664,10 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn { assert(m_print != nullptr); assert(config.opt_enum("printer_technology") == m_print->technology()); - Print::ApplyStatus invalidated = m_print->apply(model, config); + // TODO: add partplate config + DynamicPrintConfig new_config = config; + new_config.apply(*m_current_plate->config()); + Print::ApplyStatus invalidated = m_print->apply(model, new_config); if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) != 0 && m_print->technology() == ptFFF && !m_fff_print->is_step_done(psGCodeExport)) { // Some FFF status was invalidated, and the G-code was not exported yet. diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index d369b010bb..c2a1cf280c 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -60,7 +60,7 @@ public: void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); } // Produce a human readable message to be displayed by a notification or a message box. // 2nd parameter defines whether the output should be displayed with a monospace font. - std::pair format_error_message() const; + std::pair format_error_message() const; private: StatusType m_status; diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index e8713a775a..624f591df7 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -140,7 +140,7 @@ void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const Co main_sizer->Add(m_panel, 1, wxEXPAND); main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10); - wxGetApp().UpdateDlgDarkUI(this, true); + wxGetApp().UpdateDlgDarkUI(this); SetSizer(main_sizer); SetMinSize(GetSize()); @@ -201,7 +201,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf Line line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { - wxButton* shape_btn = new wxButton(parent, wxID_ANY, _L("Load shape from STL...")); + Button* shape_btn = new Button(parent, _L("Load shape from STL...")); wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL); shape_sizer->Add(shape_btn, 1, wxEXPAND); @@ -270,7 +270,7 @@ void BedShapePanel::activate_options_page(ConfigOptionsGroupShp options_group) wxPanel* BedShapePanel::init_texture_panel() { wxPanel* panel = new wxPanel(this); - wxGetApp().UpdateDarkUI(panel, true); + panel->SetBackgroundColour(*wxWHITE); ConfigOptionsGroupShp optgroup = std::make_shared(panel, _L("Texture")); optgroup->label_width = 10; @@ -281,7 +281,17 @@ wxPanel* BedShapePanel::init_texture_panel() Line line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { - wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Disabled), std::pair(wxColour(206, 206, 206), StateColor::Pressed), + std::pair(wxColour(206, 206, 206), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + StateColor btn_bd_white(std::pair(*wxWHITE, StateColor::Disabled), std::pair(wxColour(38, 46, 48), StateColor::Enabled)); + + Button* load_btn = new Button(parent, _L("Load...")); + load_btn->SetBackgroundColor(btn_bg_white); + load_btn->SetBorderColor(btn_bd_white); + load_btn->SetBackgroundColour(*wxWHITE); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -290,10 +300,16 @@ wxPanel* BedShapePanel::init_texture_panel() wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL); filename_sizer->Add(filename_lbl, 1, wxEXPAND); - wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); + Button* remove_btn = new Button(parent, _L("Remove")); + remove_btn->SetBackgroundColor(btn_bg_white); + remove_btn->SetBorderColor(btn_bd_white); + remove_btn->SetBackgroundColour(*wxWHITE); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); + wxGetApp().UpdateDarkUI(load_btn); + wxGetApp().UpdateDarkUI(remove_btn); + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(filename_sizer, 1, wxEXPAND); sizer->Add(load_sizer, 1, wxEXPAND); @@ -341,7 +357,7 @@ wxPanel* BedShapePanel::init_texture_panel() wxPanel* BedShapePanel::init_model_panel() { wxPanel* panel = new wxPanel(this); - wxGetApp().UpdateDarkUI(panel, true); + panel->SetBackgroundColour(*wxWHITE); ConfigOptionsGroupShp optgroup = std::make_shared(panel, _L("Model")); optgroup->label_width = 10; @@ -349,10 +365,21 @@ wxPanel* BedShapePanel::init_model_panel() update_shape(); }; + Line line{ "", "" }; line.full_width = 1; line.widget = [this](wxWindow* parent) { - wxButton* load_btn = new wxButton(parent, wxID_ANY, _L("Load...")); + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Disabled), std::pair(wxColour(206, 206, 206), StateColor::Pressed), + std::pair(wxColour(206, 206, 206), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + StateColor btn_bd_white(std::pair(*wxWHITE, StateColor::Disabled), std::pair(wxColour(38, 46, 48), StateColor::Enabled)); + + + Button* load_btn = new Button(parent, _L("Load...")); + load_btn->SetBackgroundColor(btn_bg_white); + load_btn->SetBorderColor(btn_bd_white); + load_btn->SetBackgroundColour(*wxWHITE); wxSizer* load_sizer = new wxBoxSizer(wxHORIZONTAL); load_sizer->Add(load_btn, 1, wxEXPAND); @@ -360,10 +387,16 @@ wxPanel* BedShapePanel::init_model_panel() wxSizer* filename_sizer = new wxBoxSizer(wxHORIZONTAL); filename_sizer->Add(filename_lbl, 1, wxEXPAND); - wxButton* remove_btn = new wxButton(parent, wxID_ANY, _L("Remove")); + Button* remove_btn = new Button(parent, _L("Remove")); + remove_btn->SetBackgroundColor(btn_bg_white); + remove_btn->SetBorderColor(btn_bd_white); + remove_btn->SetBackgroundColour(*wxWHITE); wxSizer* remove_sizer = new wxBoxSizer(wxHORIZONTAL); remove_sizer->Add(remove_btn, 1, wxEXPAND); + wxGetApp().UpdateDarkUI(load_btn); + wxGetApp().UpdateDarkUI(remove_btn); + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(filename_sizer, 1, wxEXPAND); sizer->Add(load_sizer, 1, wxEXPAND); diff --git a/src/slic3r/GUI/BindDialog.cpp b/src/slic3r/GUI/BindDialog.cpp index 1b43b5dc9e..5988c4f770 100644 --- a/src/slic3r/GUI/BindDialog.cpp +++ b/src/slic3r/GUI/BindDialog.cpp @@ -37,7 +37,9 @@ namespace GUI { wxBoxSizer *m_sizere_left_h = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *m_sizere_left_v= new wxBoxSizer(wxVERTICAL); - auto m_printer_img = new wxStaticBitmap(m_panel_left, wxID_ANY, create_scaled_bitmap("printer_thumbnail", nullptr, 96), wxDefaultPosition, wxSize(FromDIP(100), FromDIP(96)), 0); + m_printer_img = new wxStaticBitmap(m_panel_left, wxID_ANY, create_scaled_bitmap("printer_thumbnail", nullptr, FromDIP(100)), wxDefaultPosition, wxSize(FromDIP(120), FromDIP(120)), 0); + m_printer_img->SetBackgroundColour(BIND_DIALOG_GREY200); + m_printer_img->Hide(); m_printer_name = new wxStaticText(m_panel_left, wxID_ANY, wxEmptyString); m_printer_name->SetBackgroundColour(BIND_DIALOG_GREY200); m_printer_name->SetFont(::Label::Head_14); @@ -133,7 +135,7 @@ namespace GUI { std::pair(wxColour(0, 174, 66), StateColor::Normal)); m_button_bind->SetBackgroundColor(btn_bg_green); m_button_bind->SetBorderColor(wxColour(0, 174, 66)); - m_button_bind->SetTextColor(*wxWHITE); + m_button_bind->SetTextColor(wxColour("#FFFFFE")); m_button_bind->SetSize(BIND_DIALOG_BUTTON_SIZE); m_button_bind->SetMinSize(BIND_DIALOG_BUTTON_SIZE); m_button_bind->SetCornerRadius(FromDIP(12)); @@ -182,6 +184,8 @@ namespace GUI { this->Connect(EVT_BIND_MACHINE_SUCCESS, wxCommandEventHandler(BindMachineDialog::on_bind_success), NULL, this); this->Connect(EVT_BIND_UPDATE_MESSAGE, wxCommandEventHandler(BindMachineDialog::on_update_message), NULL, this); m_simplebook->SetSelection(1); + + wxGetApp().UpdateDlgDarkUI(this); } BindMachineDialog::~BindMachineDialog() @@ -271,9 +275,18 @@ void BindMachineDialog::on_dpi_changed(const wxRect &suggested_rect) void BindMachineDialog::on_show(wxShowEvent &event) { - //m_printer_name->SetLabelText(m_machine_info->get_printer_type_string()); - m_printer_name->SetLabelText(from_u8(m_machine_info->dev_name)); - Layout(); + if (event.IsShown()) { + auto img = m_machine_info->get_printer_thumbnail_img_str(); + if (wxGetApp().dark_mode()) { img += "_dark"; } + auto bitmap = create_scaled_bitmap(img, this, FromDIP(100)); + m_printer_img->SetBitmap(bitmap); + m_printer_img->Refresh(); + m_printer_img->Show(); + + m_printer_name->SetLabelText(from_u8(m_machine_info->dev_name)); + Layout(); + event.Skip(); + } } @@ -299,8 +312,9 @@ UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/) wxBoxSizer *m_sizere_left_h = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *m_sizere_left_v= new wxBoxSizer(wxVERTICAL); - auto m_printer_img = new wxStaticBitmap(m_panel_left, wxID_ANY, create_scaled_bitmap("printer_thumbnail", nullptr, 96), wxDefaultPosition, wxSize(FromDIP(100), FromDIP(96)), - 0); + m_printer_img = new wxStaticBitmap(m_panel_left, wxID_ANY, create_scaled_bitmap("printer_thumbnail", nullptr, FromDIP(100)), wxDefaultPosition, wxSize(FromDIP(120), FromDIP(120)), 0); + m_printer_img->SetBackgroundColour(BIND_DIALOG_GREY200); + m_printer_img->Hide(); m_printer_name = new wxStaticText(m_panel_left, wxID_ANY, wxEmptyString); m_printer_name->SetFont(::Label::Head_14); m_printer_name->SetBackgroundColour(BIND_DIALOG_GREY200); @@ -392,7 +406,7 @@ UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/) std::pair(wxColour(0, 174, 66), StateColor::Normal)); m_button_unbind->SetBackgroundColor(btn_bg_green); m_button_unbind->SetBorderColor(wxColour(0, 174, 66)); - m_button_unbind->SetTextColor(*wxWHITE); + m_button_unbind->SetTextColor(wxColour("#FFFFFE")); m_button_unbind->SetSize(BIND_DIALOG_BUTTON_SIZE); m_button_unbind->SetMinSize(BIND_DIALOG_BUTTON_SIZE); m_button_unbind->SetCornerRadius(FromDIP(12)); @@ -426,6 +440,7 @@ UnBindMachineDialog::UnBindMachineDialog(Plater *plater /*= nullptr*/) Bind(wxEVT_SHOW, &UnBindMachineDialog::on_show, this); 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); + wxGetApp().UpdateDlgDarkUI(this); } UnBindMachineDialog::~UnBindMachineDialog() @@ -484,9 +499,18 @@ void UnBindMachineDialog::on_unbind_printer(wxCommandEvent &event) void UnBindMachineDialog::on_show(wxShowEvent &event) { - //m_printer_name->SetLabelText(m_machine_info->get_printer_type_string()); - m_printer_name->SetLabelText(from_u8(m_machine_info->dev_name)); - Layout(); + if (event.IsShown()) { + auto img = m_machine_info->get_printer_thumbnail_img_str(); + if (wxGetApp().dark_mode()) { img += "_dark"; } + auto bitmap = create_scaled_bitmap(img, this, FromDIP(100)); + m_printer_img->SetBitmap(bitmap); + m_printer_img->Refresh(); + m_printer_img->Show(); + + m_printer_name->SetLabelText(from_u8(m_machine_info->dev_name)); + Layout(); + event.Skip(); + } } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/BindDialog.hpp b/src/slic3r/GUI/BindDialog.hpp index f7ed5debf3..6df81124f3 100644 --- a/src/slic3r/GUI/BindDialog.hpp +++ b/src/slic3r/GUI/BindDialog.hpp @@ -55,6 +55,7 @@ private: Button * m_button_cancel; wxSimplebook *m_simplebook; wxStaticBitmap *m_avatar; + wxStaticBitmap *m_printer_img; wxWebRequest web_request; MachineObject * m_machine_info{nullptr}; @@ -86,6 +87,7 @@ protected: Button * m_button_cancel; MachineObject *m_machine_info{nullptr}; wxStaticBitmap *m_avatar; + wxStaticBitmap *m_printer_img; public: UnBindMachineDialog(Plater *plater = nullptr); diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index ac68a5cf67..06b0a2f161 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -316,18 +316,34 @@ 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; - if (dark_mode) - replaces["\"#808080\""] = "\"#FFFFFF\""; - if (!new_color.empty()) - replaces["\"#ED6B21\""] = "\"" + new_color + "\""; + if (dark_mode) { + replaces["\"#262E30\""] = "\"#EFEFF0\""; + replaces["\"#323A3D\""] = "\"#B3B3B5\""; + replaces["\"#808080\""] = "\"#818183\""; + //replaces["\"#ACACAC\""] = "\"#54545A\""; + replaces["\"#CECECE\""] = "\"#54545B\""; + replaces["\"#6B6B6B\""] = "\"#818182\""; + replaces["\"#909090\""] = "\"#FFFFFF\""; + replaces["\"#00FF00\""] = "\"#FF0000\""; + } + //if (!new_color.empty()) + // replaces["\"#ED6B21\""] = "\"" + new_color + "\""; + + NSVGimage *image = nullptr; + if (strstr(bitmap_name.c_str(), "printer_thumbnail") == NULL) { + image = nsvgParseFromFileWithReplace(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f, replaces); + } + else { + std::map temp_replaces; + image = nsvgParseFromFileWithReplace(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f, temp_replaces); + } - NSVGimage *image = nsvgParseFromFileWithReplace(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f, replaces); if (image == nullptr) return nullptr; diff --git a/src/slic3r/GUI/BitmapComboBox.cpp b/src/slic3r/GUI/BitmapComboBox.cpp index 3396c627be..36c15343d3 100644 --- a/src/slic3r/GUI/BitmapComboBox.cpp +++ b/src/slic3r/GUI/BitmapComboBox.cpp @@ -17,13 +17,13 @@ #include #include -#ifdef _WIN32 +#ifdef __WINDOWS__ #include #include #ifdef _MSW_DARK_MODE -#include +#include "dark_mode.hpp" #endif //_MSW_DARK_MODE -#endif +#endif //__WINDOWS__ #include "libslic3r/libslic3r.h" #include "libslic3r/PrintConfig.hpp" @@ -254,11 +254,11 @@ void BitmapComboBox::DrawBackground_(wxDC& dc, const wxRect& rect, int WXUNUSED( dc.SetTextForeground(flags & ODCB_PAINTING_DISABLED ? wxColour(108,108,108) : wxGetApp().get_label_clr_default()); wxColour selCol = flags & ODCB_PAINTING_DISABLED ? -#ifdef _MSW_DARK_MODE - wxRGBToColour(NppDarkMode::GetSofterBackgroundColor()) : -#else +//#ifdef _MSW_DARK_MODE + //wxRGBToColour(NppDarkMode::GetSofterBackgroundColor()) : +//#else wxGetApp().get_highlight_default_clr() : -#endif +//#endif wxGetApp().get_window_default_clr(); dc.SetPen(selCol); dc.SetBrush(selCol); diff --git a/src/slic3r/GUI/Calibration.cpp b/src/slic3r/GUI/Calibration.cpp index 6d775f66cf..708a8cf7d4 100644 --- a/src/slic3r/GUI/Calibration.cpp +++ b/src/slic3r/GUI/Calibration.cpp @@ -11,6 +11,9 @@ #include "Widgets/RoundedRectangle.hpp" #include "Widgets/StaticBox.hpp" +static wxColour FG_COLOR = wxColour(0x32, 0x3A, 0x3D); +static wxColour BG_COLOR = wxColour(0xF8, 0xF8, 0xF8); + namespace Slic3r { namespace GUI { CalibrationDialog::CalibrationDialog(Plater *plater) @@ -31,17 +34,39 @@ CalibrationDialog::CalibrationDialog(Plater *plater) body_panel->SetBackgroundColour(*wxWHITE); auto cali_left_panel = new StaticBox(body_panel, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(303), FromDIP(243))); - cali_left_panel->SetBackgroundColor(wxColour(0xF8, 0xF8, 0xF8)); - cali_left_panel->SetBorderColor(wxColour(0xF8, 0xF8, 0xF8)); + cali_left_panel->SetBackgroundColor(BG_COLOR); + cali_left_panel->SetBorderColor(BG_COLOR); wxBoxSizer *cali_left_sizer = new wxBoxSizer(wxVERTICAL); cali_left_sizer->Add(0, 0, 0, wxTOP, FromDIP(25)); + // calibration step selection + auto cali_step_select_title = new wxStaticText(cali_left_panel, wxID_ANY, _L("Calibration step selection"), wxDefaultPosition, wxDefaultSize, 0); + cali_step_select_title->SetFont(::Label::Head_14); + cali_step_select_title->Wrap(-1); + cali_step_select_title->SetForegroundColour(FG_COLOR); + cali_step_select_title->SetBackgroundColour(BG_COLOR); + cali_left_sizer->Add(cali_step_select_title, 0, wxLEFT, FromDIP(15)); + + select_xcam_cali = create_check_option(_L("Micro lidar calibration"), cali_left_panel, _L("Micro lidar calibration"), "xcam_cali"); + select_bed_leveling = create_check_option(_L("Bed leveling"), cali_left_panel, _L("Bed leveling"), "bed_leveling"); + select_vibration = create_check_option(_L("Resonance frequency identification"), cali_left_panel, _L("Resonance frequency identification"), "vibration"); + + m_checkbox_list["xcam_cali"]->SetValue(true); + m_checkbox_list["bed_leveling"]->SetValue(true); + m_checkbox_list["vibration"]->SetValue(true); + + cali_left_sizer->Add(0, FromDIP(18), 0, wxEXPAND, 0); + cali_left_sizer->Add(select_xcam_cali, 0, wxLEFT, FromDIP(15)); + cali_left_sizer->Add(select_bed_leveling, 0, wxLEFT, FromDIP(15)); + cali_left_sizer->Add(select_vibration, 0, wxLEFT, FromDIP(15)); + cali_left_sizer->Add(0, FromDIP(30), 0, wxEXPAND, 0); + auto cali_left_text_top = new wxStaticText(cali_left_panel, wxID_ANY, _L("Calibration program"), wxDefaultPosition, wxDefaultSize, 0); cali_left_text_top->SetFont(::Label::Head_14); cali_left_text_top->Wrap(-1); - cali_left_text_top->SetForegroundColour(wxColour(0x32, 0x3A, 0x3D)); - cali_left_text_top->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + cali_left_text_top->SetForegroundColour(FG_COLOR); + cali_left_text_top->SetBackgroundColour(BG_COLOR); cali_left_sizer->Add(cali_left_text_top, 0, wxLEFT, FromDIP(15)); @@ -53,7 +78,7 @@ CalibrationDialog::CalibrationDialog(Plater *plater) wxDefaultPosition, wxSize(FromDIP(260), -1), 0); cali_left_text_body->Wrap(FromDIP(260)); cali_left_text_body->SetForegroundColour(wxColour(0x6B, 0x6B, 0x6B)); - cali_left_text_body->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + cali_left_text_body->SetBackgroundColour(BG_COLOR); cali_left_text_body->SetFont(::Label::Body_13); cali_left_sizer->Add(cali_left_text_body, 0, wxLEFT, FromDIP(15)); @@ -86,25 +111,25 @@ CalibrationDialog::CalibrationDialog(Plater *plater) wxBoxSizer *cali_right_sizer_v = new wxBoxSizer(wxVERTICAL); auto cali_right_panel = new StaticBox(body_panel, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(182), FromDIP(160))); - cali_right_panel->SetBackgroundColor(wxColour(0xF8, 0xF8, 0xF8)); - cali_right_panel->SetBorderColor(wxColour(0xF8, 0xF8, 0xF8)); + cali_right_panel->SetBackgroundColor(BG_COLOR); + cali_right_panel->SetBorderColor(BG_COLOR); auto cali_text_right_top = new wxStaticText(cali_right_panel, wxID_ANY, _L("Calibration Flow"), wxDefaultPosition, wxDefaultSize, 0); cali_text_right_top->Wrap(-1); cali_text_right_top->SetFont(::Label::Head_14); cali_text_right_top->SetForegroundColour(wxColour(0x00, 0xAE, 0x42)); - cali_text_right_top->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + cali_text_right_top->SetBackgroundColour(BG_COLOR); auto staticline = new ::StaticLine(cali_right_panel); staticline->SetLineColour(wxColour(0x00, 0xAE, 0x42)); auto calibration_panel = new wxPanel(cali_right_panel); - calibration_panel->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + calibration_panel->SetBackgroundColour(BG_COLOR); auto calibration_sizer = new wxBoxSizer(wxVERTICAL); calibration_panel->SetMinSize(wxSize(FromDIP(170), FromDIP(160))); calibration_panel->SetSize(wxSize(FromDIP(170), FromDIP(160))); m_calibration_flow = new StepIndicator(calibration_panel, wxID_ANY); - StateColor bg_color(std::pair(wxColour(248, 248, 248), StateColor::Normal)); + StateColor bg_color(std::pair(BG_COLOR, StateColor::Normal)); m_calibration_flow->SetBackgroundColor(bg_color); m_calibration_flow->SetFont(Label::Body_12); @@ -122,7 +147,7 @@ CalibrationDialog::CalibrationDialog(Plater *plater) m_calibration_btn = new Button(cali_right_panel, _L("Start Calibration")); m_calibration_btn->SetBackgroundColor(btn_bg_green); m_calibration_btn->SetBorderColor(btn_bd_green); - m_calibration_btn->SetTextColor(*wxWHITE); + m_calibration_btn->SetTextColor(wxColour("#FFFFFE")); m_calibration_btn->SetSize(wxSize(FromDIP(128), FromDIP(26))); m_calibration_btn->SetMinSize(wxSize(FromDIP(128), FromDIP(26))); @@ -149,15 +174,55 @@ CalibrationDialog::CalibrationDialog(Plater *plater) Fit(); m_calibration_btn->Bind(wxEVT_LEFT_DOWN, &CalibrationDialog::on_start_calibration, this); + wxGetApp().UpdateDlgDarkUI(this); } CalibrationDialog::~CalibrationDialog() {} void CalibrationDialog::on_dpi_changed(const wxRect &suggested_rect) {} +wxWindow* CalibrationDialog::create_check_option(wxString title, wxWindow* parent, wxString tooltip, std::string param) +{ + auto checkbox = new wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + checkbox->SetBackgroundColour(BG_COLOR); + + wxBoxSizer* sizer_checkbox = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* sizer_check = new wxBoxSizer(wxVERTICAL); + + auto check = new ::CheckBox(checkbox); + + 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->SetForegroundColour(wxColour(107, 107, 107)); + text->Wrap(-1); + sizer_checkbox->Add(text, 0, wxBOTTOM | wxEXPAND | wxTOP, FromDIP(5)); + + checkbox->SetSizer(sizer_checkbox); + checkbox->Layout(); + sizer_checkbox->Fit(checkbox); + + checkbox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + + text->Bind(wxEVT_LEFT_DOWN, [this, check](wxMouseEvent&) { check->SetValue(check->GetValue() ? false : true); }); + m_checkbox_list[param] = check; + return checkbox; +} + void CalibrationDialog::update_cali(MachineObject *obj) { if (!obj) return; + if (obj->is_function_supported(PrinterFunction::FUNC_AI_MONITORING)) { + select_xcam_cali->Show(); + } else { + select_xcam_cali->Hide(); + } + if (obj->is_calibration_running() || obj->is_calibration_done()) { if (obj->is_calibration_done()) { m_calibration_btn->Enable(); @@ -218,7 +283,11 @@ void CalibrationDialog::on_start_calibration(wxMouseEvent &event) Close(); } else { BOOST_LOG_TRIVIAL(info) << "on_start_calibration"; - m_obj->command_start_calibration(); + m_obj->command_start_calibration( + m_checkbox_list["vibration"]->GetValue(), + m_checkbox_list["bed_leveling"]->GetValue(), + m_checkbox_list["xcam_cali"]->GetValue() + ); } } } diff --git a/src/slic3r/GUI/Calibration.hpp b/src/slic3r/GUI/Calibration.hpp index 84ff0f2f93..db01e59555 100644 --- a/src/slic3r/GUI/Calibration.hpp +++ b/src/slic3r/GUI/Calibration.hpp @@ -30,11 +30,21 @@ #include "Widgets/Label.hpp" #include "Widgets/Button.hpp" #include "Widgets/StepCtrl.hpp" +#include "Widgets/CheckBox.hpp" namespace Slic3r { namespace GUI { class CalibrationDialog : public DPIDialog { +private: + std::map m_checkbox_list; + + wxWindow* select_xcam_cali { nullptr }; + wxWindow* select_bed_leveling { nullptr }; + wxWindow* select_vibration { nullptr }; + + wxWindow* create_check_option(wxString title, wxWindow *parent, wxString tooltip, std::string param); + public: CalibrationDialog(Plater *plater = nullptr); ~CalibrationDialog(); diff --git a/src/slic3r/GUI/CameraPopup.cpp b/src/slic3r/GUI/CameraPopup.cpp index 42dfcda629..99b18be551 100644 --- a/src/slic3r/GUI/CameraPopup.cpp +++ b/src/slic3r/GUI/CameraPopup.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "GUI_App.hpp" namespace Slic3r { namespace GUI { @@ -20,9 +21,10 @@ wxBEGIN_EVENT_TABLE(CameraPopup, wxPopupTransientWindow) EVT_KILL_FOCUS(CameraPopup::OnKillFocus ) wxEND_EVENT_TABLE() +wxDEFINE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent); +wxDEFINE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent); -static const wxFont TEXT_FONT = Label::Body_14; -static wxColour TEXT_COL = wxColour(43, 52, 54); +const wxColour TEXT_COL = wxColour(43, 52, 54); CameraPopup::CameraPopup(wxWindow *parent, MachineObject* obj) : wxPopupTransientWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), @@ -33,62 +35,106 @@ CameraPopup::CameraPopup(wxWindow *parent, MachineObject* obj) #endif m_panel = new wxScrolledWindow(this, wxID_ANY); m_panel->SetBackgroundColour(*wxWHITE); - + m_panel->SetMinSize(wxSize(FromDIP(180),-1)); m_panel->Bind(wxEVT_MOTION, &CameraPopup::OnMouse, this); - wxBoxSizer * main_sizer = new wxBoxSizer(wxHORIZONTAL); - wxFlexGridSizer* top_sizer = new wxFlexGridSizer(0, 2, 0, 0); + main_sizer = new wxBoxSizer(wxVERTICAL); + wxFlexGridSizer* top_sizer = new wxFlexGridSizer(0, 2, 0, FromDIP(50)); top_sizer->AddGrowableCol(0); top_sizer->SetFlexibleDirection(wxBOTH); top_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); - m_text_timelapse = new wxStaticText(m_panel, wxID_ANY, _L("Timelapse")); - m_text_timelapse->Wrap(-1); - m_text_timelapse->SetFont(TEXT_FONT); - m_text_timelapse->SetForegroundColour(TEXT_COL); - m_switch_timelapse = new SwitchButton(m_panel); - if (obj) - m_switch_timelapse->SetValue(obj->camera_timelapse); - m_text_recording = new wxStaticText(m_panel, wxID_ANY, _L("Monitoring Recording")); + + //recording + m_text_recording = new wxStaticText(m_panel, wxID_ANY, _L("Auto-record Monitoring")); m_text_recording->Wrap(-1); - m_text_recording->SetFont(TEXT_FONT); + m_text_recording->SetFont(Label::Head_14); m_text_recording->SetForegroundColour(TEXT_COL); m_switch_recording = new SwitchButton(m_panel); if (obj) - m_switch_recording->SetValue(obj->camera_recording); + m_switch_recording->SetValue(obj->camera_recording_when_printing); + + //vcamera + m_text_vcamera = new wxStaticText(m_panel, wxID_ANY, _L("Go Live")); + m_text_vcamera->Wrap(-1); + m_text_vcamera->SetFont(Label::Head_14); + m_text_vcamera->SetForegroundColour(TEXT_COL); + m_switch_vcamera = new SwitchButton(m_panel); + + top_sizer->Add(m_text_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(m_switch_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); + top_sizer->Add(m_text_vcamera, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(m_switch_vcamera, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); + + //resolution + m_text_resolution = new wxStaticText(m_panel, wxID_ANY, _L("Resolution")); + m_text_resolution->Wrap(-1); + m_text_resolution->SetFont(Label::Head_14); + m_text_resolution->SetForegroundColour(TEXT_COL); + top_sizer->Add(m_text_resolution, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(0, 0, wxALL, 0); + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i) + { + m_resolution_options[i] = create_item_radiobox(to_resolution_label_string(CameraResolution(i)), m_panel, wxEmptyString, FromDIP(10)); + top_sizer->Add(m_resolution_options[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); + top_sizer->Add(0, 0, wxALL, 0); + } + if (obj) + sync_resolution_setting(obj->camera_resolution); - top_sizer->Add(m_text_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); - top_sizer->Add(m_switch_timelapse, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); - top_sizer->Add(m_text_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5)); - top_sizer->Add(m_switch_recording, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5)); main_sizer->Add(top_sizer, 0, wxALL, FromDIP(10)); + + auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/virtual-camera", L"en"); + vcamera_guide_link = new wxHyperlinkCtrl(m_panel, wxID_ANY, _L("Show \"Live Video\" guide page."), + url, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE); + vcamera_guide_link->Hide(); + main_sizer->Add(vcamera_guide_link, 0, wxALL, FromDIP(15)); + m_panel->SetSizer(main_sizer); m_panel->Layout(); main_sizer->Fit(m_panel); SetClientSize(m_panel->GetSize()); - m_switch_timelapse->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(CameraPopup::on_switch_timelapse), NULL, this); m_switch_recording->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(CameraPopup::on_switch_recording), NULL, this); + m_switch_vcamera->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + wxMouseEvent evt(EVT_VCAMERA_SWITCH); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); + }); + #ifdef __APPLE__ + m_panel->Bind(wxEVT_LEFT_UP, &CameraPopup::OnLeftUp, this); + #endif //APPLE + + check_func_supported(); + wxGetApp().UpdateDarkUIWin(this); } -void CameraPopup::on_switch_timelapse(wxCommandEvent& event) +void CameraPopup::sdcard_absent_hint() { - if (!m_obj) return; - - bool value = m_switch_timelapse->GetValue(); - m_switch_timelapse->SetValue(!value); - m_obj->command_ipcam_timelapse(!value); + wxCommandEvent evt(EVT_SDCARD_ABSENT_HINT); + evt.SetEventObject(this); + GetEventHandler()->ProcessEvent(evt); } void CameraPopup::on_switch_recording(wxCommandEvent& event) { if (!m_obj) return; - + if (m_obj->sdcard_state != MachineObject::SdcardState::HAS_SDCARD_NORMAL) { + sdcard_absent_hint(); + return; + } bool value = m_switch_recording->GetValue(); m_switch_recording->SetValue(!value); m_obj->command_ipcam_record(!value); } +void CameraPopup::on_set_resolution() +{ + if (!m_obj) return; + + m_obj->command_ipcam_resolution_set(to_resolution_msg_string(curr_sel_resolution)); +} + void CameraPopup::Popup(wxWindow *WXUNUSED(focus)) { wxPoint curr_position = this->GetPosition(); @@ -98,6 +144,222 @@ void CameraPopup::Popup(wxWindow *WXUNUSED(focus)) wxPopupTransientWindow::Popup(); } +wxWindow* CameraPopup::create_item_radiobox(wxString title, wxWindow* parent, wxString tooltip, int padding_left) +{ + wxWindow *item = new wxWindow(parent, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(20))); + item->SetBackgroundColour(*wxWHITE); + + RadioBox *radiobox = new RadioBox(item); + radiobox->SetPosition(wxPoint(padding_left, (item->GetSize().GetHeight() - radiobox->GetSize().GetHeight()) / 2)); + resolution_rbtns.push_back(radiobox); + int btn_idx = resolution_rbtns.size() - 1; + radiobox->Bind(wxEVT_LEFT_DOWN, [this, btn_idx](wxMouseEvent &e) { + if (m_obj && allow_alter_resolution) { + select_curr_radiobox(btn_idx); + on_set_resolution(); + } + }); + + wxStaticText *text = new wxStaticText(item, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); + resolution_texts.push_back(text); + text->SetPosition(wxPoint(padding_left + radiobox->GetSize().GetWidth() + 10, (item->GetSize().GetHeight() - text->GetSize().GetHeight()) / 2)); + text->SetFont(Label::Body_13); + text->SetForegroundColour(0x6B6B6B); + text->Bind(wxEVT_LEFT_DOWN, [this, btn_idx](wxMouseEvent &e) { + if (m_obj && allow_alter_resolution) { + select_curr_radiobox(btn_idx); + on_set_resolution(); + } + }); + + radiobox->SetToolTip(tooltip); + text->SetToolTip(tooltip); + return item; +} + +void CameraPopup::select_curr_radiobox(int btn_idx) +{ + if (!m_obj) return; + + int len = resolution_rbtns.size(); + for (int i = 0; i < len; ++i) { + if (i == btn_idx) { + curr_sel_resolution = CameraResolution(i); + resolution_rbtns[i]->SetValue(true); + } + else { + resolution_rbtns[i]->SetValue(false); + } + } +} + +void CameraPopup::sync_resolution_setting(std::string resolution) +{ + if (resolution == "") { + reset_resolution_setting(); + return; + } + int res = 0; + for (CameraResolution i = RESOLUTION_720P; i < RESOLUTION_OPTIONS_NUM; i = CameraResolution(i+1)){ + if (resolution == to_resolution_msg_string(i)) { + res = int(i); + break; + } + } + select_curr_radiobox(res); +} + +void CameraPopup::reset_resolution_setting() +{ + int len = resolution_rbtns.size(); + for (int i = 0; i < len; ++i) { + resolution_rbtns[i]->SetValue(false); + } + curr_sel_resolution = RESOLUTION_OPTIONS_NUM; +} + +void CameraPopup::sync_vcamera_state(bool show_vcamera) +{ + is_vcamera_show = show_vcamera; + if (is_vcamera_show) { + m_switch_vcamera->SetValue(true); + vcamera_guide_link->Show(); + } + else { + m_switch_vcamera->SetValue(false); + vcamera_guide_link->Hide(); + } + + rescale(); +} + +void CameraPopup::check_func_supported() +{ + // function supported + if (m_obj->is_function_supported(PrinterFunction::FUNC_RECORDING) && m_obj->has_ipcam) { + m_text_recording->Show(); + m_switch_recording->Show(); + } else { + m_text_recording->Hide(); + m_switch_recording->Hide(); + } + + if (m_obj->is_function_supported(PrinterFunction::FUNC_VIRTUAL_CAMERA) && m_obj->has_ipcam) { + m_text_vcamera->Show(); + m_switch_vcamera->Show(); + if (is_vcamera_show) + vcamera_guide_link->Show(); + } else { + m_text_vcamera->Hide(); + m_switch_vcamera->Hide(); + vcamera_guide_link->Hide(); + } + + allow_alter_resolution = (m_obj->is_function_supported(PrinterFunction::FUNC_ALTER_RESOLUTION) && m_obj->has_ipcam); + + //resolution supported + std::vector resolution_supported = m_obj->get_resolution_supported(); + auto support_count = resolution_supported.size(); + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i){ + auto curr_res = to_resolution_msg_string(CameraResolution(i)); + std::vector ::iterator it = std::find(resolution_supported.begin(), resolution_supported.end(), curr_res); + if ((it == resolution_supported.end())||(support_count <= 1)) + m_resolution_options[i] -> Hide(); + } + //hide resolution if there is only one choice + if (support_count <= 1) { + m_text_resolution->Hide(); + } +} + +void CameraPopup::update(bool vcamera_streaming) +{ + if (!m_obj) return; + m_switch_recording->SetValue(m_obj->camera_recording_when_printing); + sync_resolution_setting(m_obj->camera_resolution); + sync_vcamera_state(vcamera_streaming); + + rescale(); +} + +wxString CameraPopup::to_resolution_label_string(CameraResolution resolution) { + switch (resolution) { + case RESOLUTION_720P: + return _L("720p"); + case RESOLUTION_1080P: + return _L("1080p"); + default: + return ""; + } + return ""; +} + +std::string CameraPopup::to_resolution_msg_string(CameraResolution resolution) { + switch (resolution) { + case RESOLUTION_720P: + return std::string("720p"); + case RESOLUTION_1080P: + return std::string("1080p"); + default: + return ""; + } + return ""; +} + +void CameraPopup::rescale() +{ + m_panel->Layout(); + main_sizer->Fit(m_panel); + SetClientSize(m_panel->GetSize()); + wxPopupTransientWindow::Update(); +} + +void CameraPopup::OnLeftUp(wxMouseEvent &event) +{ + auto mouse_pos = ClientToScreen(event.GetPosition()); + auto wxscroll_win_pos = m_panel->ClientToScreen(wxPoint(0, 0)); + + if (mouse_pos.x > wxscroll_win_pos.x && mouse_pos.y > wxscroll_win_pos.y && mouse_pos.x < (wxscroll_win_pos.x + m_panel->GetSize().x) && mouse_pos.y < (wxscroll_win_pos.y + m_panel->GetSize().y)) { + //recording + auto recording_rect = m_switch_recording->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > recording_rect.x && mouse_pos.y > recording_rect.y && mouse_pos.x < (recording_rect.x + m_switch_recording->GetSize().x) && mouse_pos.y < (recording_rect.y + m_switch_recording->GetSize().y)) { + wxMouseEvent recording_evt(wxEVT_LEFT_DOWN); + m_switch_recording->GetEventHandler()->ProcessEvent(recording_evt); + return; + } + //vcamera + auto vcamera_rect = m_switch_vcamera->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > vcamera_rect.x && mouse_pos.y > vcamera_rect.y && mouse_pos.x < (vcamera_rect.x + m_switch_vcamera->GetSize().x) && mouse_pos.y < (vcamera_rect.y + m_switch_vcamera->GetSize().y)) { + wxMouseEvent vcamera_evt(wxEVT_LEFT_DOWN); + m_switch_vcamera->GetEventHandler()->ProcessEvent(vcamera_evt); + return; + } + //resolution + for (int i = 0; i < (int)RESOLUTION_OPTIONS_NUM; ++i){ + auto resolution_rbtn = resolution_rbtns[i]; + auto rbtn_rect = resolution_rbtn->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > rbtn_rect.x && mouse_pos.y > rbtn_rect.y && mouse_pos.x < (rbtn_rect.x + resolution_rbtn->GetSize().x) && mouse_pos.y < (rbtn_rect.y + resolution_rbtn->GetSize().y)) { + wxMouseEvent resolution_evt(wxEVT_LEFT_DOWN); + resolution_rbtn->GetEventHandler()->ProcessEvent(resolution_evt); + return; + } + auto resolution_txt = resolution_texts[i]; + auto txt_rect = resolution_txt->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > txt_rect.x && mouse_pos.y > txt_rect.y && mouse_pos.x < (txt_rect.x + resolution_txt->GetSize().x) && mouse_pos.y < (txt_rect.y + resolution_txt->GetSize().y)) { + wxMouseEvent resolution_evt(wxEVT_LEFT_DOWN); + resolution_txt->GetEventHandler()->ProcessEvent(resolution_evt); + return; + } + } + //hyper link + auto h_rect = vcamera_guide_link->ClientToScreen(wxPoint(0, 0)); + if (mouse_pos.x > h_rect.x && mouse_pos.y > h_rect.y && mouse_pos.x < (h_rect.x + vcamera_guide_link->GetSize().x) && mouse_pos.y < (h_rect.y + vcamera_guide_link->GetSize().y)) { + auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/virtual-camera", L"en"); + wxLaunchDefaultBrowser(url); + } + } +} + void CameraPopup::OnDismiss() { wxPopupTransientWindow::OnDismiss(); } @@ -106,6 +368,7 @@ bool CameraPopup::ProcessLeftDown(wxMouseEvent &event) { return wxPopupTransientWindow::ProcessLeftDown(event); } + bool CameraPopup::Show(bool show) { return wxPopupTransientWindow::Show(show); @@ -131,18 +394,15 @@ void CameraPopup::OnMouse(wxMouseEvent &event) event.Skip(); } - -CameraItem::CameraItem(wxWindow *parent,std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover) +CameraItem::CameraItem(wxWindow *parent, std::string normal, std::string hover) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ - m_bitmap_on_normal = ScalableBitmap(this, on_normal, 20); - m_bitmap_off_normal = ScalableBitmap(this, off_normal, 20); - m_bitmap_on_hover = ScalableBitmap(this, on_hover, 20); - m_bitmap_off_hover = ScalableBitmap(this, off_hover, 20); + m_bitmap_normal = ScalableBitmap(this, normal, 20); + m_bitmap_hover = ScalableBitmap(this, hover, 20); SetSize(wxSize(FromDIP(20), FromDIP(20))); SetMinSize(wxSize(FromDIP(20), FromDIP(20))); @@ -154,12 +414,9 @@ CameraItem::CameraItem(wxWindow *parent,std::string off_normal, std::string on_n CameraItem::~CameraItem() {} -void CameraItem::msw_rescale() {} - -void CameraItem::set_switch(bool is_on) -{ - m_on = is_on; - Refresh(); +void CameraItem::msw_rescale() { + m_bitmap_normal.msw_rescale(); + m_bitmap_hover.msw_rescale(); } void CameraItem::on_enter_win(wxMouseEvent &evt) @@ -206,20 +463,12 @@ void CameraItem::render(wxDC &dc) void CameraItem::doRender(wxDC &dc) { - if (m_on) { - if (m_hover) { - dc.DrawBitmap(m_bitmap_on_hover.bmp(), wxPoint((GetSize().x - m_bitmap_on_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_on_hover.GetBmpSize().y) / 2)); - } else { - dc.DrawBitmap(m_bitmap_on_normal.bmp(), wxPoint((GetSize().x - m_bitmap_on_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_on_normal.GetBmpSize().y) / 2)); - } - + if (m_hover) { + dc.DrawBitmap(m_bitmap_hover.bmp(), wxPoint((GetSize().x - m_bitmap_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_hover.GetBmpSize().y) / 2)); } else { - if (m_hover) { - dc.DrawBitmap(m_bitmap_off_hover.bmp(), wxPoint((GetSize().x - m_bitmap_off_hover.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_off_hover.GetBmpSize().y) / 2)); - } else { - dc.DrawBitmap(m_bitmap_off_normal.bmp(), wxPoint((GetSize().x - m_bitmap_off_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_off_normal.GetBmpSize().y) / 2)); - } + dc.DrawBitmap(m_bitmap_normal.bmp(), wxPoint((GetSize().x - m_bitmap_normal.GetBmpSize().x) / 2, (GetSize().y - m_bitmap_normal.GetBmpSize().y) / 2)); } } + } } \ No newline at end of file diff --git a/src/slic3r/GUI/CameraPopup.hpp b/src/slic3r/GUI/CameraPopup.hpp index 6be9117791..f5a7833c9e 100644 --- a/src/slic3r/GUI/CameraPopup.hpp +++ b/src/slic3r/GUI/CameraPopup.hpp @@ -10,11 +10,16 @@ #include #include #include +#include #include "Widgets/SwitchButton.hpp" +#include "Widgets/RadioBox.hpp" namespace Slic3r { namespace GUI { +wxDECLARE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent); +wxDECLARE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent); + class CameraPopup : public wxPopupTransientWindow { public: @@ -27,22 +32,53 @@ public: virtual bool ProcessLeftDown(wxMouseEvent &event) wxOVERRIDE; virtual bool Show(bool show = true) wxOVERRIDE; + void sync_vcamera_state(bool show_vcamera); + void check_func_supported(); + void update(bool vcamera_streaming); + + enum CameraResolution + { + RESOLUTION_720P = 0, + RESOLUTION_1080P = 1, + RESOLUTION_OPTIONS_NUM = 2 + }; + + void rescale(); + protected: - void on_switch_timelapse(wxCommandEvent& event); void on_switch_recording(wxCommandEvent& event); + void on_set_resolution(); + void sdcard_absent_hint(); + + wxWindow * create_item_radiobox(wxString title, wxWindow *parent, wxString tooltip, int padding_left); + void select_curr_radiobox(int btn_idx); + void sync_resolution_setting(std::string resolution); + void reset_resolution_setting(); + wxString to_resolution_label_string(CameraResolution resolution); + std::string to_resolution_msg_string(CameraResolution resolution); private: MachineObject* m_obj { nullptr }; wxStaticText* m_text_recording; SwitchButton* m_switch_recording; - wxStaticText* m_text_timelapse; - SwitchButton* m_switch_timelapse; + wxStaticText* m_text_vcamera; + SwitchButton* m_switch_vcamera; + wxStaticText* m_text_resolution; + wxWindow* m_resolution_options[RESOLUTION_OPTIONS_NUM]; wxScrolledWindow *m_panel; + wxBoxSizer* main_sizer; + std::vector resolution_rbtns; + std::vector resolution_texts; + CameraResolution curr_sel_resolution = RESOLUTION_1080P; + wxHyperlinkCtrl* vcamera_guide_link { nullptr }; + bool is_vcamera_show = false; + bool allow_alter_resolution = false; void OnMouse(wxMouseEvent &event); void OnSize(wxSizeEvent &event); void OnSetFocus(wxFocusEvent &event); void OnKillFocus(wxFocusEvent &event); + void OnLeftUp(wxMouseEvent& event); private: wxDECLARE_ABSTRACT_CLASS(CameraPopup); @@ -53,20 +89,15 @@ private: class CameraItem : public wxPanel { public: - CameraItem(wxWindow *parent, std::string off_normal, std::string on_normal, std::string off_hover, std::string on_hover); + CameraItem(wxWindow *parent, std::string normal, std::string hover); ~CameraItem(); MachineObject *m_obj{nullptr}; - bool m_on{false}; bool m_hover{false}; - ScalableBitmap m_bitmap_on_normal; - ScalableBitmap m_bitmap_on_hover; - ScalableBitmap m_bitmap_off_normal; - ScalableBitmap m_bitmap_off_hover; + ScalableBitmap m_bitmap_normal; + ScalableBitmap m_bitmap_hover; void msw_rescale(); - void set_switch(bool is_on); - bool get_switch_status() { return m_on; }; void on_enter_win(wxMouseEvent &evt); void on_level_win(wxMouseEvent &evt); void paintEvent(wxPaintEvent &evt); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index b8bb7e940f..1d70bf9342 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -131,7 +131,8 @@ void ConfigManipulation::check_bed_temperature_difference(int bed_type, DynamicP } if (first_layer_bed_temp > vitrification || bed_temp > vitrification) { - const wxString msg_text = wxString::Format(_L("Bed temperature is higher than vitrification temperature of this filament.\nThis may cause nozzle blocked and printing failure\nPlease keep the printer open during the printing process to ensure air circulation or reduce the temperature of the hot bed")); + const wxString msg_text = wxString::Format( + _L("Bed temperature is higher than vitrification temperature of this filament.\nThis may cause nozzle blocked and printing failure\nPlease keep the printer open during the printing process to ensure air circulation or reduce the temperature of the hot bed")); MessageDialog dialog(m_msg_dlg_parent, msg_text, "", wxICON_WARNING | wxOK); is_msg_dlg_already_exist = true; dialog.ShowModal(); @@ -141,6 +142,26 @@ void ConfigManipulation::check_bed_temperature_difference(int bed_type, DynamicP } } +void ConfigManipulation::check_filament_max_volumetric_speed(DynamicPrintConfig *config) +{ + //if (is_msg_dlg_already_exist) return; + //float max_volumetric_speed = config->opt_float("filament_max_volumetric_speed"); + + float max_volumetric_speed = config->has("filament_max_volumetric_speed") ? config->opt_float("filament_max_volumetric_speed", (float) 0.5) : 0.5; + // BBS: limite the min max_volumetric_speed + if (max_volumetric_speed < 0.5) { + const wxString msg_text = _(L("Too small max volumetric speed.\nReset to 0.5")); + MessageDialog dialog(nullptr, msg_text, "", wxICON_WARNING | wxOK); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + dialog.ShowModal(); + new_conf.set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats({0.5})); + apply(config, &new_conf); + is_msg_dlg_already_exist = false; + } + +} + void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config) { // #ys_FIXME_to_delete @@ -255,6 +276,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con sparse_infill_density == 0 && ! config->opt_bool("enable_support") && config->opt_int("enforce_support_layers") == 0 && + config->opt_bool("ensure_vertical_shell_thickness") && ! config->opt_bool("detect_thin_wall"))) { wxString msg_text = _(L("Spiral mode only works when wall loops is 1, \n" @@ -275,6 +297,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con new_conf.set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); new_conf.set_key_value("enable_support", new ConfigOptionBool(false)); new_conf.set_key_value("enforce_support_layers", new ConfigOptionInt(0)); + new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(true)); new_conf.set_key_value("detect_thin_wall", new ConfigOptionBool(false)); sparse_infill_density = 0; support = false; @@ -291,6 +314,37 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con is_msg_dlg_already_exist = false; } + //BBS + if (config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne && + config->opt_bool("enable_overhang_speed")) + { + wxString msg_text = _(L("Arachne engine only works when overhang slowing down is disabled.\n" + "This may cause decline in the quality of overhang surface when print fastly\n")); + if (is_global_config) + msg_text += "\n" + _(L("Disable overhang slowing down automatically? \n" + "Yes - Enable arachne and disable overhang slowing down\n" + "No - Give up using arachne this time")); + MessageDialog dialog(m_msg_dlg_parent, msg_text, "", + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + is_msg_dlg_already_exist = true; + auto answer = dialog.ShowModal(); + bool enable_overhang_slow_down = true; + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("enable_overhang_speed", new ConfigOptionBool(false)); + enable_overhang_slow_down = false; + } + else { + new_conf.set_key_value("wall_generator", new ConfigOptionEnum(PerimeterGeneratorType::Classic)); + } + apply(config, &new_conf); + if (cb_value_change) { + if (!enable_overhang_slow_down) + cb_value_change("enable_overhang_speed", false); + } + is_msg_dlg_already_exist = false; + } + // BBS int filament_cnt = wxGetApp().preset_bundle->filament_presets.size(); #if 0 @@ -415,7 +469,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (opt != nullptr) { if (opt->getInt() > filament_cnt) { DynamicPrintConfig new_conf = *config; - new_conf.set_key_value(key, new ConfigOptionInt(filament_cnt)); + new_conf.set_key_value(key, new ConfigOptionInt(0)); apply(config, &new_conf); } } @@ -425,7 +479,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std::vector const &keys, std::map const &configs) { for (auto &k : keys) { - if (k == "adaptive_layer_height" || k == "independent_support_layer_height" || k == "enable_support" || k == "detect_thin_wall") + if (/*k == "adaptive_layer_height" || */k == "independent_support_layer_height" || k == "enable_support" || k == "detect_thin_wall") config->set_key_value(k, new ConfigOptionBool(true)); else if (k == "wall_loops") config->set_key_value(k, new ConfigOptionInt(0)); @@ -449,7 +503,7 @@ void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std:: void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, const bool is_global_config) { bool have_perimeters = config->opt_int("wall_loops") > 0; - for (auto el : { "detect_thin_wall", "detect_overhang_wall", + for (auto el : { "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall", "seam_position", "wall_infill_order", "outer_wall_line_width", "inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" }) toggle_field(el, have_perimeters); @@ -511,9 +565,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool have_support_soluble = have_support_material && config->opt_float("support_top_z_distance") == 0; auto support_style = config->opt_enum("support_style"); for (auto el : { "support_style", "support_base_pattern", - "support_base_pattern_spacing", "support_angle", + "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", + "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_object_xy_distance", "independent_support_layer_height"}) @@ -521,7 +575,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field("support_threshold_angle", have_support_material && (support_type == stNormalAuto || support_type == stTreeAuto || support_type==stHybridAuto)); //toggle_field("support_closing_radius", have_support_material && support_style == smsSnug); - for (auto el : {"tree_support_branch_angle", "tree_support_wall_count", "tree_support_with_infill", "tree_support_branch_distance", "tree_support_branch_diameter"}) + for (auto el : {"tree_support_branch_angle", "tree_support_wall_count", "tree_support_branch_distance", "tree_support_branch_diameter"}) toggle_field(el, config->opt_bool("enable_support") && (support_type == stTreeAuto || support_type == stTree || support_type == stHybridAuto)); // hide tree support settings when normal is selected @@ -530,7 +584,6 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("tree_support_branch_diameter", support_is_tree); toggle_line("tree_support_branch_angle", support_is_tree); toggle_line("tree_support_wall_count", support_is_tree); - toggle_line("tree_support_with_infill", support_is_tree); toggle_line("max_bridge_length", support_is_tree); // tree support use max_bridge_length instead of bridge_no_support @@ -558,7 +611,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co bool has_ironing = (config->opt_enum("ironing_type") != IroningType::NoIroning); for (auto el : { "ironing_flow", "ironing_spacing", "ironing_speed" }) - toggle_field(el, has_ironing); + toggle_line(el, has_ironing); // bool have_sequential_printing = (config->opt_enum("print_sequence") == PrintSequence::ByObject); // for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" }) @@ -568,19 +621,37 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_field("standby_temperature_delta", have_ooze_prevention); bool have_prime_tower = config->opt_bool("enable_prime_tower"); - for (auto el : { "prime_tower_width", "prime_volume"}) + for (auto el : { "prime_tower_width", "prime_volume", "prime_tower_brim_width"}) + toggle_line(el, have_prime_tower); + + for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"}) toggle_field(el, have_prime_tower); bool have_avoid_crossing_perimeters = config->opt_bool("reduce_crossing_wall"); - toggle_field("max_travel_detour_distance", have_avoid_crossing_perimeters); + toggle_line("max_travel_detour_distance", have_avoid_crossing_perimeters); bool has_overhang_speed = config->opt_bool("enable_overhang_speed"); - toggle_line("overhang_1_4_speed", has_overhang_speed); - toggle_line("overhang_2_4_speed", has_overhang_speed); - toggle_line("overhang_3_4_speed", has_overhang_speed); - toggle_line("overhang_4_4_speed", has_overhang_speed); + for (auto el : { "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"}) + toggle_line(el, has_overhang_speed); toggle_line("flush_into_objects", !is_global_config); + + bool has_fuzzy_skin = (config->opt_enum("fuzzy_skin") != FuzzySkinType::None); + for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance"}) + toggle_line(el, has_fuzzy_skin); + + // C11 printer is not support smooth timelapse + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + std::string str_preset_type = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle); + toggle_field("timelapse_type", str_preset_type != "C11"); + + bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; + for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", + "min_feature_size", "min_bead_width", "wall_distribution_count" }) + toggle_line(el, have_arachne); + toggle_field("detect_thin_wall", !have_arachne); + toggle_field("enable_overhang_speed", !have_arachne); + toggle_field("only_one_wall_top", !have_arachne); } void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/) diff --git a/src/slic3r/GUI/ConfigManipulation.hpp b/src/slic3r/GUI/ConfigManipulation.hpp index c7300639d8..1f6b566c43 100644 --- a/src/slic3r/GUI/ConfigManipulation.hpp +++ b/src/slic3r/GUI/ConfigManipulation.hpp @@ -76,6 +76,7 @@ public: void check_nozzle_temperature_range(DynamicPrintConfig* config); void check_nozzle_temperature_initial_layer_range(DynamicPrintConfig* config); void check_bed_temperature_difference(int bed_type, DynamicPrintConfig* config); + void check_filament_max_volumetric_speed(DynamicPrintConfig *config); // SLA print void update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config = false); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 1b4c09136b..4a6eecbaad 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -47,6 +47,7 @@ #include "format.hpp" #include "MsgDialog.hpp" #include "UnsavedChangesDialog.hpp" +#include "MainFrame.hpp" #if defined(__linux__) && defined(__WXGTK3__) #define wxLinux_gtk3 true @@ -344,9 +345,14 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt if (titles.size() > 1 || is_variants) { // It only makes sense to add the All / None buttons if there's multiple printers // All Standard button is added when there are more variants for at least one printer - auto *sel_all_std = new wxButton(this, wxID_ANY, titles.size() > 1 ? _L("All standard") : _L("Standard")); - auto *sel_all = new wxButton(this, wxID_ANY, _L("All")); - auto *sel_none = new wxButton(this, wxID_ANY, _L("None")); + auto *sel_all_std = new Button(this, titles.size() > 1 ? _L("All standard") : _L("Standard")); + auto *sel_all = new Button(this, _L("All")); + auto *sel_none = new Button(this, _L("None")); + + wxGetApp().UpdateDarkUI(sel_all_std); + wxGetApp().UpdateDarkUI(sel_all); + wxGetApp().UpdateDarkUI(sel_none); + if (is_variants) sel_all_std->Bind(wxEVT_BUTTON, [this](const wxCommandEvent& event) { this->select_all(true, false); }); sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &event) { this->select_all(true, true); }); @@ -449,13 +455,12 @@ ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxStrin , shortname(std::move(shortname)) , indent(indent) { - wxGetApp().UpdateDarkUI(this); - auto *sizer = new wxBoxSizer(wxVERTICAL); auto *text = new wxStaticText(this, wxID_ANY, std::move(title), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); const auto font = GetFont().MakeBold().Scaled(1.5); text->SetFont(font); + text->SetForegroundColour(*wxBLACK); sizer->Add(text, 0, wxALIGN_LEFT, 0); sizer->AddSpacer(10); @@ -473,6 +478,8 @@ ConfigWizardPage::ConfigWizardPage(ConfigWizard *parent, wxString title, wxStrin this->Layout(); event.Skip(); }); + + wxGetApp().UpdateDarkUI(this); } ConfigWizardPage::~ConfigWizardPage() {} @@ -639,6 +646,7 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin , list_vendor(new StringList(this)) , list_profile(new PresetList(this)) { + SetBackgroundColour(*wxWHITE); append_spacer(VERTICAL_SPACING); const int em = parent->em_unit(); @@ -650,8 +658,6 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin list_vendor->SetMinSize(wxSize(13*em, list_h)); list_profile->SetMinSize(wxSize(23*em, list_h)); - - grid = new wxFlexGridSizer(4, em/2, em); grid->AddGrowableCol(3, 1); grid->AddGrowableRow(1, 1); @@ -667,8 +673,13 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin grid->Add(list_profile, 1, wxEXPAND); auto *btn_sizer = new wxBoxSizer(wxHORIZONTAL); - auto *sel_all = new wxButton(this, wxID_ANY, _L("All")); - auto *sel_none = new wxButton(this, wxID_ANY, _L("None")); + auto *sel_all = new Button(this, _L("All")); + auto *sel_none = new Button(this, _L("None")); + + wxGetApp().UpdateDarkUI(sel_all); + wxGetApp().UpdateDarkUI(sel_none); + + btn_sizer->Add(sel_all, 0, wxRIGHT, em / 2); btn_sizer->Add(sel_none); @@ -677,6 +688,7 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin wxGetApp().UpdateDarkUI(list_vendor); wxGetApp().UpdateDarkUI(sel_all); wxGetApp().UpdateDarkUI(sel_none); + wxGetApp().UpdateDarkUI(list_profile); grid->Add(new wxBoxSizer(wxHORIZONTAL)); grid->Add(new wxBoxSizer(wxHORIZONTAL)); @@ -755,16 +767,16 @@ void PageMaterials::reload_presets() void PageMaterials::set_compatible_printers_html_window(const std::vector& printer_names, bool all_printers) { - const auto bgr_clr = -#if defined(__APPLE__) - html_window->GetParent()->GetBackgroundColour(); -#else -#if defined(_WIN32) - wxGetApp().get_window_default_clr(); -#else - wxSystemSettings::GetColour(wxSYS_COLOUR_MENU); -#endif -#endif + const auto bgr_clr = html_window->GetParent()->GetBackgroundColour(); +//#if defined(__APPLE__) +// html_window->GetParent()->GetBackgroundColour(); +//#else +//#if defined(_WIN32) +// html_window->GetParent()->GetBackgroundColour(); +//#else +// wxSystemSettings::GetColour(wxSYS_COLOUR_MENU); +//#endif +//#endif const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); const auto text_clr = wxGetApp().get_label_clr_default();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); @@ -1048,7 +1060,7 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected sel_vendor_prev = sel_vendor; } - wxGetApp().UpdateDarkUI(list_profile); + //wxGetApp().UpdateDarkUI(list_profile); } void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool material_type_ordering) @@ -1218,72 +1230,70 @@ PageCustom::PageCustom(ConfigWizard *parent) append(cb_custom); append(label); append(tc_profile_name); + wxGetApp().UpdateDarkUI(this); } -#ifdef _WIN32 -PageFilesAssociation::PageFilesAssociation(ConfigWizard* parent) - : ConfigWizardPage(parent, _L("Files association"), _L("Files association")) +PageFirmware::PageFirmware(ConfigWizard *parent) + : ConfigWizardPage(parent, _L("Firmware Type"), _L("Firmware"), 1) + , gcode_opt(*print_config_def.get("gcode_flavor")) + , gcode_picker(nullptr) { - cb_3mf = new wxCheckBox(this, wxID_ANY, _L("Associate with 3mf files")); - cb_stl = new wxCheckBox(this, wxID_ANY, _L("Associate with stl files")); - //cb_gcode = new wxCheckBox(this, wxID_ANY, _L("Associate with gcode files")); + append_text(_L("Choose the type of firmware used by your printer.")); + append_text(_(gcode_opt.tooltip)); - append(cb_3mf); - append(cb_stl); - //append(cb_gcode); + wxArrayString choices; + choices.Alloc(gcode_opt.enum_labels.size()); + for (const auto &label : gcode_opt.enum_labels) { + choices.Add(label); + } + + gcode_picker = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices); + wxGetApp().UpdateDarkUI(gcode_picker); + const auto &enum_values = gcode_opt.enum_values; + auto needle = enum_values.cend(); + if (gcode_opt.default_value) { + needle = std::find(enum_values.cbegin(), enum_values.cend(), gcode_opt.default_value->serialize()); + } + if (needle != enum_values.cend()) { + gcode_picker->SetSelection(needle - enum_values.cbegin()); + } else { + gcode_picker->SetSelection(0); + } + + append(gcode_picker); } -#endif // _WIN32 -PageVendors::PageVendors(ConfigWizard *parent) - : ConfigWizardPage(parent, _L("Other Vendors"), _L("Other Vendors")) +void PageFirmware::apply_custom_config(DynamicPrintConfig &config) { - const AppConfig &appconfig = this->wizard_p()->appconfig_new; - - append_text(_L("Pick another vendor:")); - - auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - boldfont.SetWeight(wxFONTWEIGHT_BOLD); - - for (const auto &pair : wizard_p()->bundles) { - const VendorProfile *vendor = pair.second.vendor_profile; - //BBS: add BBL as default - if (vendor->id == PresetBundle::BBL_BUNDLE) { continue; } - - auto *cbox = new wxCheckBox(this, wxID_ANY, vendor->name); - cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) { - wizard_p()->on_3rdparty_install(vendor, cbox->IsChecked()); - }); - - const auto &vendors = appconfig.vendors(); - const bool enabled = vendors.find(pair.first) != vendors.end(); - if (enabled) { - cbox->SetValue(true); - - auto pages = wizard_p()->pages_3rdparty.find(vendor->id); - wxCHECK_RET(pages != wizard_p()->pages_3rdparty.end(), _L("Internal error: third party vendor printers not created")); - - for (PagePrinters* page : { pages->second.first, pages->second.second }) - if (page) page->install = true; - } - - append(cbox); + auto sel = gcode_picker->GetSelection(); + if (sel >= 0 && (size_t)sel < gcode_opt.enum_labels.size()) { + auto *opt = new ConfigOptionEnum(static_cast(sel)); + config.set_key_value("gcode_flavor", opt); } } -/*PageBedShape::PageBedShape(ConfigWizard *parent) +PageBedShape::PageBedShape(ConfigWizard* parent) : ConfigWizardPage(parent, _L("Bed Shape and Size"), _L("Bed Shape"), 1) , shape_panel(new BedShapePanel(this)) { append_text(_L("Set the shape of your printer's bed.")); - shape_panel->build_panel(*wizard_p()->custom_config->option("printable_area"), {}, {}); + + shape_panel->build_panel(*wizard_p()->custom_config->option("printable_area"), + *wizard_p()->custom_config->option("bed_custom_texture"), + *wizard_p()->custom_config->option("bed_custom_model")); + append(shape_panel); } -void PageBedShape::apply_custom_config(DynamicPrintConfig &config) +void PageBedShape::apply_custom_config(DynamicPrintConfig& config) { const std::vector& points = shape_panel->get_shape(); + const std::string& custom_texture = shape_panel->get_custom_texture(); + const std::string& custom_model = shape_panel->get_custom_model(); config.set_key_value("printable_area", new ConfigOptionPoints(points)); -}*/ + config.set_key_value("bed_custom_texture", new ConfigOptionString(custom_texture)); + config.set_key_value("bed_custom_model", new ConfigOptionString(custom_model)); +} static void focus_event(wxFocusEvent& e, wxTextCtrl* ctrl, double def_value) { @@ -1460,19 +1470,231 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent) append(sizer_bed); } -void PageTemperatures::apply_custom_config(DynamicPrintConfig &config) +void PageTemperatures::apply_custom_config(DynamicPrintConfig& config) { // BBS -#if 0 - auto *opt_extr = new ConfigOptionInts(1, spin_extr->GetValue()); + /* + auto* opt_extr = new ConfigOptionInts(1, spin_extr->GetValue()); config.set_key_value("nozzle_temperature", opt_extr); - auto *opt_extr1st = new ConfigOptionInts(1, spin_extr->GetValue()); + auto* opt_extr1st = new ConfigOptionInts(1, spin_extr->GetValue()); config.set_key_value("nozzle_temperature_initial_layer", opt_extr1st); - auto *opt_bed = new ConfigOptionInts(1, spin_bed->GetValue()); + auto* opt_bed = new ConfigOptionInts(1, spin_bed->GetValue()); config.set_key_value("bed_temperature", opt_bed); - auto *opt_bed1st = new ConfigOptionInts(1, spin_bed->GetValue()); + auto* opt_bed1st = new ConfigOptionInts(1, spin_bed->GetValue()); config.set_key_value("bed_temperature_initial_layer", opt_bed1st); -#endif + */ +} + +ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) + : wxPanel(parent) + , bg(ScalableBitmap(parent, "BambuStudio_192px_transparent.png", 192)) + , bullet_black(ScalableBitmap(parent, "bullet_black.png")) + , bullet_blue(ScalableBitmap(parent, "bullet_blue.png")) + , bullet_white(ScalableBitmap(parent, "bullet_white.png")) + , item_active(NO_ITEM) + , item_hover(NO_ITEM) + , last_page((size_t)-1) +{ +#ifndef __WXOSX__ + SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX +#endif //__WXOSX__ + SetMinSize(bg.bmp().GetSize()); + + const wxSize size = GetTextExtent("m"); + em_w = size.x; + em_h = size.y; + + Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); + Bind(wxEVT_SIZE, [this](wxEvent& e) { e.Skip(); Refresh(); }); + Bind(wxEVT_MOTION, &ConfigWizardIndex::on_mouse_move, this); + + Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &evt) { + if (item_hover != -1) { + item_hover = -1; + Refresh(); + } + evt.Skip(); + }); + + Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &evt) { + if (item_hover >= 0) { go_to(item_hover); } + }); +} + +wxDECLARE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); + +void ConfigWizardIndex::add_page(ConfigWizardPage *page) +{ + if (!page) + return; + last_page = items.size(); + items.emplace_back(Item { page->shortname, page->indent, page }); + Refresh(); +} + +void ConfigWizardIndex::add_label(wxString label, unsigned indent) +{ + items.emplace_back(Item { std::move(label), indent, nullptr }); + Refresh(); +} + +ConfigWizardPage* ConfigWizardIndex::active_page() const +{ + if (item_active >= items.size()) { return nullptr; } + + return items[item_active].page; +} + +void ConfigWizardIndex::go_prev() +{ + // Search for a preceiding item that is a page (not a label, ie. page != nullptr) + + if (item_active == NO_ITEM) { return; } + + for (size_t i = item_active; i > 0; i--) { + if (items[i - 1].page != nullptr) { + go_to(i - 1); + return; + } + } +} + +void ConfigWizardIndex::go_next() +{ + // Search for a next item that is a page (not a label, ie. page != nullptr) + + if (item_active == NO_ITEM) { return; } + + for (size_t i = item_active + 1; i < items.size(); i++) { + if (items[i].page != nullptr) { + go_to(i); + return; + } + } +} + +// This one actually performs the go-to op +void ConfigWizardIndex::go_to(size_t i) +{ + if (i != item_active + && i < items.size() + && items[i].page != nullptr) { + auto *new_active = items[i].page; + auto *former_active = active_page(); + if (former_active != nullptr) { + former_active->Hide(); + } + + item_active = i; + new_active->Show(); + + wxCommandEvent evt(EVT_INDEX_PAGE, GetId()); + AddPendingEvent(evt); + + Refresh(); + + new_active->on_activate(); + } +} + +void ConfigWizardIndex::go_to(const ConfigWizardPage *page) +{ + if (page == nullptr) { return; } + + for (size_t i = 0; i < items.size(); i++) { + if (items[i].page == page) { + go_to(i); + return; + } + } +} + +void ConfigWizardIndex::clear() +{ + auto *former_active = active_page(); + if (former_active != nullptr) { former_active->Hide(); } + + items.clear(); + item_active = NO_ITEM; +} + +void ConfigWizardIndex::on_paint(wxPaintEvent & evt) +{ + const auto size = GetClientSize(); + if (size.GetHeight() == 0 || size.GetWidth() == 0) { return; } + + wxPaintDC dc(this); + + const auto bullet_w = bullet_black.bmp().GetSize().GetWidth(); + const auto bullet_h = bullet_black.bmp().GetSize().GetHeight(); + const int yoff_icon = bullet_h < em_h ? (em_h - bullet_h) / 2 : 0; + const int yoff_text = bullet_h > em_h ? (bullet_h - em_h) / 2 : 0; + const int yinc = item_height(); + + int index_width = 0; + + unsigned y = 0; + for (size_t i = 0; i < items.size(); i++) { + const Item& item = items[i]; + unsigned x = em_w/2 + item.indent * em_w; + + if (i == item_active || (item_hover >= 0 && i == (size_t)item_hover)) { + dc.DrawBitmap(bullet_blue.bmp(), x, y + yoff_icon, false); + } + else if (i < item_active) { dc.DrawBitmap(bullet_black.bmp(), x, y + yoff_icon, false); } + else if (i > item_active) { dc.DrawBitmap(bullet_white.bmp(), x, y + yoff_icon, false); } + + x += + bullet_w + em_w/2; + const auto text_size = dc.GetTextExtent(item.label); + dc.SetTextForeground(wxGetApp().get_label_clr_default()); + dc.DrawText(item.label, x, y + yoff_text); + + y += yinc; + index_width = std::max(index_width, (int)x + text_size.x); + } + + //draw logo + if (int y = size.y - bg.GetBmpHeight(); y>=0) { + dc.DrawBitmap(bg.bmp(), 0, y, false); + index_width = std::max(index_width, bg.GetBmpWidth() + em_w / 2); + } + + if (GetMinSize().x < index_width) { + CallAfter([this, index_width]() { + SetMinSize(wxSize(index_width, GetMinSize().y)); + Refresh(); + }); + } +} + +void ConfigWizardIndex::on_mouse_move(wxMouseEvent &evt) +{ + const wxClientDC dc(this); + const wxPoint pos = evt.GetLogicalPosition(dc); + + const ssize_t item_hover_new = pos.y / item_height(); + + if (item_hover_new < ssize_t(items.size()) && item_hover_new != item_hover) { + item_hover = item_hover_new; + Refresh(); + } + + evt.Skip(); +} + +void ConfigWizardIndex::msw_rescale() +{ + const wxSize size = GetTextExtent("m"); + em_w = size.x; + em_h = size.y; + + bg.msw_rescale(); + SetMinSize(bg.bmp().GetSize()); + + bullet_black.msw_rescale(); + bullet_blue.msw_rescale(); + bullet_white.msw_rescale(); + Refresh(); } // Materials @@ -1562,8 +1784,29 @@ void ConfigWizard::priv::load_pages() wxWindowUpdateLocker freeze_guard(q); (void)freeze_guard; + const ConfigWizardPage *former_active = index->active_page(); + + index->clear(); + + // Printers + if (!only_sla_mode) { + index->add_page(page_custom); + if (page_custom->custom_wanted()) { + index->add_page(page_firmware); + index->add_page(page_bed); + index->add_page(page_diams); + //index->add_page(page_temps); + } + + // Filaments & Materials + if (any_fff_selected) { index->add_page(page_filaments); } + } + if (any_sla_selected) { index->add_page(page_sla_materials); } + // there should to be selected at least one printer - btn_finish->Enable(); + btn_finish->Enable(any_fff_selected || any_sla_selected || custom_printer_selected); + + index->go_to(former_active); // Will restore the active item/page if possible q->Layout(); // This Refresh() is needed to avoid ugly artifacts after printer selection, when no one vendor was selected from the very beginnig @@ -1584,6 +1827,12 @@ void ConfigWizard::priv::init_dialog_size() 9*disp_rect.width / 10, 9*disp_rect.height / 10); + const int width_hint = index->GetSize().GetWidth() + 90 * em()/*std::max(90 * em(), (only_sla_mode ? page_msla->get_width() : page_fff->get_width()) + 30 * em())*/; // XXX: magic constant, I found no better solution + if (width_hint < window_rect.width) { + window_rect.x += (window_rect.width - width_hint) / 2; + window_rect.width = width_hint; + } + q->SetSize(window_rect); } @@ -1668,16 +1917,20 @@ void ConfigWizard::priv::enable_next(bool enable) void ConfigWizard::priv::set_start_page(ConfigWizard::StartPage start_page) { switch (start_page) { - case ConfigWizard::SP_PRINTERS: + case ConfigWizard::SP_CUSTOM: + index->go_to(page_custom); btn_next->SetFocus(); break; case ConfigWizard::SP_FILAMENTS: + index->go_to(page_filaments); btn_finish->SetFocus(); break; case ConfigWizard::SP_MATERIALS: + index->go_to(page_sla_materials); btn_finish->SetFocus(); break; default: + index->go_to(page_custom); btn_next->SetFocus(); break; } @@ -1714,7 +1967,7 @@ void ConfigWizard::priv::create_3rdparty_pages() add_page(pageSLA); } - pages_3rdparty.insert({vendor->id, {pageFFF, pageSLA}}); + //pages_3rdparty.insert({vendor->id, {pageFFF, pageSLA}}); } } @@ -1932,19 +2185,19 @@ void ConfigWizard::priv::select_default_materials_for_printer_models(Technology void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install) { - auto it = pages_3rdparty.find(vendor->id); - wxCHECK_RET(it != pages_3rdparty.end(), "Internal error: GUI page not found for 3rd party vendor profile"); + //auto it = pages_3rdparty.find(vendor->id); + //wxCHECK_RET(it != pages_3rdparty.end(), "Internal error: GUI page not found for 3rd party vendor profile"); - for (PagePrinters* page : { it->second.first, it->second.second }) - if (page) { - if (page->install && !install) - page->select_all(false); - page->install = install; - // if some 3rd vendor is selected, select first printer for them - if (install) - page->printer_pickers[0]->select_one(0, true); - page->Layout(); - } + //for (PagePrinters* page : { it->second.first, it->second.second }) + // if (page) { + // if (page->install && !install) + // page->select_all(false); + // page->install = install; + // // if some 3rd vendor is selected, select first printer for them + // if (install) + // page->printer_pickers[0]->select_one(0, true); + // page->Layout(); + // } load_pages(); } @@ -1960,6 +2213,7 @@ bool ConfigWizard::priv::on_bnt_finish() * than last changes wouldn't be updated for filaments/materials. * SO, do that before close of Wizard */ + update_materials(T_ANY); if (any_fff_selected) page_filaments->reload_presets(); @@ -2323,30 +2577,42 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese app_config->set_vendors(appconfig_new); -#ifdef _WIN32 - app_config->set_bool("associate_3mf", page_files_association->associate_3mf()); - app_config->set_bool("associate_stl", page_files_association->associate_stl()); - - if (wxGetApp().is_editor()) { - if (page_files_association->associate_3mf()) - wxGetApp().associate_files(L"3mf"); - if (page_files_association->associate_stl()) - wxGetApp().associate_files(L"stl"); - } -// else { -// if (page_files_association->associate_gcode()) -// wxGetApp().associate_gcode_files(); -// } - -#endif // _WIN32 - if (check_unsaved_preset_changes) preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSilentDisableSystem, {preferred_model, preferred_variant, first_added_filament, first_added_sla_material}); + if (!only_sla_mode && page_custom->custom_wanted()) { + // if unsaved changes was not cheched till this moment + if (!check_unsaved_preset_changes && + !wxGetApp().check_and_keep_current_preset_changes(caption, _L("Custom printer was installed and it will be activated."), act_btns, &apply_keeped_changes)) + return false; + + page_firmware->apply_custom_config(*custom_config); + page_bed->apply_custom_config(*custom_config); + page_diams->apply_custom_config(*custom_config); + //page_temps->apply_custom_config(*custom_config); + +#if ENABLE_COPY_CUSTOM_BED_MODEL_AND_TEXTURE + copy_bed_model_and_texture_if_needed(*custom_config); +#endif // ENABLE_COPY_CUSTOM_BED_MODEL_AND_TEXTURE + + custom_config->set_key_value("filament_colour", wxGetApp().preset_bundle->project_config.option("filament_colour")); + const std::string profile_name = page_custom->profile_name(); + Semver semver(SLIC3R_VERSION); + preset_bundle->load_config_from_wizard(profile_name, *custom_config, semver, true); + + wxGetApp().plater()->sidebar().update_presets(Slic3r::Preset::Type::TYPE_PRINTER); + wxGetApp().plater()->sidebar().update_presets(Slic3r::Preset::Type::TYPE_FILAMENT); + wxGetApp().plater()->sidebar().update_presets(Slic3r::Preset::Type::TYPE_PRINT); + } + // Update the selections from the compatibilty. preset_bundle->export_selections(*app_config); + // Update Preset Combobox + //auto evt = new SimpleEvent(EVT_UPDATE_PRESET_CB); + //wxQueueEvent(wxGetApp().mainframe, evt); + return true; } void ConfigWizard::priv::update_presets_in_config(const std::string& section, const std::string& alias_key, bool add) @@ -2370,11 +2636,7 @@ void ConfigWizard::priv::update_presets_in_config(const std::string& section, co bool ConfigWizard::priv::check_fff_selected() { - bool ret = page_fff->any_selected(); - for (const auto& printer: pages_3rdparty) - if (printer.second.first) // FFF page - ret |= printer.second.first->any_selected(); - return ret; + return false; } bool ConfigWizard::priv::check_sla_selected() @@ -2386,17 +2648,20 @@ bool ConfigWizard::priv::check_sla_selected() // Public ConfigWizard::ConfigWizard(wxWindow *parent) - : DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + : DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE /*| wxRESIZE_BORDER*/) , p(new priv(this)) { this->SetFont(wxGetApp().normal_font()); - + SetBackgroundColour(*wxWHITE); p->load_vendors(); //BBS: add bed exclude areas p->custom_config.reset(DynamicPrintConfig::new_from_defaults_keys({ - "gcode_flavor", "printable_area", "bed_exclude_area", "filament_diameter", "nozzle_temperature", "thumbnails"/*"bed_temperature",*/ + "gcode_flavor", "printable_area", "bed_exclude_area", "bed_custom_texture", "bed_custom_model", "nozzle_diameter", "filament_diameter", "thumbnails" + //, "nozzle_temperature", "bed_temperature" })); + p->index = new ConfigWizardIndex(this); + auto *vsizer = new wxBoxSizer(wxVERTICAL); auto *topsizer = new wxBoxSizer(wxHORIZONTAL); auto* hline = new StaticLine(this); @@ -2408,23 +2673,25 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->hscroll_sizer = new wxBoxSizer(wxHORIZONTAL); p->hscroll->SetSizer(p->hscroll_sizer); + wxGetApp().UpdateDarkUI(p->hscroll); + + topsizer->Add(p->index, 0, wxEXPAND); topsizer->AddSpacer(INDEX_MARGIN); topsizer->Add(p->hscroll, 1, wxEXPAND); - p->btn_sel_all = new wxButton(this, wxID_ANY, _L("Select all standard printers")); - p->btnsizer->Add(p->btn_sel_all); - - p->btn_prev = new wxButton(this, wxID_ANY, _L("< &Back")); - p->btn_next = new wxButton(this, wxID_ANY, _L("&Next >")); - p->btn_finish = new wxButton(this, wxID_APPLY, _L("&Finish")); - p->btn_cancel = new wxButton(this, wxID_CANCEL, _L("Cancel")); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac + p->btn_prev = new Button(this, _L("btn_next = new Button(this, _L("Next>")); + p->btn_finish = new Button(this,_L("Finish")); + p->btn_finish->SetId(wxID_APPLY); + p->btn_cancel = new Button(this, _L("Cancel")); // Note: The label needs to be present, otherwise we get accelerator bugs on Mac + p->btn_cancel->SetId(wxID_CANCEL); + p->btnsizer->AddStretchSpacer(); p->btnsizer->Add(p->btn_prev, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_next, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING); p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING); - wxGetApp().UpdateDarkUI(p->btn_sel_all); wxGetApp().UpdateDarkUI(p->btn_prev); wxGetApp().UpdateDarkUI(p->btn_next); wxGetApp().UpdateDarkUI(p->btn_finish); @@ -2435,36 +2702,22 @@ ConfigWizard::ConfigWizard(wxWindow *parent) wxCHECK_RET(bbl_it != p->bundles.cend(), "Vendor BambooLab not found"); const VendorProfile * vendor_bbl = bbl_it->second.vendor_profile; - p->page_fff = new PagePrinters(this, _L("BBL FFF Technology Printers"), "BBL FFF", *vendor_bbl, 0, T_FFF); p->only_sla_mode = false; - if (!p->only_sla_mode) { - p->add_page(p->page_fff); - p->page_fff->is_primary_printer_page = true; - } - - if (!p->only_sla_mode) { - // Pages for 3rd party vendors - p->create_3rdparty_pages(); // Needs to be done _before_ creating PageVendors - p->add_page(p->page_vendors = new PageVendors(this)); - //p->add_page(p->page_custom = new PageCustom(this)); - //p->custom_printer_selected = p->page_custom->custom_wanted(); - } - p->any_sla_selected = p->check_sla_selected(); if (p->only_sla_mode) p->any_fff_selected = p->check_fff_selected(); - p->update_materials(T_ANY); - if (!p->only_sla_mode) - p->add_page(p->page_filaments = new PageMaterials(this, &p->filaments, - _L("Filament Profiles Selection"), _L("Filaments"), _L("Type:") )); + p->add_page(p->page_custom = new PageCustom(this)); + p->custom_printer_selected = p->page_custom->custom_wanted(); -#ifdef _WIN32 - p->add_page(p->page_files_association = new PageFilesAssociation(this)); -#endif // _WIN32 - //p->add_page(p->page_bed = new PageBedShape(this)); + p->add_page(p->page_firmware = new PageFirmware(this)); + p->add_page(p->page_bed = new PageBedShape(this)); p->add_page(p->page_diams = new PageDiameters(this)); - p->add_page(p->page_temps = new PageTemperatures(this)); + //p->add_page(p->page_temps = new PageTemperatures(this)); + + p->update_materials(T_ANY); + p->add_page(p->page_filaments = new PageMaterials(this, &p->filaments, + _L("Filament Profiles Selection"), _L("Filaments"), _L("Type:"))); p->load_pages(); @@ -2484,7 +2737,12 @@ ConfigWizard::ConfigWizard(wxWindow *parent) p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { - ; + ConfigWizardPage* active_page = this->p->index->active_page(); + if ((active_page == p->page_filaments || active_page == p->page_sla_materials) && + !p->check_and_install_missing_materials(dynamic_cast(active_page)->materials->technology)) + // In that case don't leave the page and the function above queried the user whether to install default materials. + return; + this->p->index->go_next(); }); p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) @@ -2493,16 +2751,21 @@ ConfigWizard::ConfigWizard(wxWindow *parent) this->EndModal(wxID_OK); }); - p->btn_sel_all->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &) { - p->any_sla_selected = true; - p->load_pages(); - p->page_fff->select_all(true, false); + p->index->Bind(EVT_INDEX_PAGE, [this](const wxCommandEvent &) { + const bool is_last = p->index->active_is_last(); + p->btn_next->Show(! is_last); + if (is_last) + p->btn_finish->SetFocus(); + + Layout(); }); if (wxLinux_gtk3) this->Bind(wxEVT_SHOW, [this, vsizer](const wxShowEvent& e) { ; }); + + wxGetApp().UpdateDlgDarkUI(this); } ConfigWizard::~ConfigWizard() {} @@ -2558,13 +2821,9 @@ void ConfigWizard::on_dpi_changed(const wxRect &suggested_rect) msw_buttons_rescale(this, em, { wxID_APPLY, wxID_CANCEL, - p->btn_sel_all->GetId(), p->btn_next->GetId(), p->btn_prev->GetId() }); - for (auto printer_picker: p->page_fff->printer_pickers) - msw_buttons_rescale(this, em, printer_picker->get_button_indexes()); - p->init_dialog_size(); Refresh(); diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index 88d2e2d7c3..f929a3aaa2 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -32,6 +32,7 @@ public: SP_PRINTERS, SP_FILAMENTS, SP_MATERIALS, + SP_CUSTOM, }; ConfigWizard(wxWindow *parent); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index 157bf07c12..364d378b42 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -24,9 +24,10 @@ #include "libslic3r/PrintConfig.hpp" #include "libslic3r/PresetBundle.hpp" #include "slic3r/Utils/PresetUpdater.hpp" -//#include "BedShapeDialog.hpp" +#include "BedShapeDialog.hpp" #include "GUI.hpp" #include "wxExtensions.hpp" +#include "Widgets/Button.hpp" namespace fs = boost::filesystem; @@ -162,7 +163,7 @@ struct PrinterPickerEvent; typedef std::function ModelFilter; -struct PrinterPicker: wxPanel +struct PrinterPicker: wxPanel //TO check { struct Checkbox : wxCheckBox { @@ -240,7 +241,7 @@ struct PageWelcome: ConfigWizardPage virtual void set_run_reason(ConfigWizard::RunReason run_reason) override; }; -struct PagePrinters: ConfigWizardPage +struct PagePrinters: ConfigWizardPage //TO check { std::vector printer_pickers; Technology technology; @@ -386,50 +387,59 @@ private: }; -struct PageUpdate: ConfigWizardPage +//struct PageUpdate: ConfigWizardPage +//{ +// bool version_check; +// bool preset_update; +// +// PageUpdate(ConfigWizard *parent); +//}; + +//struct PageReloadFromDisk : ConfigWizardPage +//{ +// bool full_pathnames; +// +// PageReloadFromDisk(ConfigWizard* parent); +//}; + +//#ifdef _WIN32 +//struct PageFilesAssociation : ConfigWizardPage +//{ +//private: +// wxCheckBox* cb_3mf{ nullptr }; +// wxCheckBox* cb_stl{ nullptr }; +//// wxCheckBox* cb_gcode; +// +//public: +// PageFilesAssociation(ConfigWizard* parent); +// +// bool associate_3mf() const { return cb_3mf->IsChecked(); } +// bool associate_stl() const { return cb_stl->IsChecked(); } +//// bool associate_gcode() const { return cb_gcode->IsChecked(); } +//}; +//#endif // _WIN32 + +//struct PageVendors: ConfigWizardPage +//{ +// PageVendors(ConfigWizard *parent); +//}; + +struct PageFirmware: ConfigWizardPage { - bool version_check; - bool preset_update; + const ConfigOptionDef &gcode_opt; + wxChoice *gcode_picker; - PageUpdate(ConfigWizard *parent); -}; - -struct PageReloadFromDisk : ConfigWizardPage -{ - bool full_pathnames; - - PageReloadFromDisk(ConfigWizard* parent); -}; - -#ifdef _WIN32 -struct PageFilesAssociation : ConfigWizardPage -{ -private: - wxCheckBox* cb_3mf{ nullptr }; - wxCheckBox* cb_stl{ nullptr }; -// wxCheckBox* cb_gcode; - -public: - PageFilesAssociation(ConfigWizard* parent); - - bool associate_3mf() const { return cb_3mf->IsChecked(); } - bool associate_stl() const { return cb_stl->IsChecked(); } -// bool associate_gcode() const { return cb_gcode->IsChecked(); } -}; -#endif // _WIN32 - -struct PageVendors: ConfigWizardPage -{ - PageVendors(ConfigWizard *parent); -}; - -/*struct PageBedShape: ConfigWizardPage -{ - BedShapePanel *shape_panel; - - PageBedShape(ConfigWizard *parent); + PageFirmware(ConfigWizard *parent); virtual void apply_custom_config(DynamicPrintConfig &config); -};*/ +}; + +struct PageBedShape : ConfigWizardPage +{ + BedShapePanel* shape_panel; + + PageBedShape(ConfigWizard* parent); + virtual void apply_custom_config(DynamicPrintConfig& config); +}; struct PageDiameters: ConfigWizardPage { @@ -454,6 +464,62 @@ typedef std::map> Pages3rdparty; + +class ConfigWizardIndex: public wxPanel +{ +public: + ConfigWizardIndex(wxWindow *parent); + + void add_page(ConfigWizardPage *page); + void add_label(wxString label, unsigned indent = 0); + + size_t active_item() const { return item_active; } + ConfigWizardPage* active_page() const; + bool active_is_last() const { return item_active < items.size() && item_active == last_page; } + + void go_prev(); + void go_next(); + void go_to(size_t i); + void go_to(const ConfigWizardPage *page); + + void clear(); + void msw_rescale(); + + int em() const { return em_w; } + + static const size_t NO_ITEM = size_t(-1); +private: + struct Item + { + wxString label; + unsigned indent; + ConfigWizardPage *page; // nullptr page => label-only item + + bool operator==(ConfigWizardPage *page) const { return this->page == page; } + }; + + int em_w; + int em_h; + ScalableBitmap bg; + ScalableBitmap bullet_black; + ScalableBitmap bullet_blue; + ScalableBitmap bullet_white; + + std::vector items; + size_t item_active; + ssize_t item_hover; + size_t last_page; + + int item_height() const { return std::max(bullet_black.bmp().GetSize().GetHeight(), em_w) + em_w; } + + void on_paint(wxPaintEvent &evt); + void on_mouse_move(wxMouseEvent &evt); +}; + +wxDEFINE_EVENT(EVT_INDEX_PAGE, wxCommandEvent); + + + // ConfigWizard private data typedef std::map> PresetAliases; @@ -482,26 +548,28 @@ struct ConfigWizard::priv wxBoxSizer *hscroll_sizer = nullptr; wxBoxSizer *btnsizer = nullptr; ConfigWizardPage *page_current = nullptr; - wxButton *btn_sel_all = nullptr; - wxButton *btn_prev = nullptr; - wxButton *btn_next = nullptr; - wxButton *btn_finish = nullptr; - wxButton *btn_cancel = nullptr; + ConfigWizardIndex *index = nullptr; + //wxButton *btn_sel_all = nullptr; + Button *btn_prev = nullptr; + Button *btn_next = nullptr; + Button *btn_finish = nullptr; + Button *btn_cancel = nullptr; - PagePrinters *page_fff = nullptr; - PagePrinters *page_msla = nullptr; + //PagePrinters *page_fff = nullptr; + //PagePrinters *page_msla = nullptr; PageMaterials *page_filaments = nullptr; PageMaterials *page_sla_materials = nullptr; PageCustom *page_custom = nullptr; - PageReloadFromDisk *page_reload_from_disk = nullptr; -#ifdef _WIN32 - PageFilesAssociation* page_files_association = nullptr; -#endif // _WIN32 - PageVendors *page_vendors = nullptr; - Pages3rdparty pages_3rdparty; + //PageReloadFromDisk *page_reload_from_disk = nullptr; +//#ifdef _WIN32 +// PageFilesAssociation* page_files_association = nullptr; +//#endif // _WIN32 + //PageVendors *page_vendors = nullptr; + //Pages3rdparty pages_3rdparty; // Custom setup pages - //PageBedShape *page_bed = nullptr; + PageFirmware *page_firmware = nullptr; + PageBedShape *page_bed = nullptr; PageDiameters *page_diams = nullptr; PageTemperatures *page_temps = nullptr; diff --git a/src/slic3r/GUI/ConfirmHintDialog.cpp b/src/slic3r/GUI/ConfirmHintDialog.cpp deleted file mode 100644 index c64aea79f7..0000000000 --- a/src/slic3r/GUI/ConfirmHintDialog.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "ConfirmHintDialog.hpp" -#include -#include -#include -#include - - -namespace Slic3r { namespace GUI { - -wxDEFINE_EVENT(EVT_CONFIRM_HINT, wxCommandEvent); - -ConfirmHintDialog::ConfirmHintDialog(wxWindow* parent, wxWindowID id, const wxString& title, enum ButtonStyle btn_style, const wxPoint& pos, const wxSize& size, long style) - : DPIDialog(parent, id, title, pos, size, style) -{ - std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); - SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); - - auto* main_sizer = new wxBoxSizer(wxVERTICAL); - auto* button_sizer = new wxBoxSizer(wxHORIZONTAL); - - wxPanel* m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); - m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); - - m_button_confirm = new Button(this, _L("Confirm")); - m_button_confirm->SetFont(Label::Body_14); - m_button_confirm->SetMinSize(wxSize(-1, FromDIP(24))); - m_button_confirm->SetCornerRadius(FromDIP(12)); - StateColor confirm_btn_bg(std::pair(wxColour(61, 203, 115), StateColor::Hovered), - std::pair(wxColour(0, 174, 66), StateColor::Normal)); - m_button_confirm->SetBackgroundColor(confirm_btn_bg); - m_button_confirm->SetBorderColor(wxColour(0, 174, 66)); - m_button_confirm->SetTextColor(*wxWHITE); - - m_button_close = new Button(this, _L("Cancel")); - m_button_close->SetFont(Label::Body_14); - m_button_close->SetMinSize(wxSize(-1, FromDIP(24))); - m_button_close->SetCornerRadius(FromDIP(12)); - StateColor close_btn_bg(std::pair(wxColour(206, 206, 206), StateColor::Hovered), - std::pair(*wxWHITE, StateColor::Normal)); - m_button_close->SetBackgroundColor(close_btn_bg); - m_button_close->SetBorderColor(wxColour(38, 46, 48)); - m_button_close->SetTextColor(wxColour(38, 46, 48)); - - button_sizer->AddStretchSpacer(); - button_sizer->Add(m_button_confirm); - button_sizer->AddSpacer(FromDIP(20)); - button_sizer->Add(m_button_close); - - if (btn_style == CONFIRM_AND_CANCEL) - m_button_close->Show(); - else - m_button_close->Hide(); - - main_sizer->Add(m_line_top, 0, wxEXPAND, 0); - main_sizer->AddSpacer(wxSize(FromDIP(475), FromDIP(100)).y); - main_sizer->Add(button_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, FromDIP(25)); - - SetSizer(main_sizer); - - CenterOnParent(); - - this->SetSize(wxSize(wxSize(FromDIP(475), FromDIP(100)).x, -1)); - this->SetMinSize(wxSize(wxSize(FromDIP(475), FromDIP(100)).x, -1)); - Layout(); - Fit(); - this->Bind(wxEVT_PAINT, &ConfirmHintDialog::OnPaint, this); - m_button_confirm->Bind(wxEVT_BUTTON, &ConfirmHintDialog::on_button_confirm, this); - m_button_close->Bind(wxEVT_BUTTON, &ConfirmHintDialog::on_button_close, this); -} - -ConfirmHintDialog::~ConfirmHintDialog() {} - -void ConfirmHintDialog::SetHint(const wxString& hint){ - firm_up_hint = hint; -} - -void ConfirmHintDialog::OnPaint(wxPaintEvent& event){ - wxPaintDC dc(this); - render(dc); -} - -void ConfirmHintDialog::render(wxDC& dc) { - wxSize size = GetSize(); - - dc.SetFont(Label::Body_14); - dc.SetTextForeground(text_color); - wxPoint pos_start = wxPoint(FromDIP(25), FromDIP(25)); - - wxSize firm_up_hint_size = dc.GetTextExtent(firm_up_hint); - wxPoint pos_firm_up_hint = pos_start; - - if (firm_up_hint_size.x + pos_firm_up_hint.x + FromDIP(25) > wxSize(FromDIP(475), FromDIP(100)).x) { - bool is_ch = false; - if (firm_up_hint[0] > 0x80 && firm_up_hint[1] > 0x80) - is_ch = true; - - wxString fisrt_line; - wxString remaining_line; - - wxString count_txt; - int new_line_pos = 0; - for (int i = 0; i < firm_up_hint.length(); i++) { - count_txt += firm_up_hint[i]; - auto text_size = dc.GetTextExtent(count_txt); - if (text_size.x + pos_firm_up_hint.x + FromDIP(25) < wxSize(FromDIP(475), FromDIP(100)).x) - { - if (firm_up_hint[i] == ' ') { - new_line_pos = i; - } else if (firm_up_hint[i] == '\n') { - fisrt_line = firm_up_hint.SubString(0, i); - remaining_line = firm_up_hint.SubString(i + 1, firm_up_hint.length()); - break; - } - } - else { - if (!is_ch) { - fisrt_line = firm_up_hint.SubString(0, new_line_pos); - remaining_line = firm_up_hint.SubString(new_line_pos + 1, firm_up_hint.length()); - break; - } - else { - fisrt_line = firm_up_hint.SubString(0, i - 1); - remaining_line = firm_up_hint.SubString(i, firm_up_hint.length()); - break; - } - count_txt = ""; - } - } - dc.DrawText(fisrt_line, pos_firm_up_hint); - - count_txt = ""; - new_line_pos = 0; - for (int i = 0; i < remaining_line.length(); i++) { - count_txt += remaining_line[i]; - auto text_size = dc.GetTextExtent(count_txt); - if (text_size.x + FromDIP(25) + FromDIP(25) < wxSize(FromDIP(475), FromDIP(100)).x) - { - if (remaining_line[i] == ' ' || remaining_line[i] == '\n') - new_line_pos = i; - } - else { - if (!is_ch){ - remaining_line[new_line_pos] = '\n'; - } - else { - remaining_line.insert(i, '\n'); - } - count_txt = ""; - } - } - wxPoint pos_txt = pos_firm_up_hint; - pos_txt.y += dc.GetCharHeight(); - dc.DrawText(remaining_line, pos_txt); - } - else - dc.DrawText(firm_up_hint, pos_firm_up_hint); -} - -void ConfirmHintDialog::on_button_confirm(wxCommandEvent& event) { - wxCommandEvent evt(EVT_CONFIRM_HINT, GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(evt); - - if (this->IsModal()) - this->EndModal(wxID_OK); - else - this->Close(); -} - -void ConfirmHintDialog::on_button_close(wxCommandEvent& event) { - this->Close(); -} - -bool ConfirmHintDialog::Show(bool show) -{ - if (show) { CentreOnParent(); } - return DPIDialog::Show(show); -} - -void ConfirmHintDialog::on_dpi_changed(const wxRect& suggested_rect) { - m_button_confirm->SetMinSize(wxSize(-1, FromDIP(24))); - m_button_confirm->SetCornerRadius(FromDIP(12)); - if (m_button_close->IsShown()) { - m_button_close->SetMinSize(wxSize(-1, FromDIP(24))); - m_button_close->SetCornerRadius(FromDIP(12)); - } - Layout(); -} - -}} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/ConfirmHintDialog.hpp b/src/slic3r/GUI/ConfirmHintDialog.hpp deleted file mode 100644 index e265077e07..0000000000 --- a/src/slic3r/GUI/ConfirmHintDialog.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef slic3r_GUI_ConfirmHintDialog_hpp_ -#define slic3r_GUI_ConfirmHintDialog_hpp_ - -#include "GUI_Utils.hpp" -#include -#include "Widgets/Button.hpp" -#include - -namespace Slic3r { namespace GUI { - -wxDECLARE_EVENT(EVT_CONFIRM_HINT, wxCommandEvent); - -class ConfirmHintDialog : public DPIDialog -{ -private: - wxStaticText* m_staticText_hint; - Button* m_button_confirm; - Button* m_button_close; - wxStaticBitmap* m_bitmap_home; - ScalableBitmap m_home_bmp; - wxString firm_up_hint = ""; - - void OnPaint(wxPaintEvent& event); - void render(wxDC& dc); - void on_button_confirm(wxCommandEvent& event); - void on_button_close(wxCommandEvent& event); - void on_dpi_changed(const wxRect& suggested_rect) override; - -public: - enum ButtonStyle { - ONLY_CONFIRM = 0, - CONFIRM_AND_CANCEL = 1, - MAX_STYLE_NUM = 2 - }; - - ConfirmHintDialog(wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxString& title = wxEmptyString, - enum ButtonStyle btn_style = CONFIRM_AND_CANCEL, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxCLOSE_BOX | wxCAPTION); - - const wxColour text_color = wxColour(107, 107, 107); - - void SetHint(const wxString &hint); - - bool Show(bool show) override; - - ~ConfirmHintDialog(); -}; -}} // namespace Slic3r::GUI - -#endif \ No newline at end of file diff --git a/src/slic3r/GUI/ConnectPrinter.cpp b/src/slic3r/GUI/ConnectPrinter.cpp index fcd8df8220..124dac10d7 100644 --- a/src/slic3r/GUI/ConnectPrinter.cpp +++ b/src/slic3r/GUI/ConnectPrinter.cpp @@ -1,4 +1,5 @@ #include "ConnectPrinter.hpp" +#include "GUI_App.hpp" #include #include #include "libslic3r/AppConfig.hpp" @@ -8,7 +9,7 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons : DPIDialog(parent, id, _L("ConnectPrinter(LAN)"), pos, size, style) { init_bitmap(); - + SetBackgroundColour(*wxWHITE); this->SetSizeHints(wxDefaultSize, wxDefaultSize); wxBoxSizer *main_sizer; @@ -50,6 +51,7 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons m_button_confirm->SetFont(Label::Body_12); m_button_confirm->SetMinSize(wxSize(-1, FromDIP(24))); m_button_confirm->SetCornerRadius(FromDIP(12)); + m_button_confirm->SetTextColor(wxColour("#FFFFFE")); StateColor btn_bg( std::pair(wxColour(27, 136, 68), StateColor::Pressed), @@ -101,10 +103,16 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons m_textCtrl_code->Bind(wxEVT_TEXT, &ConnectPrinterDialog::on_input_enter, this); m_button_confirm->Bind(wxEVT_BUTTON, &ConnectPrinterDialog::on_button_confirm, this); + wxGetApp().UpdateDlgDarkUI(this); } ConnectPrinterDialog::~ConnectPrinterDialog() {} +void ConnectPrinterDialog::end_modal(wxStandardID id) +{ + EndModal(id); +} + void ConnectPrinterDialog::init_bitmap() { AppConfig *config = get_app_config(); @@ -141,6 +149,7 @@ void ConnectPrinterDialog::on_button_confirm(wxCommandEvent &event) } if (m_obj) { m_obj->set_access_code(code.ToStdString()); + wxGetApp().getDeviceManager()->set_selected_machine(m_obj->dev_id); } EndModal(wxID_OK); } diff --git a/src/slic3r/GUI/ConnectPrinter.hpp b/src/slic3r/GUI/ConnectPrinter.hpp index 6f105dee1c..54f5021412 100644 --- a/src/slic3r/GUI/ConnectPrinter.hpp +++ b/src/slic3r/GUI/ConnectPrinter.hpp @@ -45,6 +45,7 @@ public: ~ConnectPrinterDialog(); + void end_modal(wxStandardID id); void init_bitmap(); void set_machine_object(MachineObject* obj); void on_input_enter(wxCommandEvent& evt); diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 4bc670b6fe..05ff4e63e8 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -279,6 +279,11 @@ std::string MachineObject::get_preset_printer_model_name(std::string printer_typ return DeviceManager::get_printer_display_name(printer_type); } +std::string MachineObject::get_preset_printer_thumbnail_img(std::string printer_type) +{ + return DeviceManager::get_printer_thumbnail_img(printer_type); +} + wxString MachineObject::get_printer_type_display_str() { std::string display_name = get_preset_printer_model_name(printer_type); @@ -288,6 +293,15 @@ wxString MachineObject::get_printer_type_display_str() return _L("Unknown"); } +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"; +} + void MachineObject::set_access_code(std::string code) { this->access_code = code; @@ -334,6 +348,8 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string ams_insert_flag = false; ams_power_on_flag = false; ams_support_use_ams = false; + ams_calibrate_remain_flag = false; + ams_humidity = 5; /* signals */ wifi_signal = ""; @@ -348,6 +364,7 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string cooling_fan_speed = 0; big_fan1_speed = 0; big_fan2_speed = 0; + fan_gear = 0; /* printing */ mc_print_stage = 0; @@ -360,6 +377,8 @@ MachineObject::MachineObject(NetworkAgent* agent, std::string name, std::string home_flag = -1; hw_switch_state = 0; printing_speed_lvl = PrintingSpeedLevel::SPEED_LEVEL_INVALID; + + has_ipcam = true; // default true } MachineObject::~MachineObject() @@ -402,6 +421,11 @@ bool MachineObject::check_valid_ip() return true; } +void MachineObject::_parse_print_option_ack(int option) +{ + xcam_auto_recovery_step_loss = ((option >> (int)PRINT_OP_AUTO_RECOVERY) & 0x01) != 0; +} + void MachineObject::_parse_tray_now(std::string tray_now) { m_tray_now = tray_now; @@ -481,6 +505,18 @@ void MachineObject::_parse_ams_status(int ams_status) BOOST_LOG_TRIVIAL(trace) << "ams_debug: main = " << ams_status_main_int << ", sub = " << ams_status_sub; } +bool MachineObject::can_unload_filament() +{ + bool result = false; + if (!has_ams()) + return true; + + if (ams_status_main == AMS_STATUS_MAIN_IDLE && hw_switch_state == 1 && m_tray_now == "255") { + return true; + } + return result; +} + bool MachineObject::is_U0_firmware() { auto ota_ver_it = module_vers.find("ota"); @@ -493,36 +529,42 @@ bool MachineObject::is_U0_firmware() bool MachineObject::is_support_ams_mapping() { - AppConfig* config = Slic3r::GUI::wxGetApp().app_config; - if (config) { - if (config->get("check_ams_version") == "0") - return false; - } - 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; - } + if (printer_type == "BL-P001" || printer_type == "BL-P002") { + AppConfig* config = Slic3r::GUI::wxGetApp().app_config; + if (config) { + if (config->get("check_ams_version") == "0") + return 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)) { + 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; } - return !need_upgrade; } 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; @@ -791,7 +833,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std std::vector cache_map_result = result; //check ams mapping result - if (is_valid_mapping_result(result)) { + if (is_valid_mapping_result(result, true)) { return 0; } @@ -819,7 +861,7 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std } //check order mapping result - if (is_valid_mapping_result(result)) { + if (is_valid_mapping_result(result, true)) { return 0; } } catch(...) { @@ -839,36 +881,39 @@ int MachineObject::ams_filament_mapping(std::vector filaments, std return 0; } -bool MachineObject::is_valid_mapping_result(std::vector& result) +bool MachineObject::is_valid_mapping_result(std::vector& result, bool check_empty_slot) { - if (is_support_ams_mapping()) { - bool valid_ams_mapping_result = true; - for (int i = 0; i < result.size(); i++) { - if (result[i].tray_id == -1) { - valid_ams_mapping_result = false; - break; - } - } - return valid_ams_mapping_result; - } else { - bool is_valid = true; + bool valid_ams_mapping_result = true; + if (result.empty()) return false; + + for (int i = 0; i < result.size(); i++) { // invalid mapping result - if (result.empty()) return false; - for (int i = 0; i < result.size(); i++) { - // invalid mapping result - if (result[i].tray_id < 0) - is_valid = false; - else { - int ams_id = result[i].tray_id / 4; - if (amsList.find(std::to_string(ams_id)) == amsList.end()) { - result[i].tray_id = -1; - is_valid = false; + if (result[i].tray_id < 0) + valid_ams_mapping_result = false; + else { + int ams_id = result[i].tray_id / 4; + auto ams_item = amsList.find(std::to_string(ams_id)); + if (ams_item == amsList.end()) { + result[i].tray_id = -1; + valid_ams_mapping_result = false; + } else { + if (check_empty_slot) { + int tray_id = result[i].tray_id % 4; + auto tray_item = ams_item->second->trayList.find(std::to_string(tray_id)); + if (tray_item == ams_item->second->trayList.end()) { + result[i].tray_id = -1; + valid_ams_mapping_result = false; + } else { + if (!tray_item->second->is_exists) { + result[i].tray_id = -1; + valid_ams_mapping_result = false; + } + } } } } - return is_valid; } - return true; + return valid_ams_mapping_result; } bool MachineObject::is_mapping_exceed_filament(std::vector & result, int &exceed_index) @@ -989,6 +1034,21 @@ std::string MachineObject::get_ota_version() return ""; } +bool MachineObject::check_version_valid() +{ + bool valid = true; + for (auto module : module_vers) { + if (module.second.sn.empty() + && module.first != "ota" + && module.first != "xm") + return false; + if (module.second.sw_ver.empty()) + return false; + } + get_version_retry = 0; + return valid; +} + wxString MachineObject::get_upgrade_result_str(int err_code) { switch(err_code) { @@ -1080,7 +1140,8 @@ int MachineObject::get_curr_stage_idx() bool MachineObject::is_in_calibration() { - if (boost::contains(m_gcode_file, "auto_cali_for_user.gcode") + // gcode file: auto_cali_for_user.gcode or auto_cali_for_user_param + if (boost::contains(m_gcode_file, "auto_cali_for_user") && stage_curr != 0) { return true; } else { @@ -1117,6 +1178,27 @@ void MachineObject::parse_state_changed_event() last_mc_print_stage = mc_print_stage; } +void MachineObject::parse_status(int flag) +{ + is_220V_voltage = ((flag >> 3) & 0x1) != 0; + if (xcam_auto_recovery_hold_count > 0) + xcam_auto_recovery_hold_count--; + else { + xcam_auto_recovery_step_loss = ((flag >> 4) & 0x1) != 0; + } + + camera_recording = ((flag >> 5) & 0x1) != 0; + ams_calibrate_remain_flag = ((flag >> 7) & 0x1) != 0; + + if (ams_print_option_count > 0) + ams_print_option_count--; + else { + ams_auto_switch_filament_flag = ((flag >> 10) & 0x1) != 0; + } + + sdcard_state = MachineObject::SdcardState((flag >> 8) & 0x11); +} + PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl) { if (lvl < (int)SPEED_LEVEL_COUNT) @@ -1125,6 +1207,22 @@ PrintingSpeedLevel MachineObject::_parse_printing_speed_lvl(int lvl) return PrintingSpeedLevel::SPEED_LEVEL_INVALID; } +int MachineObject::get_bed_temperature_limit() +{ + if (printer_type == "BL-P001" || printer_type == "BL-P002") { + if (is_220V_voltage) + return 110; + else { + return 120; + } + } else { + int limit = BED_TEMP_LIMIT; + DeviceManager::get_bed_temperature_limit(printer_type, limit); + return limit; + } + return BED_TEMP_LIMIT; +} + bool MachineObject::is_sdcard_printing() { if (can_abort() @@ -1138,26 +1236,38 @@ bool MachineObject::is_sdcard_printing() bool MachineObject::has_sdcard() { - return camera_has_sdcard; + return (sdcard_state == MachineObject::SdcardState::HAS_SDCARD_NORMAL); } -bool MachineObject::has_timelapse() +MachineObject::SdcardState MachineObject::get_sdcard_state() +{ + return sdcard_state; +} + +bool MachineObject::is_timelapse() { return camera_timelapse; } -bool MachineObject::has_recording() +bool MachineObject::is_recording_enable() +{ + return camera_recording_when_printing; +} + +bool MachineObject::is_recording() { return camera_recording; } -int MachineObject::command_get_version() +int MachineObject::command_get_version(bool with_retry) { BOOST_LOG_TRIVIAL(info) << "command_get_version"; json j; j["info"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["info"]["command"] = "get_version"; - return this->publish_json(j.dump()); + if (with_retry) + get_version_retry = GET_VERSION_RETRYS; + return this->publish_json(j.dump(), 1); } int MachineObject::command_request_push_all() @@ -1177,6 +1287,28 @@ int MachineObject::command_request_push_all() return this->publish_json(j.dump()); } +int MachineObject::command_pushing(std::string cmd) +{ + auto curr_time = std::chrono::system_clock::now(); + auto diff = std::chrono::duration_cast(curr_time - last_request_start); + if (diff.count() < REQUEST_START_MIN_TIME) { + BOOST_LOG_TRIVIAL(trace) << "static: command_request_start: send request too fast, dev_id=" << dev_id; + return -1; + } + else { + BOOST_LOG_TRIVIAL(trace) << "static: command_request_start, dev_id=" << dev_id; + last_request_start = std::chrono::system_clock::now(); + } + + if (cmd == "start" || cmd == "stop") { + json j; + j["pushing"]["command"] = cmd; + j["pushing"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + return this->publish_json(j.dump()); + } + return -1; +} + int MachineObject::command_upgrade_confirm() { BOOST_LOG_TRIVIAL(info) << "command_upgrade_confirm"; @@ -1214,6 +1346,19 @@ int MachineObject::command_upgrade_firmware(FirmwareInfo info) return this->publish_json(j.dump()); } +int MachineObject::command_upgrade_module(std::string url, std::string module_type, std::string version) +{ + json j; + j["upgrade"]["command"] = "start"; + j["upgrade"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["upgrade"]["url"] = url; + j["upgrade"]["module"] = module_type; + j["upgrade"]["version"] = version; + j["upgrade"]["src_id"] = 1; + + return this->publish_json(j.dump()); +} + int MachineObject::command_xyz_abs() { return this->publish_gcode("G90 \n"); @@ -1235,6 +1380,13 @@ int MachineObject::command_control_fan(FanType fan_type, bool on_off) return this->publish_gcode(gcode); } +int MachineObject::command_control_fan_val(FanType fan_type, int val) +{ + std::string gcode = (boost::format("M106 P%1% S%2% \n") % (int)fan_type % (val)).str(); + return this->publish_gcode(gcode); +} + + int MachineObject::command_task_abort() { json j; @@ -1318,22 +1470,46 @@ int MachineObject::command_ams_change_filament(int tray_id, int old_temp, int ne return this->publish_json(j.dump()); } -int MachineObject::command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt) +int MachineObject::command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt, bool remain_flag) { json j; j["print"]["command"] = "ams_user_setting"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["print"]["ams_id"] = ams_id; - j["print"]["startup_read_option"] = start_read_opt; - j["print"]["tray_read_option"] = tray_read_opt; + j["print"]["startup_read_option"] = start_read_opt; + j["print"]["tray_read_option"] = tray_read_opt; + j["print"]["calibrate_remain_flag"] = remain_flag; ams_insert_flag = tray_read_opt; ams_power_on_flag = start_read_opt; + ams_calibrate_remain_flag = remain_flag; ams_user_setting_hold_count = HOLD_COUNT_MAX; return this->publish_json(j.dump()); } +int MachineObject::command_ams_user_settings(int ams_id, AmsOptionType op, bool value) +{ + json j; + j["print"]["command"] = "ams_user_setting"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["ams_id"] = ams_id; + if (op == AmsOptionType::AMS_OP_STARTUP_READ) { + j["print"]["startup_read_option"] = value; + ams_power_on_flag = value; + } else if (op == AmsOptionType::AMS_OP_TRAY_READ) { + j["print"]["tray_read_option"] = value; + ams_insert_flag = value; + } else if (op == AmsOptionType::AMS_OP_CALIBRATE_REMAIN) { + j["print"]["calibrate_remain_flag"] = value; + ams_calibrate_remain_flag = value; + } else { + return -1; + } + ams_user_setting_hold_count = HOLD_COUNT_MAX; + return this->publish_json(j.dump()); +} + int MachineObject::command_ams_calibrate(int ams_id) { std::string gcode_cmd = (boost::format("M620 C%1% \n") % ams_id).str(); @@ -1343,6 +1519,8 @@ int MachineObject::command_ams_calibrate(int ams_id) int MachineObject::command_ams_filament_settings(int ams_id, int tray_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max) { + BOOST_LOG_TRIVIAL(info) << "command_ams_filament_settings, ams_id = " << ams_id << ", tray_id = " << tray_id << ", tray_color = " << tray_color + << ", tray_type = " << tray_type; json j; j["print"]["command"] = "ams_filament_setting"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); @@ -1426,6 +1604,32 @@ int MachineObject::command_set_printing_speed(PrintingSpeedLevel lvl) return this->publish_json(j.dump()); } +int MachineObject::command_set_printing_option(bool auto_recovery) +{ + int print_option = (int)auto_recovery << (int)PRINT_OP_AUTO_RECOVERY; + json j; + j["print"]["command"] = "print_option"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["option"] = print_option; + j["print"]["auto_recovery"] = auto_recovery; + + return this->publish_json(j.dump()); +} + +int MachineObject::command_ams_switch_filament(bool switch_filament) +{ + json j; + j["print"]["command"] = "print_option"; + j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["auto_switch_filament"] = switch_filament; + + ams_auto_switch_filament_flag = switch_filament; + BOOST_LOG_TRIVIAL(trace) << "command_ams_filament_settings:" << switch_filament; + ams_print_option_count = HOLD_COUNT_MAX; + + return this->publish_json(j.dump()); +} + int MachineObject::command_axis_control(std::string axis, double unit, double value, int speed) { char cmd[256]; @@ -1436,6 +1640,7 @@ int MachineObject::command_axis_control(std::string axis, double unit, double va } else if (axis.compare("E") == 0) { sprintf(cmd, "M83 \nG0 %s%0.1f F%d\n", axis.c_str(), value * unit, speed); + extruder_axis_status = (value >= 0.0f)? LOAD : UNLOAD; } else { return -1; @@ -1443,10 +1648,23 @@ int MachineObject::command_axis_control(std::string axis, double unit, double va return this->publish_gcode(cmd); } -int MachineObject::command_start_calibration() + +bool MachineObject::is_support_command_calibration() { if (printer_type == "BL-P001" || printer_type == "BL-P002") { + auto ap_ver_it = module_vers.find("rv1126"); + if (ap_ver_it != module_vers.end()) { + if (ap_ver_it->second.sw_ver.compare("00.00.15.79") < 0) + return false; + } + } + return true; +} + +int MachineObject::command_start_calibration(bool vibration, bool bed_leveling, bool xcam_cali) +{ + if (!is_support_command_calibration()) { // fixed gcode file json j; j["print"]["command"] = "gcode_file"; @@ -1457,6 +1675,9 @@ int MachineObject::command_start_calibration() json j; j["print"]["command"] = "calibration"; j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["print"]["option"] = (vibration ? 1 << 2 : 0) + + (bed_leveling ? 1 << 1 : 0) + + (xcam_cali ? 1 << 0 : 0); return this->publish_json(j.dump()); } } @@ -1483,46 +1704,86 @@ int MachineObject::command_unload_filament() int MachineObject::command_ipcam_record(bool on_off) { + BOOST_LOG_TRIVIAL(info) << "command_ipcam_record = " << on_off; json j; j["camera"]["command"] = "ipcam_record_set"; j["camera"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["camera"]["control"] = on_off ? "enable" : "disable"; + camera_recording_hold_count = HOLD_COUNT_CAMERA; + this->camera_recording_when_printing = on_off; return this->publish_json(j.dump()); } int MachineObject::command_ipcam_timelapse(bool on_off) { + BOOST_LOG_TRIVIAL(info) << "command_ipcam_timelapse " << on_off; json j; j["camera"]["command"] = "ipcam_timelapse"; j["camera"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["camera"]["control"] = on_off ? "enable" : "disable"; + camera_timelapse_hold_count = HOLD_COUNT_CAMERA; + this->camera_timelapse = on_off; return this->publish_json(j.dump()); } -int MachineObject::command_xcam_control(std::string module_name, bool on_off, bool print_halt) +int MachineObject::command_ipcam_resolution_set(std::string resolution) +{ + BOOST_LOG_TRIVIAL(info) << "command:ipcam_resolution_set" << ", resolution:" << resolution; + json j; + j["camera"]["command"] = "ipcam_resolution_set"; + j["camera"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); + j["camera"]["resolution"] = resolution; + camera_resolution_hold_count = HOLD_COUNT_CAMERA; + camera_recording_hold_count = HOLD_COUNT_CAMERA; + this->camera_resolution = resolution; + return this->publish_json(j.dump()); +} + +int MachineObject::command_xcam_control(std::string module_name, bool on_off, std::string lvl) { json j; j["xcam"]["command"] = "xcam_control_set"; j["xcam"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++); j["xcam"]["module_name"] = module_name; j["xcam"]["control"] = on_off; - j["xcam"]["print_halt"] = print_halt; + j["xcam"]["enable"] = on_off; //old protocol + j["xcam"]["print_halt"] = true; //old protocol + if (!lvl.empty()) { + j["xcam"]["halt_print_sensitivity"] = lvl; + } + BOOST_LOG_TRIVIAL(info) << "command:xcam_control_set" << ", module_name:" << module_name << ", control:" << on_off << ", halt_print_sensitivity:" << lvl; return this->publish_json(j.dump()); } +int MachineObject::command_xcam_control_ai_monitoring(bool on_off, std::string lvl) +{ + bool print_halt = (lvl == "never_halt") ? false:true; + + xcam_ai_monitoring = on_off; + xcam_ai_monitoring_hold_count = HOLD_COUNT_MAX; + xcam_ai_monitoring_sensitivity = lvl; + return command_xcam_control("printing_monitor", on_off, lvl); +} + +int MachineObject::command_xcam_control_buildplate_marker_detector(bool on_off) +{ + xcam_buildplate_marker_detector = on_off; + xcam_buildplate_marker_hold_count = HOLD_COUNT_MAX; + return command_xcam_control("buildplate_marker_detector", on_off); +} + int MachineObject::command_xcam_control_first_layer_inspector(bool on_off, bool print_halt) { xcam_first_layer_inspector = on_off; xcam_first_layer_hold_count = HOLD_COUNT_MAX; - return command_xcam_control("first_layer_inspector", on_off, print_halt); + return command_xcam_control("first_layer_inspector", on_off); } -int MachineObject::command_xcam_control_spaghetti_detector(bool on_off, bool print_halt) +int MachineObject::command_xcam_control_auto_recovery_step_loss(bool on_off) { - xcam_spaghetti_detector = on_off; - xcam_spaghetti_print_halt = print_halt; - xcam_spaghetti_hold_count = HOLD_COUNT_MAX; - return command_xcam_control("spaghetti_detector", on_off, print_halt); + xcam_auto_recovery_step_loss = on_off; + xcam_auto_recovery_hold_count = HOLD_COUNT_MAX; + return command_set_printing_option(on_off); } void MachineObject::set_bind_status(std::string status) @@ -1576,6 +1837,7 @@ bool MachineObject::is_in_printing_status(std::string status) { if (status.compare("PAUSE") == 0 || status.compare("RUNNING") == 0 + || status.compare("SLICING") == 0 || status.compare("PREPARE") == 0) { return true; } @@ -1618,14 +1880,19 @@ void MachineObject::reset() BOOST_LOG_TRIVIAL(trace) << "reset dev_id=" << dev_id; last_update_time = std::chrono::system_clock::now(); m_push_count = 0; + is_220V_voltage = false; + get_version_retry = 0; camera_recording = false; + camera_recording_when_printing = false; camera_timelapse = false; + camera_resolution = ""; printing_speed_mag = 100; gcode_file_prepare_percent = 0; iot_print_status = ""; print_status = ""; last_mc_print_stage = -1; m_new_ver_list_exist = false; + extruder_axis_status = LOAD; subtask_ = nullptr; @@ -1719,8 +1986,14 @@ bool MachineObject::is_function_supported(PrinterFunction func) case FUNC_FIRSTLAYER_INSPECT: func_name = "FUNC_FIRSTLAYER_INSPECT"; break; - case FUNC_SPAGHETTI: - func_name = "FUNC_SPAGHETTI"; + case FUNC_AI_MONITORING: + func_name = "FUNC_AI_MONITORING"; + break; + case FUNC_BUILDPLATE_MARKER_DETECT: + func_name = "FUNC_BUILDPLATE_MARKER_DETECT"; + break; + case FUNC_AUTO_RECOVERY_STEP_LOSS: + func_name = "FUNC_AUTO_RECOVERY_STEP_LOSS"; break; case FUNC_FLOW_CALIBRATION: func_name = "FUNC_FLOW_CALIBRATION"; @@ -1746,12 +2019,35 @@ bool MachineObject::is_function_supported(PrinterFunction func) 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: + func_name = "FUNC_SEND_TO_SDCARD"; + break; + case FUNC_AUTO_SWITCH_FILAMENT: + 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; 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); +} + bool MachineObject::is_support_print_with_timelapse() { //TODO version check, set true by default @@ -1798,8 +2094,9 @@ int MachineObject::parse_json(std::string payload) bool restored_json = false; json j; json j_pre = json::parse(payload); - if (j_pre.empty()) + if (j_pre.empty()) { return 0; + } if (j_pre.contains("print")) { if (j_pre["print"].contains("command")) { @@ -1822,6 +2119,7 @@ int MachineObject::parse_json(std::string payload) }); return -1; } + return -1; } } else { BOOST_LOG_TRIVIAL(warning) << "unsupported msg_type=" << j_pre["print"]["msg"].get(); @@ -1851,6 +2149,7 @@ int MachineObject::parse_json(std::string payload) if (jj.contains("home_flag")) { home_flag = jj["home_flag"].get(); + parse_status(home_flag); } if (jj.contains("hw_switch_state")) { hw_switch_state = jj["hw_switch_state"].get(); @@ -1913,6 +2212,15 @@ int MachineObject::parse_json(std::string payload) online_rfid = false; } } + if (jj["online"].contains("version")) { + online_version = jj["online"]["version"].get(); + } + if (last_online_version != online_version) { + last_online_version = online_version; + GUI::wxGetApp().CallAfter([this] { + this->command_get_version(); + }); + } } } catch (...) { ; @@ -2022,18 +2330,42 @@ int MachineObject::parse_json(std::string payload) wifi_signal = jj["wifi_signal"].get(); /* cooling */ - if (jj.contains("cooling_fan_speed")) { - cooling_fan_speed = stoi(jj["cooling_fan_speed"].get()); + if (jj.contains("fan_gear")) { + fan_gear = jj["fan_gear"].get(); + big_fan2_speed = (int)((fan_gear & 0x00FF0000) >> 16); + big_fan1_speed = (int)((fan_gear & 0x0000FF00) >> 8); + cooling_fan_speed= (int)((fan_gear & 0x000000FF) >> 0); } - if (jj.contains("big_fan1_speed")) { - big_fan1_speed = stoi(jj["big_fan1_speed"].get()); - } - if (jj.contains("big_fan2_speed")) { - big_fan2_speed = stoi(jj["big_fan2_speed"].get()); + else { + if (jj.contains("cooling_fan_speed")) { + cooling_fan_speed = stoi(jj["cooling_fan_speed"].get()); + cooling_fan_speed = round( floor(cooling_fan_speed / float(1.5)) * float(25.5) ); + } + else { + cooling_fan_speed = 0; + } + + if (jj.contains("big_fan1_speed")) { + big_fan1_speed = stoi(jj["big_fan1_speed"].get()); + big_fan1_speed = round( floor(big_fan1_speed / float(1.5)) * float(25.5) ); + } + else { + big_fan1_speed = 0; + } + + if (jj.contains("big_fan2_speed")) { + big_fan2_speed = stoi(jj["big_fan2_speed"].get()); + big_fan2_speed = round( floor(big_fan2_speed / float(1.5)) * float(25.5) ); + } + else { + big_fan2_speed = 0; + } } + if (jj.contains("heatbreak_fan_speed")) { heatbreak_fan_speed = stoi(jj["heatbreak_fan_speed"].get()); } + /* parse speed */ try { if (jj.contains("spd_lvl")) { @@ -2095,10 +2427,13 @@ int MachineObject::parse_json(std::string payload) // media try { if (jj.contains("sdcard")) { - camera_has_sdcard = jj["sdcard"].get(); + if (jj["sdcard"].get()) + sdcard_state = MachineObject::SdcardState::HAS_SDCARD_NORMAL; + else + sdcard_state = MachineObject::SdcardState::NO_SDCARD; } else { //do not check sdcard if no sdcard field - camera_has_sdcard = false; + sdcard_state = MachineObject::SdcardState::NO_SDCARD; } } catch (...) { @@ -2201,19 +2536,27 @@ int MachineObject::parse_json(std::string payload) try { if (jj.contains("ipcam")) { if (jj["ipcam"].contains("ipcam_record")) { - if (jj["ipcam"]["ipcam_record"].get() == "enable") { - camera_recording = true; - } + if (camera_recording_hold_count > 0) + camera_recording_hold_count--; else { - camera_recording = false; + if (jj["ipcam"]["ipcam_record"].get() == "enable") { + camera_recording_when_printing = true; + } + else { + camera_recording_when_printing = false; + } } } if (jj["ipcam"].contains("timelapse")) { - if (jj["ipcam"]["timelapse"].get() == "enable") { - camera_timelapse = true; - } + if (camera_timelapse_hold_count > 0) + camera_timelapse_hold_count--; else { - camera_timelapse = false; + if (jj["ipcam"]["timelapse"].get() == "enable") { + camera_timelapse = true; + } + else { + camera_timelapse = false; + } } } if (jj["ipcam"].contains("ipcam_dev")) { @@ -2223,6 +2566,13 @@ int MachineObject::parse_json(std::string payload) has_ipcam = false; } } + if (jj["ipcam"].contains("resolution")) { + if (camera_resolution_hold_count > 0) + camera_resolution_hold_count--; + else { + camera_resolution = jj["ipcam"]["resolution"].get(); + } + } } } catch (...) { @@ -2231,6 +2581,27 @@ int MachineObject::parse_json(std::string payload) try { if (jj.contains("xcam")) { + if (xcam_ai_monitoring_hold_count > 0) + xcam_ai_monitoring_hold_count--; + else { + if (jj["xcam"].contains("printing_monitor")) { + // new protocol + xcam_ai_monitoring = jj["xcam"]["printing_monitor"].get(); + } else { + // old version protocol + if (jj["xcam"].contains("spaghetti_detector")) { + xcam_ai_monitoring = jj["xcam"]["spaghetti_detector"].get(); + if (jj["xcam"].contains("print_halt")) { + bool print_halt = jj["xcam"]["print_halt"].get(); + if (print_halt) { xcam_ai_monitoring_sensitivity = "medium"; } + } + } + } + if (jj["xcam"].contains("halt_print_sensitivity")) { + xcam_ai_monitoring_sensitivity = jj["xcam"]["halt_print_sensitivity"].get(); + } + } + if (xcam_first_layer_hold_count > 0) xcam_first_layer_hold_count--; else { @@ -2239,14 +2610,11 @@ int MachineObject::parse_json(std::string payload) } } - if (xcam_spaghetti_hold_count > 0) { - xcam_spaghetti_hold_count--; - } else { - if (jj["xcam"].contains("spaghetti_detector")) { - xcam_spaghetti_detector = jj["xcam"]["spaghetti_detector"].get(); - } - if (jj["xcam"].contains("print_halt")) { - xcam_spaghetti_print_halt = jj["xcam"]["print_halt"].get(); + if (xcam_buildplate_marker_hold_count > 0) + xcam_buildplate_marker_hold_count--; + else { + if (jj["xcam"].contains("buildplate_marker_detector")) { + xcam_buildplate_marker_detector = jj["xcam"]["buildplate_marker_detector"].get(); } } } @@ -2327,8 +2695,19 @@ int MachineObject::parse_json(std::string payload) } if (jj["ams"].contains("ams_rfid_status")) ams_rfid_status = jj["ams"]["ams_rfid_status"].get(); + if (jj["ams"].contains("humidity")) { + if (jj["ams"]["humidity"].is_string()) { + std::string humidity_str = jj["ams"]["humidity"].get(); + try { + ams_humidity = atoi(humidity_str.c_str()); + } catch (...) { + ; + } + } + } - if (jj["ams"].contains("insert_flag") || jj["ams"].contains("power_on_flag")) { + if (jj["ams"].contains("insert_flag") || jj["ams"].contains("power_on_flag") + || jj["ams"].contains("calibrate_remain_flag")) { if (ams_user_setting_hold_count > 0) { ams_user_setting_hold_count--; } else { @@ -2338,6 +2717,9 @@ int MachineObject::parse_json(std::string payload) if (jj["ams"].contains("power_on_flag")) { ams_power_on_flag = jj["ams"]["power_on_flag"].get(); } + if (jj["ams"].contains("calibrate_remain_flag")) { + ams_calibrate_remain_flag = jj["ams"]["calibrate_remain_flag"].get(); + } } } if (ams_exist_bits != last_ams_exist_bits @@ -2381,6 +2763,18 @@ int MachineObject::parse_json(std::string payload) } if (!curr_ams) continue; + if (it->contains("humidity")) { + std::string humidity = (*it)["humidity"].get(); + + try { + curr_ams->humidity = atoi(humidity.c_str()); + } + catch (...) { + ; + } + } + + if (it->contains("tray")) { std::set tray_id_set; for (auto it = curr_ams->trayList.begin(); it != curr_ams->trayList.end(); it++) { @@ -2478,6 +2872,9 @@ int MachineObject::parse_json(std::string payload) } else { curr_tray->color = ""; } + if (tray_it->contains("remain")) { + curr_tray->remain = (*tray_it)["remain"].get(); + } try { if (!ams_id.empty() && !curr_tray->id.empty()) { int ams_id_int = atoi(ams_id.c_str()); @@ -2527,11 +2924,14 @@ int MachineObject::parse_json(std::string payload) } } } else if (jj["command"].get() == "ams_filament_setting") { + // BBS trigger ams UI update + ams_version = -1; + if (jj["ams_id"].is_number()) { int ams_id = jj["ams_id"].get(); auto ams_it = amsList.find(std::to_string(ams_id)); if (ams_it != amsList.end()) { - int tray_id = jj["tray_id"].get() - ams_id * 4; + int tray_id = jj["tray_id"].get(); auto tray_it = ams_it->second->trayList.find(std::to_string(tray_id)); if (tray_it != ams_it->second->trayList.end()) { BOOST_LOG_TRIVIAL(trace) << "ams_filament_setting, parse tray info"; @@ -2550,17 +2950,57 @@ int MachineObject::parse_json(std::string payload) } } } else if (jj["command"].get() == "xcam_control_set") { - if (jj.contains("module_name") && jj.contains("control")) { - if (jj["module_name"].get() == "first_layer_inspector") { - xcam_first_layer_inspector = jj["control"].get(); - xcam_first_layer_hold_count = HOLD_COUNT_MAX; - } else if (jj["module_name"].get() == "spaghetti_detector") { - xcam_spaghetti_detector = jj["control"].get(); - xcam_spaghetti_hold_count = HOLD_COUNT_MAX; - if (jj.contains("print_halt")) - xcam_spaghetti_print_halt = jj["print_halt"].get(); + if (jj.contains("module_name")) { + if (jj.contains("enable") || jj.contains("control")) { + bool enable = false; + if (jj.contains("enable")) + enable = jj["enable"].get(); + else if (jj.contains("control")) + enable = jj["control"].get(); + else { + ; + } + + if (jj["module_name"].get() == "first_layer_inspector") { + xcam_first_layer_inspector = enable; + xcam_first_layer_hold_count = HOLD_COUNT_MAX; + } + else if (jj["module_name"].get() == "buildplate_marker_detector") { + xcam_buildplate_marker_detector = enable; + xcam_buildplate_marker_hold_count = HOLD_COUNT_MAX; + } + else if (jj["module_name"].get() == "printing_monitor") { + xcam_ai_monitoring = enable; + xcam_ai_monitoring_hold_count = HOLD_COUNT_MAX; + if (jj.contains("halt_print_sensitivity")) { + xcam_ai_monitoring_sensitivity = jj["halt_print_sensitivity"].get(); + } + } + else if (jj["module_name"].get() == "spaghetti_detector") { + // old protocol + xcam_ai_monitoring = enable; + xcam_ai_monitoring_hold_count = HOLD_COUNT_MAX; + if (jj.contains("print_halt")) { + if (jj["print_halt"].get()) + xcam_ai_monitoring_sensitivity = "medium"; + } + } } } + }else if(jj["command"].get() == "print_option") { + try { + if (jj.contains("option")) { + if (jj["option"].is_number()) { + int option = jj["option"].get(); + _parse_print_option_ack(option); + } + } + if (jj.contains("auto_recovery")) { + xcam_auto_recovery_step_loss = jj["auto_recovery"].get(); + } + } + catch(...) { + } } } } @@ -2581,6 +3021,20 @@ int MachineObject::parse_json(std::string payload) ver_info.hw_ver = (*it)["hw_ver"].get(); module_vers.emplace(ver_info.name, ver_info); } + 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 (...) {} @@ -2593,11 +3047,16 @@ int MachineObject::parse_json(std::string payload) this->camera_timelapse = true; if (j["camera"]["control"].get() == "disable") this->camera_timelapse = false; + BOOST_LOG_TRIVIAL(info) << "ack of timelapse = " << camera_timelapse; } else if (j["camera"]["command"].get() == "ipcam_record_set") { if (j["camera"]["control"].get() == "enable") - this->camera_recording = true; + this->camera_recording_when_printing = true; if (j["camera"]["control"].get() == "disable") - this->camera_recording = false; + this->camera_recording_when_printing = false; + BOOST_LOG_TRIVIAL(info) << "ack of ipcam_record_set " << camera_recording_when_printing; + } else if (j["camera"]["command"].get() == "ipcam_resolution_set") { + this->camera_resolution = j["camera"]["resolution"].get(); + BOOST_LOG_TRIVIAL(info) << "ack of resolution = " << camera_resolution; } } } @@ -2836,6 +3295,19 @@ void DeviceManager::set_agent(NetworkAgent* agent) m_agent = agent; } +void DeviceManager::check_pushing() +{ + MachineObject* obj = this->get_selected_machine(); + if (obj) { + std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); + auto internal = std::chrono::duration_cast(start - obj->last_update_time); + if (internal.count() > TIMEOUT_FOR_STRAT && internal.count() < 1000 * 60 * 60 * 300) { + BOOST_LOG_TRIVIAL(info) << "command_pushing: diff = " << internal.count(); + obj->command_pushing("start"); + } + } +} + void DeviceManager::on_machine_alive(std::string json_str) { try { @@ -2872,6 +3344,7 @@ void DeviceManager::on_machine_alive(std::string json_str) obj->wifi_signal = printer_signal; obj->dev_connection_type = connect_type; obj->bind_state = bind_state; + obj->printer_type = MachineObject::parse_printer_type(printer_type_str); // U0 firmware if (obj->dev_connection_type.empty() && obj->bind_state.empty()) @@ -3034,9 +3507,19 @@ bool DeviceManager::set_selected_machine(std::string dev_id) auto it = my_machine_list.find(dev_id); if (it != my_machine_list.end()) { if (selected_machine == dev_id) { - // only reset update time - it->second->reset_update_time(); - return true; + if (it->second->connection_type() != "lan") { + // only reset update time + it->second->reset_update_time(); + return true; + } else { + // lan mode printer reconnect printer + if (m_agent) { + m_agent->disconnect_printer(); + it->second->reset(); + it->second->connect(); + it->second->set_lan_mode_connection_state(true); + } + } } else { if (m_agent) { if (it->second->connection_type() != "lan" || it->second->connection_type().empty()) { @@ -3051,6 +3534,7 @@ bool DeviceManager::set_selected_machine(std::string dev_id) m_agent->disconnect_printer(); it->second->reset(); it->second->connect(); + it->second->set_lan_mode_connection_state(true); } } } @@ -3267,6 +3751,20 @@ std::string DeviceManager::get_printer_display_name(std::string type_str) return ""; } +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 ""; +} + bool DeviceManager::is_function_supported(std::string type_str, std::string function_name) { if (DeviceManager::function_table.contains("printers")) { @@ -3282,6 +3780,38 @@ bool DeviceManager::is_function_supported(std::string type_str, std::string func return true; } +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) { + if (printer.contains("camera_resolution")) { + for (auto res : printer["camera_resolution"]) + resolution_supported.emplace_back(res.get()); + } + } + } + } + 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::load_functional_config(std::string config_file) { std::ifstream json_file(config_file.c_str()); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index cf4573fce4..2eb3095f80 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -11,18 +11,25 @@ #include "libslic3r/ProjectTask.hpp" #include "slic3r/Utils/json_diff.hpp" #include "slic3r/Utils/NetworkAgent.hpp" +#include "CameraPopup.hpp" #define USE_LOCAL_SOCKET_BIND 0 #define DISCONNECT_TIMEOUT 30000.f // milliseconds #define PUSHINFO_TIMEOUT 15000.f // milliseconds +#define TIMEOUT_FOR_STRAT 20000.f // milliseconds #define REQUEST_PUSH_MIN_TIME 15000.f // milliseconds +#define REQUEST_START_MIN_TIME 15000.f // milliseconds #define FILAMENT_MAX_TEMP 300 #define FILAMENT_DEF_TEMP 220 #define FILAMENT_MIN_TEMP 120 +#define BED_TEMP_LIMIT 120 #define HOLD_COUNT_MAX 3 +#define HOLD_COUNT_CAMERA 6 +#define GET_VERSION_RETRYS 10 +#define RETRY_INTERNAL 2000 inline int correct_filament_temperature(int filament_temp) { @@ -61,7 +68,9 @@ enum PrinterFunction { FUNC_TIMELAPSE, FUNC_RECORDING, FUNC_FIRSTLAYER_INSPECT, - FUNC_SPAGHETTI, + FUNC_AI_MONITORING, + FUNC_BUILDPLATE_MARKER_DETECT, + FUNC_AUTO_RECOVERY_STEP_LOSS, FUNC_FLOW_CALIBRATION, FUNC_AUTO_LEVELING, FUNC_CHAMBER_TEMP, @@ -70,6 +79,12 @@ enum PrinterFunction { 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_MAX }; @@ -126,6 +141,12 @@ enum AmsRfidStatus { AMS_RFID_HAS_FILAMENT = 6 }; +enum AmsOptionType { + AMS_OP_STARTUP_READ, + AMS_OP_TRAY_READ, + AMS_OP_CALIBRATE_REMAIN +}; + class AmsTray { public: AmsTray(std::string tray_id) { @@ -177,6 +198,7 @@ public: bool is_bbl; bool is_exists = false; int hold_count = 0; + int remain = 0; // filament remain: 0 ~ 100 AmsRoadPosition road_position; AmsStep step_state; @@ -199,6 +221,7 @@ public: id = ams_id; } std::string id; + int humidity = 5; bool startup_read_opt{true}; bool tray_read_opt{false}; bool is_exists{false}; @@ -288,6 +311,8 @@ private: NetworkAgent* m_agent { nullptr }; bool check_valid_ip(); + void _parse_print_option_ack(int option); + public: enum LIGHT_EFFECT { @@ -310,6 +335,18 @@ public: UpgradingFinished = 3 }; + enum ExtruderAxisStatus { + LOAD = 0, + UNLOAD =1, + STATUS_NUMS = 2 + }; + enum ExtruderAxisStatus extruder_axis_status = LOAD; + + enum PrintOption { + PRINT_OP_AUTO_RECOVERY = 0, + PRINT_OP_MAX, + }; + class ModuleVersionInfo { public: @@ -320,10 +357,18 @@ public: std::string sw_new_ver; }; + enum SdcardState { + NO_SDCARD = 0, + HAS_SDCARD_NORMAL = 1, + HAS_SDCARD_ABNORMAL = 2, + SDCARD_STATE_NUM = 3 + }; + /* static members and functions */ static inline int m_sequence_id = 20000; static std::string parse_printer_type(std::string type_str); static std::string get_preset_printer_model_name(std::string printer_type); + static std::string get_preset_printer_thumbnail_img(std::string printer_type); static bool is_bbl_filament(std::string tag_uid); typedef std::function UploadedFn; @@ -343,8 +388,13 @@ public: bool is_lan_mode_printer(); //PRINTER_TYPE printer_type = PRINTER_3DPrinter_UKNOWN; std::string printer_type; /* model_id */ + + 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::string bind_user_name; @@ -353,10 +403,14 @@ public: bool is_avaliable() { return bind_state == "free"; } time_t last_alive; bool m_is_online; + bool m_lan_mode_connection_state{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;}; int parse_msg_count = 0; std::chrono::system_clock::time_point last_update_time; /* last received print data from machine */ std::chrono::system_clock::time_point last_push_time; /* last received print push from machine */ std::chrono::system_clock::time_point last_request_push; /* last received print push from machine */ + std::chrono::system_clock::time_point last_request_start; /* last received print push from machine */ /* ams properties */ std::map amsList; // key: ams[id], start with 0 @@ -368,7 +422,10 @@ public: int ams_rfid_status = 0; bool ams_insert_flag { false }; bool ams_power_on_flag { false }; + bool ams_calibrate_remain_flag { false }; + bool ams_auto_switch_filament_flag { false }; bool ams_support_use_ams { false }; + int ams_humidity; int ams_user_setting_hold_count = 0; AmsStatusMain ams_status_main; int ams_status_sub; @@ -388,13 +445,14 @@ public: // parse amsStatusMain and ams_status_sub 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_only_support_cloud_print(); 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 is_valid_mapping_result(std::vector& result, bool check_empty_slot = false); // exceed index start with 0 bool is_mapping_exceed_filament(std::vector& result, int &exceed_index); void reset_mapping_result(std::vector& result); @@ -402,6 +460,8 @@ public: /*online*/ bool online_rfid; bool online_ahb; + int online_version = -1; + int last_online_version = -1; /* temperature */ float nozzle_temp; @@ -416,6 +476,7 @@ public: int cooling_fan_speed = 0; int big_fan1_speed = 0; int big_fan2_speed = 0; + uint32_t fan_gear = 0; /* signals */ std::string wifi_signal; @@ -431,7 +492,7 @@ public: /* upgrade */ bool upgrade_force_upgrade { false }; bool upgrade_new_version { false }; - bool upgrade_consistency_request; + bool upgrade_consistency_request { false }; int upgrade_display_state = 0; // 0 : upgrade unavailable, 1: upgrade idle, 2: upgrading, 3: upgrade_finished PrinterFirmwareType firmware_type; // engineer|production std::string upgrade_progress; @@ -441,6 +502,7 @@ public: std::string ams_new_version_number; std::string ota_new_version_number; std::string ahb_new_version_number; + int get_version_retry = 0; std::map module_vers; std::map new_ver_list; bool m_new_ver_list_exist = false; @@ -452,12 +514,17 @@ public: bool is_upgrading_avalable(); int get_upgrade_percent(); std::string get_ota_version(); + bool check_version_valid(); wxString get_upgrade_result_str(int upgrade_err_code); // key: ams_id start as 0,1,2,3 std::map get_ams_version(); /* printing */ std::string print_type; + float nozzle { 0.0f }; + bool is_220V_voltage { false }; + + int mc_print_stage; int mc_print_sub_stage; int mc_print_error_code; @@ -487,6 +554,7 @@ public: bool is_calibration_done(); void parse_state_changed_event(); + void parse_status(int flag); /* printing status */ std::string print_status; /* enum string: FINISH, RUNNING, PAUSE, INIT, FAILED */ @@ -494,17 +562,32 @@ public: PrintingSpeedLevel printing_speed_lvl; int printing_speed_mag = 100; PrintingSpeedLevel _parse_printing_speed_lvl(int lvl); + int get_bed_temperature_limit(); /* camera */ bool has_ipcam { false }; bool camera_recording { false }; + bool camera_recording_when_printing { false }; bool camera_timelapse { false }; - bool camera_has_sdcard { false }; + int camera_recording_hold_count = 0; + int camera_timelapse_hold_count = 0; + int camera_resolution_hold_count = 0; + std::string camera_resolution = ""; bool xcam_first_layer_inspector { false }; int xcam_first_layer_hold_count = 0; - bool xcam_spaghetti_detector { false }; - bool xcam_spaghetti_print_halt{ false }; - int xcam_spaghetti_hold_count = 0; + + bool xcam_ai_monitoring{ false }; + int xcam_ai_monitoring_hold_count = 0; + std::string xcam_ai_monitoring_sensitivity; + bool xcam_buildplate_marker_detector{ false }; + int xcam_buildplate_marker_hold_count = 0; + bool xcam_auto_recovery_step_loss{ false }; + int xcam_auto_recovery_hold_count = 0; + int ams_print_option_count = 0; + + /* sdcard */ + MachineObject::SdcardState sdcard_state { NO_SDCARD }; + MachineObject::SdcardState get_sdcard_state(); /* HMS */ std::vector hms_list; @@ -523,6 +606,7 @@ public: BBLSliceInfo* slice_info {nullptr}; boost::thread* get_slice_info_thread { nullptr }; + int plate_index { -1 }; std::string m_gcode_file; int gcode_file_prepare_percent = 0; @@ -531,26 +615,30 @@ public: std::string subtask_name; bool is_sdcard_printing(); bool has_sdcard(); - bool has_timelapse(); - bool has_recording(); + bool is_timelapse(); + bool is_recording_enable(); + bool is_recording(); MachineObject(NetworkAgent* agent, std::string name, std::string id, std::string ip); ~MachineObject(); /* command commands */ - int command_get_version(); + int command_get_version(bool with_retry = true); int command_request_push_all(); + int command_pushing(std::string cmd); /* command upgrade */ int command_upgrade_confirm(); int command_consistency_upgrade_confirm(); int command_upgrade_firmware(FirmwareInfo info); + int command_upgrade_module(std::string url, std::string module_type, std::string version); /* control apis */ int command_xyz_abs(); int command_auto_leveling(); int command_go_home(); int command_control_fan(FanType fan_type, bool on_off); + int command_control_fan_val(FanType fan_type, int val); int command_task_abort(); int command_task_pause(); int command_task_resume(); @@ -559,7 +647,9 @@ public: // ams controls int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210); int command_ams_change_filament(int tray_id, int old_temp = 210, int new_temp = 210); - int command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt); + int command_ams_user_settings(int ams_id, bool start_read_opt, bool tray_read_opt, bool remain_flag = false); + int command_ams_user_settings(int ams_id, AmsOptionType op, bool value); + int command_ams_switch_filament(bool switch_filament); int command_ams_calibrate(int ams_id); int command_ams_filament_settings(int ams_id, int tray_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max); int command_ams_select_tray(std::string tray_id); @@ -571,20 +661,27 @@ public: // set printing speed int command_set_printing_speed(PrintingSpeedLevel lvl); + // set print option + int command_set_printing_option(bool auto_recovery); + // axis string is X, Y, Z, E int command_axis_control(std::string axis, double unit = 1.0f, double value = 1.0f, int speed = 3000); // calibration printer - int command_start_calibration(); + bool is_support_command_calibration(); + int command_start_calibration(bool vibration, bool bed_leveling, bool xcam_cali); int command_unload_filament(); // camera control int command_ipcam_record(bool on_off); int command_ipcam_timelapse(bool on_off); - int command_xcam_control(std::string module_name, bool on_off, bool print_halt); + int command_ipcam_resolution_set(std::string resolution); + int command_xcam_control(std::string module_name, bool on_off, std::string lvl = ""); + int command_xcam_control_ai_monitoring(bool on_off, std::string lvl); int command_xcam_control_first_layer_inspector(bool on_off, bool print_halt); - int command_xcam_control_spaghetti_detector(bool on_off, bool print_halt); + int command_xcam_control_buildplate_marker_detector(bool on_off); + int command_xcam_control_auto_recovery_step_loss(bool on_off); /* common apis */ inline bool is_local() { return !dev_ip.empty(); } @@ -609,6 +706,7 @@ public: 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(); @@ -645,6 +743,8 @@ public: std::map localMachineList; /* dev_id -> MachineObject*, localMachine SSDP */ std::map userMachineList; /* dev_id -> MachineObject* cloudMachine of User */ + void check_pushing(); + MachineObject* get_default_machine(); MachineObject* get_local_selected_machine(); MachineObject* get_local_machine(std::string dev_id); @@ -677,8 +777,11 @@ public: static json function_table; 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 bool is_function_supported(std::string type_str, std::string function_name); + static std::vector get_resolution_supported(std::string type_str); + static bool get_bed_temperature_limit(std::string type_str, int& limit); static bool load_functional_config(std::string config_file); }; diff --git a/src/slic3r/GUI/DownloadProgressDialog.cpp b/src/slic3r/GUI/DownloadProgressDialog.cpp index 9c943d1c3a..d88ed43cc9 100644 --- a/src/slic3r/GUI/DownloadProgressDialog.cpp +++ b/src/slic3r/GUI/DownloadProgressDialog.cpp @@ -114,6 +114,7 @@ DownloadProgressDialog::DownloadProgressDialog(wxString title) CentreOnParent(); Bind(wxEVT_CLOSE_WINDOW, &DownloadProgressDialog::on_close, this); + wxGetApp().UpdateDlgDarkUI(this); } wxString DownloadProgressDialog::format_text(wxStaticText* st, wxString str, int warp) @@ -141,12 +142,12 @@ bool DownloadProgressDialog::Show(bool show) { if (show) { m_simplebook_status->SetSelection(0); - m_upgrade_job = std::make_shared(m_status_bar); + m_upgrade_job = make_job(m_status_bar); m_upgrade_job->set_event_handle(this); m_status_bar->set_progress(0); Bind(EVT_UPGRADE_NETWORK_SUCCESS, [this](wxCommandEvent& evt) { - m_status_bar->change_button_label(_L("Finish")); - wxGetApp().restart_networking(); + m_status_bar->change_button_label(_L("Close")); + on_finish(); m_status_bar->set_cancel_callback_fina( [this]() { this->Close(); @@ -205,4 +206,8 @@ void DownloadProgressDialog::on_dpi_changed(const wxRect &suggested_rect) {} void DownloadProgressDialog::update_release_note(std::string release_note, std::string version) {} +std::shared_ptr DownloadProgressDialog::make_job(std::shared_ptr pri) { return std::make_shared(pri); } + +void DownloadProgressDialog::on_finish() { wxGetApp().restart_networking(); } + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/DownloadProgressDialog.hpp b/src/slic3r/GUI/DownloadProgressDialog.hpp index 0f5504cc1f..938d2706a6 100644 --- a/src/slic3r/GUI/DownloadProgressDialog.hpp +++ b/src/slic3r/GUI/DownloadProgressDialog.hpp @@ -50,7 +50,9 @@ public: std::shared_ptr m_upgrade_job { nullptr }; wxPanel * m_panel_download; - +protected: + virtual std::shared_ptr make_job(std::shared_ptr pri); + virtual void on_finish(); }; diff --git a/src/slic3r/GUI/ExtraRenderers.cpp b/src/slic3r/GUI/ExtraRenderers.cpp index 4931a71ea2..7f77c0a4ce 100644 --- a/src/slic3r/GUI/ExtraRenderers.cpp +++ b/src/slic3r/GUI/ExtraRenderers.cpp @@ -313,13 +313,18 @@ wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1), 0, nullptr, wxCB_READONLY | CB_NO_DROP_ICON | CB_NO_TEXT); c_editor->GetDropDown().SetUseContentWidth(true); - // BBS + + if (has_default_extruder && has_default_extruder()) + c_editor->Append(_L("default"), *get_default_extruder_color_icon()); + for (size_t i = 0; i < icons.size(); i++) c_editor->Append(wxString::Format("%d", i+1), *icons[i]); - c_editor->SetSelection(atoi(data.GetText().c_str()) - 1); + if (has_default_extruder && has_default_extruder()) + c_editor->SetSelection(atoi(data.GetText().c_str())); + else + c_editor->SetSelection(atoi(data.GetText().c_str()) - 1); - #ifdef __linux__ c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) { // to avoid event propagation to other sidebar items diff --git a/src/slic3r/GUI/ExtraRenderers.hpp b/src/slic3r/GUI/ExtraRenderers.hpp index 432e31debc..ef16ddece9 100644 --- a/src/slic3r/GUI/ExtraRenderers.hpp +++ b/src/slic3r/GUI/ExtraRenderers.hpp @@ -153,11 +153,13 @@ public: void set_can_create_editor_ctrl_function(std::function can_create_fn) { can_create_editor_ctrl = can_create_fn; } void set_default_extruder_idx(std::function default_extruder_idx_fn) { get_default_extruder_idx = default_extruder_idx_fn; } + void set_has_default_extruder(std::function has_default_extruder_fn) { has_default_extruder = has_default_extruder_fn; } private: DataViewBitmapText m_value; std::function can_create_editor_ctrl { nullptr }; std::function get_default_extruder_idx{ nullptr }; + std::function has_default_extruder{ nullptr }; }; diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 1a07cb1472..3d09afd566 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -26,6 +26,7 @@ #include "Widgets/TextInput.hpp" #include "Widgets/SpinInput.hpp" #include "Widgets/ComboBox.hpp" +#include "Widgets/TextCtrl.h" #ifdef __WXOSX__ #define wxOSX true @@ -730,7 +731,7 @@ void CheckBox::BUILD() { // BBS: use ::CheckBox auto temp = new ::CheckBox(m_parent); if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT); - temp->SetBackgroundColour(*wxWHITE); + //temp->SetBackgroundColour(*wxWHITE); temp->SetValue(check_value); temp->Bind(wxEVT_TOGGLEBUTTON, ([this](wxCommandEvent & e) { @@ -986,13 +987,46 @@ using choice_ctrl = ::ComboBox; // BBS using choice_ctrl = ::ComboBox; // BBS #endif // __WXOSX__ -void Choice::BUILD() { +static std::map dynamic_lists; + +void Choice::register_dynamic_list(std::string const &optname, DynamicList *list) { dynamic_lists.emplace(optname, list); } + +void DynamicList::update() +{ + for (auto c : m_choices) apply_on(c); +} + +void DynamicList::add_choice(Choice *choice) +{ + auto iter = std::find(m_choices.begin(), m_choices.end(), choice); + if (iter != m_choices.end()) return; + apply_on(choice); + m_choices.push_back(choice); +} + +void DynamicList::remove_choice(Choice *choice) +{ + auto iter = std::find(m_choices.begin(), m_choices.end(), choice); + if (iter != m_choices.end()) m_choices.erase(iter); +} + +Choice::~Choice() +{ + if (m_list) { m_list->remove_choice(this); } +} + +void Choice::BUILD() +{ wxSize size(def_width_wider() * m_em_unit, wxDefaultCoord); if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); choice_ctrl* temp; - if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open) { + auto dynamic_list = dynamic_lists.find(m_opt.opt_key); + if (dynamic_list != dynamic_lists.end()) + m_list = dynamic_list->second; + if (m_opt.gui_type != ConfigOptionDef::GUIType::undefined && m_opt.gui_type != ConfigOptionDef::GUIType::select_open + && m_list == nullptr) { m_is_editable = true; temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxTE_PROCESS_ENTER); } @@ -1009,6 +1043,7 @@ void Choice::BUILD() { temp = new choice_ctrl(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY); #endif //__WXOSX__ } + temp->GetDropDown().SetUseContentWidth(true); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double) temp->GetTextCtrl()->GetSize().GetHeight() / m_em_unit; @@ -1035,11 +1070,25 @@ void Choice::BUILD() { temp->Append(el); } else { // Append localized enum_labels - for (auto el : m_opt.enum_labels) - temp->Append(_(el)); + int i = 0; + boost::filesystem::path image_path(Slic3r::resources_dir()); + image_path /= "images"; + for (auto el : m_opt.enum_labels) { + auto icon_name = "param_" + m_opt.enum_values[i]; + if (boost::filesystem::exists(image_path / (icon_name + ".svg"))) { + ScalableBitmap bm(temp, icon_name, 24); + temp->Append(_(el), bm.bmp()); + } else { + temp->Append(_(el)); + } + ++i; + } } set_selection(); - } + } else if (m_list) { + m_list->add_choice(this); + set_selection(); + } temp->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent& e) { if (m_suppress_scroll && !m_is_dropped) @@ -1212,7 +1261,9 @@ void Choice::set_value(const boost::any& value, bool change_event) break; ++idx; } - if (idx == enums.size()) { + if (m_list) + field->SetSelection(m_list->index_of(text_value)); + else if (idx == enums.size()) { // For editable Combobox under OSX is needed to set selection to -1 explicitly, // otherwise selection doesn't be changed field->SetSelection(-1); @@ -1332,7 +1383,10 @@ boost::any& Choice::get_value() } else if (m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open) { const int ret_enum = field->GetSelection(); - if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings || + if (m_list) { + ret_str = m_list->get_value(ret_enum); + get_value_by_opt_type(ret_str); + } else if (ret_enum < 0 || m_opt.enum_values.empty() || m_opt.type == coStrings || (ret_str != m_opt.enum_values[ret_enum] && ret_str != _(m_opt.enum_labels[ret_enum]))) // modifies ret_string! get_value_by_opt_type(ret_str); @@ -1393,6 +1447,20 @@ void Choice::msw_rescale() field->SetValue(selection) : field->SetSelection(idx); #else + if (!m_opt.enum_labels.empty()) { + boost::filesystem::path image_path(Slic3r::resources_dir()); + image_path /= "images"; + int i = 0; + auto temp = dynamic_cast(window); + for (auto el : m_opt.enum_values) { + auto icon_name = "param_" + m_opt.enum_values[i]; + if (boost::filesystem::exists(image_path / (icon_name + ".svg"))) { + ScalableBitmap bm(window, icon_name, 24); + temp->SetItemBitmap(i, bm.bmp()); + } + ++i; + } + } auto size = wxSize(def_width_wider() * m_em_unit, wxDefaultCoord); if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit); @@ -1444,14 +1512,21 @@ void ColourPicker::set_undef_value(wxColourPickerCtrl* field) field->SetColour(wxTransparentColour); wxButton* btn = dynamic_cast(field->GetPickerCtrl()); - wxBitmap bmp = btn->GetBitmap(); + wxImage image(btn->GetBitmap().GetSize()); + image.InitAlpha(); + memset(image.GetAlpha(), 0, image.GetWidth() * image.GetHeight()); + wxBitmap bmp(std::move(image)); wxMemoryDC dc(bmp); if (!dc.IsOk()) return; - dc.SetTextForeground(*wxWHITE); - dc.SetFont(wxGetApp().normal_font()); +#ifdef __WXMSW__ + wxGCDC dc2(dc); +#else + wxDC &dc2(dc); +#endif + dc2.SetPen(wxPen("#F1754E", 1)); const wxRect rect = wxRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); - dc.DrawLabel("undef", rect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); + dc2.DrawLine(rect.GetLeftBottom(), rect.GetTopRight()); dc.SelectObject(wxNullBitmap); btn->SetBitmapLabel(bmp); @@ -1529,8 +1604,8 @@ void PointCtrl::BUILD() #ifdef _WIN32 style |= wxBORDER_SIMPLE; #endif - x_textctrl = new wxTextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, style); - y_textctrl = new wxTextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, style); + x_textctrl = new ::TextCtrl(m_parent, wxID_ANY, X, wxDefaultPosition, field_size, style); + y_textctrl = new ::TextCtrl(m_parent, wxID_ANY, Y, wxDefaultPosition, field_size, style); if (parent_is_custom_ctrl && m_opt.height < 0) opt_height = (double)x_textctrl->GetSize().GetHeight() / m_em_unit; @@ -1769,5 +1844,4 @@ boost::any& SliderCtrl::get_value() } -} // GUI -} // Slic3r +}} // Slic3r diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 5ca0eae8aa..879cbdb469 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -335,13 +335,36 @@ public: wxWindow* getWindow() override { return window; } }; +class Choice; + +class DynamicList +{ +public: + virtual ~DynamicList() {} + virtual void apply_on(Choice * choice) = 0; + virtual wxString get_value(int index) = 0; + virtual int index_of(wxString value) = 0; + +protected: + void update(); + + std::vector m_choices; + +private: + friend class Choice; + void add_choice(Choice *choice); + void remove_choice(Choice *choice); +}; + class Choice : public Field { using Field::Field; - + DynamicList * m_list = nullptr; public: Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} - ~Choice() {} + ~Choice(); + + static void register_dynamic_list(std::string const &optname, DynamicList *list); wxWindow* window{ nullptr }; void BUILD() override; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index f2c0741e60..97145215af 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -330,9 +330,8 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he static float last_window_width = 0.0f; static size_t last_text_length = 0; - static const ImU32 text_name_clr = IM_COL32(38, 46, 48, 255); - static const ImU32 text_value_clr = IM_COL32(144, 144, 144, 255); - static const ImU32 window_bg_clr = IM_COL32(255, 255, 255, 255); + const ImU32 text_name_clr = m_is_dark ? IM_COL32(255, 255, 255, 0.88 * 255) : IM_COL32(38, 46, 48, 255); + const ImU32 text_value_clr = m_is_dark ? IM_COL32(255, 255, 255, 0.4 * 255) : IM_COL32(144, 144, 144, 255); auto it = std::find_if(moves.begin(), moves.end(), [&curr_line_id](auto move) { return move.gcode_id == curr_line_id; @@ -347,7 +346,6 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he imgui.push_toolbar_style(m_scale); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 4.0 * m_scale)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 * m_scale, 6.0 * m_scale)); - ImGui::PushStyleColor(ImGuiCol_WindowBg, window_bg_clr); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, text_name_clr); ImGui::PushStyleColor(ImGuiCol_Text, text_value_clr); imgui.begin(std::string("ExtruderPosition"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar); @@ -362,117 +360,92 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he std::string height = ImGui::ColorMarkerStart + _u8L("Height: ") + ImGui::ColorMarkerEnd; std::string width = ImGui::ColorMarkerStart + _u8L("Width: ") + ImGui::ColorMarkerEnd; std::string speed = ImGui::ColorMarkerStart + _u8L("Speed: ") + ImGui::ColorMarkerEnd; - std::string fan = ImGui::ColorMarkerStart + _u8L("Fan: ") + ImGui::ColorMarkerEnd; std::string flow = ImGui::ColorMarkerStart + _u8L("Flow: ") + ImGui::ColorMarkerEnd; + std::string fanspeed = ImGui::ColorMarkerStart + _u8L("Fan Speed: ") + ImGui::ColorMarkerEnd; + std::string temperature = ImGui::ColorMarkerStart + _u8L("Temperature: ") + ImGui::ColorMarkerEnd; const float item_size = imgui.calc_text_size("X: 000.000 ").x; const float item_spacing = imgui.get_item_spacing().x; const float window_padding = ImGui::GetStyle().WindowPadding.x; char buf[1024]; - switch (view_type){ + if (view_type == EViewType::Height || + view_type == EViewType::Width || + view_type == EViewType::Feedrate || + view_type == EViewType::VolumetricRate || + view_type == EViewType::FanSpeed || + view_type == EViewType::Temperature) + { + sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); + ImGui::PushItemWidth(item_size); + imgui.text(buf); + + ImGui::SameLine(window_padding + item_size + item_spacing); + sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); + ImGui::PushItemWidth(item_size); + imgui.text(buf); + + sprintf(buf, "%s%.3f", z.c_str(), position.z()); + ImGui::PushItemWidth(item_size); + imgui.text(buf); + + switch (view_type) { case EViewType::Height: { - sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - sprintf(buf, "%s%.3f", z.c_str(), position.z()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - ImGui::SameLine(window_padding + item_size + item_spacing); sprintf(buf, "%s%.2f", height.c_str(), it->height); ImGui::PushItemWidth(item_size); imgui.text(buf); - break; } case EViewType::Width: { - sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - sprintf(buf, "%s%.3f", z.c_str(), position.z()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - ImGui::SameLine(window_padding + item_size + item_spacing); sprintf(buf, "%s%.2f", width.c_str(), it->width); ImGui::PushItemWidth(item_size); imgui.text(buf); - + break; + } + case EViewType::Feedrate: { + ImGui::SameLine(window_padding + item_size + item_spacing); + sprintf(buf, "%s%.0f", speed.c_str(), it->feedrate); + ImGui::PushItemWidth(item_size); + imgui.text(buf); break; } case EViewType::VolumetricRate: { - sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - sprintf(buf, "%s%.3f", z.c_str(), position.z()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - ImGui::SameLine(window_padding + item_size + item_spacing); sprintf(buf, "%s%.2f", flow.c_str(), it->volumetric_rate()); ImGui::PushItemWidth(item_size); imgui.text(buf); - break; } - case EViewType::FanSpeed: - sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - + case EViewType::FanSpeed: { ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - sprintf(buf, "%s%.3f", z.c_str(), position.z()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%d", fan.c_str(), int(it->fan_speed + 0.5)); + sprintf(buf, "%s%.0f", fanspeed.c_str(), it->fan_speed); ImGui::PushItemWidth(item_size); imgui.text(buf); break; - - case EViewType::Feedrate: + } + case EViewType::Temperature: { + ImGui::SameLine(window_padding + item_size + item_spacing); + sprintf(buf, "%s%.0f", temperature.c_str(), it->temperature); + ImGui::PushItemWidth(item_size); + imgui.text(buf); + break; + } default: - sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); + break; + } + } + else { + sprintf(buf, "%s%.3f", x.c_str(), position.x() - plate->get_origin().x()); + imgui.text(buf); - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); + ImGui::SameLine(); + sprintf(buf, "%s%.3f", y.c_str(), position.y() - plate->get_origin().y()); + imgui.text(buf); - sprintf(buf, "%s%.3f", z.c_str(), position.z()); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - - ImGui::SameLine(window_padding + item_size + item_spacing); - sprintf(buf, "%s%.2f", speed.c_str(), it->feedrate); - ImGui::PushItemWidth(item_size); - imgui.text(buf); - + ImGui::SameLine(); + sprintf(buf, "%s%.3f", z.c_str(), position.z()); + imgui.text(buf); } // force extra frame to automatically update window size @@ -490,9 +463,9 @@ void GCodeViewer::SequentialView::Marker::render(int canvas_width, int canvas_he } imgui.end(); - imgui.pop_toolbar_style(); ImGui::PopStyleVar(2); - ImGui::PopStyleColor(3); + ImGui::PopStyleColor(2); + imgui.pop_toolbar_style(); } void GCodeViewer::SequentialView::GCodeWindow::load_gcode(const std::string& filename, std::vector &&lines_ends) @@ -688,9 +661,10 @@ void GCodeViewer::SequentialView::GCodeWindow::stop_mapping_file() } } //BBS: GUI refactor: move to the right -void GCodeViewer::SequentialView::render(float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector& moves) const +void GCodeViewer::SequentialView::render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector& moves) const { - marker.render(canvas_width, canvas_height, view_type, moves, static_cast(gcode_ids[current.last])); + if (has_render_path) + marker.render(canvas_width, canvas_height, view_type, moves, static_cast(gcode_ids[current.last])); //float bottom = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_height(); // BBS #if 0 @@ -699,7 +673,8 @@ void GCodeViewer::SequentialView::render(float legend_height, int canvas_width, #endif //gcode_window.render(legend_height, bottom, static_cast(gcode_ids[current.last])); if (wxGetApp().get_mode() == ConfigOptionMode::comDevelop) { - gcode_window.render(legend_height, (float) canvas_height, (float) canvas_width, static_cast(gcode_ids[current.last])); + if (has_render_path) + gcode_window.render(legend_height, (float)canvas_height, (float)canvas_width, static_cast(gcode_ids[current.last])); } } @@ -825,6 +800,9 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) // buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel; // } // else { + if(type == EMoveType::Seam) + buffer.visible = true; + buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel; buffer.vertices.format = VBuffer::EFormat::PositionNormal3; buffer.shader = "gouraud_light"; @@ -888,6 +866,11 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle) BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": finished"); } +void GCodeViewer::on_change_color_mode(bool is_dark) { + m_is_dark = is_dark; + m_sequential_view.marker.on_change_color_mode(m_is_dark); +} + void GCodeViewer::set_scale(float scale) { if(m_scale != scale)m_scale = scale; @@ -912,7 +895,9 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode) view_type_items.push_back(EViewType::VolumetricRate); view_type_items.push_back(EViewType::FanSpeed); view_type_items.push_back(EViewType::Temperature); - 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])); @@ -921,13 +906,13 @@ void GCodeViewer::update_by_mode(ConfigOptionMode mode) // BBS for first layer inspection view_type_items.push_back(EViewType::FilamentId); - options_items.push_back(EMoveType::Travel); options_items.push_back(EMoveType::Seam); + options_items.push_back(EMoveType::Travel); + 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::Retract); - options_items.push_back(EMoveType::Unretract); options_items.push_back(EMoveType::Tool_change); - options_items.push_back(EMoveType::Wipe); } } @@ -1257,7 +1242,7 @@ void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin) m_sequential_view.marker.set_world_position(m_sequential_view.current_position); m_sequential_view.marker.set_world_offset(m_sequential_view.current_offset); //BBS fixed buttom margin. m_moves_slider.pos_y - m_sequential_view.render(legend_height, canvas_width - right_margin * m_scale, canvas_height - bottom_margin * m_scale, m_view_type, m_gcode_result->moves); + m_sequential_view.render(!m_no_render_path, legend_height, canvas_width - right_margin * m_scale, canvas_height - bottom_margin * m_scale, m_view_type, m_gcode_result->moves); //} #if ENABLE_GCODE_VIEWER_STATISTICS render_statistics(); @@ -1291,13 +1276,13 @@ static void debug_calibration_output_thumbnail(const ThumbnailData& thumbnail_da #endif void GCodeViewer::_render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager) -{ +{ int plate_idx = thumbnail_params.plate_id; PartPlate* plate = partplate_list.get_plate(plate_idx); BoundingBoxf3 plate_box = plate->get_bounding_box(false); plate_box.min.z() = 0.0; plate_box.max.z() = 0.0; - Vec3d center = plate_box.center(); + Vec3d center = plate_box.center(); #if 1 Camera camera; @@ -3030,10 +3015,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const m_extruder_ids.shrink_to_fit(); std::vector plater_extruder; - for (auto mid : m_extruder_ids){ + for (auto mid : m_extruder_ids){ int eid = mid; plater_extruder.push_back(++eid); - } + } m_plater_extruder = plater_extruder; @@ -3143,7 +3128,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p 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 && + 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; @@ -4079,7 +4064,6 @@ void GCodeViewer::render_shells() // glsafe(::glDepthMask(GL_TRUE)); } -//BBS: GUI refactor: add canvas size void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin) { if (!m_legend_enabled) @@ -4118,7 +4102,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv //BBS /*bool show_estimated_time = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType || (m_view_type == EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()));*/ - bool show_estimated_time = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType || m_view_type == EViewType::ColorPrint); + bool show_estimated = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType || m_view_type == EViewType::ColorPrint); const float icon_size = ImGui::GetTextLineHeight() * 0.7; //BBS GUI refactor @@ -4134,18 +4118,16 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImVec2(pos_rect.x + ImGui::GetWindowWidth() + ImGui::GetFrameHeight(),pos_rect.y + ImGui::GetFrameHeight() + window_padding * 2.5), ImGui::GetColorU32(ImVec4(0,0,0,0.3))); - auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units,&window_padding,&draw_list,this](EItemType type, const Color &color, const std::string &label, - bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array& offsets = { 0.0f, 0.0f, 0.0f, 0.0f }, - double used_filament_m = 0.0, double used_filament_g = 0.0, - std::function callback = nullptr) { - /* BBS GUI refactor */ - /*if (!visible) - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); - */ - + auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this]( + EItemType type, + const Color& color, + const std::vector>& columns_offsets, + bool checkbox = true, + bool visible = true, + std::function callback = nullptr) + { + // render icon ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y); - float dummy_size = icon_size * m_scale; - switch (type) { default: case EItemType::Rect: { @@ -4167,125 +4149,66 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv draw_list->AddLine({ pos.x + 1, pos.y + icon_size + 2 }, { pos.x + icon_size - 1, pos.y + 4 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); break; case EItemType::None: - dummy_size = 0; break; } } - // draw text - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0, 6.0 * m_scale)); - ImGui::Dummy({ dummy_size, 0.0 }); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale)); + + // BBS render selectable + ImGui::Dummy({ 0.0, 0.0 }); ImGui::SameLine(); - if (callback != nullptr) { + if (callback) { ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * m_scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 * m_scale,0.0)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 * m_scale, 0.0)); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.00f, 0.68f, 0.26f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.00f, 0.68f, 0.26f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - bool b_menu_item = ImGui::BBLMenuItem(label.c_str()); + float max_height = 0.f; + for (auto column_offset : columns_offsets) { + if (ImGui::CalcTextSize(column_offset.first.c_str()).y > max_height) + max_height = ImGui::CalcTextSize(column_offset.first.c_str()).y; + } + bool b_menu_item = ImGui::BBLMenuItem(("##" + columns_offsets[0].first).c_str(), nullptr, false, true, max_height); ImGui::PopStyleVar(2); - ImGui::PopStyleColor(2); + ImGui::PopStyleColor(3); if (b_menu_item) callback(); - else { - // show tooltip - if (ImGui::IsItemHovered()) { - /* BBS GUI refactor */ - /* - if (!visible) - ImGui::PopStyleVar(); - */ - //ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - - //ImGui::BeginTooltip(); - //imgui.text(visible ? _u8L("Click to hide") : _u8L("Click to show")); - //ImGui::EndTooltip(); - //ImGui::PopStyleColor(); - /* BBS GUI refactor */ - /* - if (!visible) - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); - */ - - // to avoid the tooltip to change size when moving the mouse -#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - imgui.set_requires_extra_frame(); -#else - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); -#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - } - } - - //BBS GUI:refactor - if (!time.empty()) { - ImGui::SameLine(offsets[0]); - imgui.text(time); - ImGui::SameLine(offsets[1]); - pos = ImGui::GetCursorScreenPos(); - const float width = std::max(1.0f, percent_bar_size * percent / max_percent); - /* BBS GUI refactor do not draw percentage - draw_list->AddRectFilled({ pos.x, pos.y + 2.0f }, { pos.x + width, pos.y + icon_size - 2.0f }, - ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT)); - ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.20f, 0.64f, 1.00f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.20f, 0.64f, 1.00f, 0.00f)); - ImGui::BBLProgressBar(1.0 * percent, ImVec2(25.0f, 0.0f)); - ImGui::PopStyleColor(2); - ImGui::SameLine();*/ - char buf[64]; - ::sprintf(buf, "%.1f%%", 100.0f * percent); - ImGui::TextUnformatted((percent > 0.0f) ? buf : ""); - - ImGui::SameLine(offsets[3]); + if (checkbox) { + ImGui::SameLine(ImGui::GetWindowWidth() - imgui.calc_text_size(_u8L("Display")).x / 2 - ImGui::GetFrameHeight() / 2 - 2 * window_padding); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0)); ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - ImGui::Checkbox("", &visible); - ImGui::PopStyleVar(1); + ImGui::Checkbox(("##" + columns_offsets[0].first).c_str(), &visible); ImGui::PopStyleColor(1); - } else { - if (used_filament_m > 0.0) { - char buf[64]; - ImGui::SameLine(offsets[0]); - ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", used_filament_m); - imgui.text(buf); - ImGui::SameLine(offsets[1]); - ::sprintf(buf, "%.2fg", used_filament_g); - imgui.text(buf); - } - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0)); - ImGui::SameLine(offsets[3]); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - ImGui::Checkbox("", &visible); - ImGui::PopStyleColor(1); - ImGui::PopStyleVar(1); } } - else { - imgui.text(label); - // BBS refactor do not show used_filament info - if (used_filament_m > 0.0) { - char buf[64]; - ImGui::SameLine(offsets[0]); - ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", used_filament_m); - imgui.text(buf); - ImGui::SameLine(offsets[1]); - ::sprintf(buf, "%.2f g", used_filament_g); - imgui.text(buf); + + // BBS render column item + { + if(callback && !checkbox && !visible) + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(172 / 255.0f, 172 / 255.0f, 172 / 255.0f, 1.00f)); + float dummy_size = type == EItemType::None ? window_padding * 3 : ImGui::GetStyle().ItemSpacing.x + icon_size; + ImGui::SameLine(dummy_size); + imgui.text(columns_offsets[0].first); + + for (auto i = 1; i < columns_offsets.size(); i++) { + ImGui::SameLine(columns_offsets[i].second); + imgui.text(columns_offsets[i].first); } + if (callback && !checkbox && !visible) + ImGui::PopStyleColor(1); } + ImGui::PopStyleVar(1); - /* BBS GUI refactor */ - /*if (!visible) - ImGui::PopStyleVar(); - */ }; auto append_range = [append_item](const Extrusions::Range& range, unsigned int decimals) { auto append_range_item = [append_item](int i, float value, unsigned int decimals) { char buf[1024]; ::sprintf(buf, "%.*f", decimals, value); - append_item(EItemType::Rect, Range_Colors[i], buf); + append_item(EItemType::Rect, Range_Colors[i], { { buf , 0} }); }; if (range.count == 1) @@ -4303,13 +4226,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } }; - auto append_headers = [&imgui](const std::array& texts, const std::array& offsets) { - size_t i = 0; - for (; i < offsets.size(); i++) { - imgui.bold_text(texts[i]); - ImGui::SameLine(offsets[i]); + auto append_headers = [&imgui](const std::vector>& title_offsets) { + for (size_t i = 0; i < title_offsets.size(); i++) { + ImGui::SameLine(title_offsets[i].second); + imgui.bold_text(title_offsets[i].first); } - imgui.bold_text(texts[i]); ImGui::Separator(); }; @@ -4321,13 +4242,22 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv return ret; }; - auto calculate_offsets = [max_width](const std::vector& labels, const std::vector& times, - const std::array& titles, float extra_size = 0.0f) { + auto calculate_offsets = [max_width, window_padding](const std::vector>>& title_columns, float extra_size = 0.0f) { const ImGuiStyle& style = ImGui::GetStyle(); - std::array ret = { 0.0f, 0.0f, 0.0f, 0.0f }; - ret[0] = max_width(labels, titles[0], extra_size) + 3.0f * style.ItemSpacing.x; - for (size_t i = 1; i < titles.size(); i++) - ret[i] = ret[i-1] + max_width(times, titles[i]) + style.ItemSpacing.x; + std::vector offsets; + offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 3.0f * style.ItemSpacing.x); + for (size_t i = 1; i < title_columns.size() - 1; i++) + offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + style.ItemSpacing.x); + if (title_columns.back().first == _u8L("Display")) + offsets.back() = ImGui::GetWindowWidth() - ImGui::CalcTextSize(_u8L("Display").c_str()).x - ImGui::GetFrameHeight() / 2 - 2 * window_padding; + + float average_col_width = ImGui::GetWindowWidth() / static_cast(title_columns.size()); + std::vector ret; + ret.push_back(0); + for (size_t i = 1; i < title_columns.size(); i++) { + ret.push_back(std::max(offsets[i - 1], i * average_col_width)); + } + return ret; }; @@ -4445,6 +4375,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::Dummy({ window_padding, window_padding }); if (m_fold) { + legend_height = ImGui::GetStyle().WindowPadding.y + ImGui::GetFrameHeight() + window_padding * 2.5; imgui.end(); ImGui::PopStyleColor(6); ImGui::PopStyleVar(2); @@ -4452,45 +4383,21 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } // data used to properly align items in columns when showing time - std::array offsets = { 0.0f, 0.0f, 0.0f, 0.0f }; + std::vector offsets; std::vector labels; std::vector times; - std::vector percents; - std::vector used_filaments_m; - std::vector used_filaments_g; - double total_flushed_filament_m = 0.0; - double total_flushed_filament_g = 0.0; - - float max_percent = 0.0f; - - if (m_view_type == EViewType::FeatureType) { - // calculate offsets to align time/percentage data - for (size_t i = 0; i < m_roles.size(); ++i) { - ExtrusionRole role = m_roles[i]; - if (role < erCount) { - labels.push_back(_u8L(ExtrusionEntity::role_to_string(role))); - auto [time, percent] = role_time_and_percent(role); - times.push_back((time > 0.0f) ? short_time(get_time_dhms(time)) : ""); - percents.push_back(percent); - max_percent = std::max(max_percent, percent); - auto [used_filament_m, used_filament_g] = used_filament_per_role(role); - used_filaments_m.push_back(used_filament_m); - used_filaments_g.push_back(used_filament_g); - } - } - - std::string longest_percentage_string; - for (double item : percents) { - char buffer[64]; - ::sprintf(buffer, "%.2f %%", item); - if (::strlen(buffer) > longest_percentage_string.length()) - longest_percentage_string = buffer; - } - if (_u8L("Percent").length() > longest_percentage_string.length()) - longest_percentage_string = _u8L("Percent"); - - offsets = calculate_offsets(labels, times, {_u8L("Line Type"), _u8L("Time"), longest_percentage_string, _u8L("Display")}, icon_size); - } + std::vector percents; + std::vector model_used_filaments_m; + std::vector model_used_filaments_g; + double total_model_used_filament_m = 0, total_model_used_filament_g = 0; + 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; + 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; // get used filament (meters and grams) from used volume in respect to the active extruder auto get_used_filament_from_volume = [this, imperial_units](double volume, int extruder_id) { @@ -4500,29 +4407,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv return ret; }; - if (m_view_type == EViewType::Tool) { - // calculate used filaments data - 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 [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id); - used_filaments_m.push_back(used_filament_m); - used_filaments_g.push_back(used_filament_g); - } - - std::string longest_used_filament_string; - for (double item : used_filaments_m) { - char buffer[64]; - ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", item); - if (::strlen(buffer) > longest_used_filament_string.length()) - longest_used_filament_string = buffer; - } - - offsets = calculate_offsets(labels, times, { "Extruder NNN", longest_used_filament_string }, icon_size); - } - // extrusion paths section -> title ImGui::Dummy({ window_padding, window_padding }); ImGui::SameLine(); @@ -4530,7 +4414,27 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv { case EViewType::FeatureType: { - append_headers({_u8L("Line Type"), _u8L("Time"), _u8L("Percent"), "", _u8L("Display")}, offsets); + // calculate offsets to align time/percentage data + char buffer[64]; + for (size_t i = 0; i < m_roles.size(); ++i) { + ExtrusionRole role = m_roles[i]; + if (role < erCount) { + labels.push_back(_u8L(ExtrusionEntity::role_to_string(role))); + auto [time, percent] = role_time_and_percent(role); + times.push_back((time > 0.0f) ? short_time(get_time_dhms(time)) : ""); + if (percent == 0) + ::sprintf(buffer, "0%%"); + else + percent > 0.001 ? ::sprintf(buffer, "%.1f%%", percent * 100) : ::sprintf(buffer, "<0.1%%"); + percents.push_back(buffer); + //auto [model_used_filament_m, model_used_filament_g] = used_filament_per_role(role); + //model_used_filaments_m.push_back(model_used_filament_m); + //model_used_filaments_g.push_back(model_used_filament_g); + } + } + + offsets = calculate_offsets({ {_u8L("Line Type"), labels}, {_u8L("Time"), times}, {_u8L("Percent"), percents}, {_u8L("Display"), {""}}}, icon_size); + append_headers({{_u8L("Line Type"), offsets[0]}, {_u8L("Time"), offsets[1]}, {_u8L("Percent"), offsets[2]}, {_u8L("Display"), offsets[3]}}); break; } case EViewType::Height: { imgui.title(_u8L("Layer Height (mm)")); break; } @@ -4538,7 +4442,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); - offsets = calculate_offsets(labels, times, {_u8L("Speed (mm/s)")}, icon_size); break; } @@ -4547,55 +4450,65 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; } case EViewType::Tool: { - append_headers({ _u8L("Filament"), _u8L("Used filament") }, offsets); + // calculate used filaments data + 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); + } + + offsets = calculate_offsets({ { "Extruder NNN", {""}}}, icon_size); + append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Used filament"), offsets[1]} }); break; } 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 [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id); - used_filaments_m.push_back(used_filament_m); - used_filaments_g.push_back(used_filament_g); + 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 (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 (flushed_filaments_m.size() == 0 || flushed_filaments_g.size() == 0) + show_flushed_filaments = false; - std::string longest_used_filament_string; + std::vector total_filaments; char buffer[64]; - for (double item : used_filaments_m) { - ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", item); - if (::strlen(buffer) > longest_used_filament_string.length()) longest_used_filament_string = buffer; - } - ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", total_flushed_filament_m); - if (::strlen(buffer) > longest_used_filament_string.length()) longest_used_filament_string = buffer; + ::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); - std::string longest_used_filament_g_string; - for (double item : used_filaments_g) { - ::sprintf(buffer, imperial_units ? "%.2f g" : "%.2f g", item); - if (::strlen(buffer) > longest_used_filament_g_string.length()) longest_used_filament_g_string = buffer; - } - ::sprintf(buffer, imperial_units ? "%.2f g" : "%.2f g", total_flushed_filament_g); - if (::strlen(buffer) > longest_used_filament_g_string.length()) longest_used_filament_g_string = buffer; - - // BBL XX is placeholder - offsets = calculate_offsets(labels, times, {_u8L("Filament N XX"), longest_used_filament_string, longest_used_filament_g_string, _u8L("Display")}, icon_size); - append_headers({ _u8L("Color Print"), _u8L("Comsumption"), "", "", _u8L("Display") }, offsets); + 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) + 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 break; } default: { break; } } - auto append_option_item = [this,append_item](EMoveType type, std::array offsets) { + auto append_option_item = [this, append_item](EMoveType type, std::vector offsets) { auto append_option_item_with_type = [this, offsets, append_item](EMoveType type, const Color& color, const std::string& label, bool visible) { - append_item(EItemType::Rect, color, label, visible, "", 0.0f, 0.0f, offsets, 0.0, 0.0, [this, type, visible]() { + append_item(EItemType::Rect, color, {{ label , offsets[0] }}, true, visible, [this, type, visible]() { m_buffers[buffer_id(type)].visible = !m_buffers[buffer_id(type)].visible; // update buffers' render paths refresh_render_paths(false, false); @@ -4630,8 +4543,12 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv if (role >= erCount) continue; const bool visible = is_visible(role); - append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast(role)], labels[i], - visible, times[i], percents[i], max_percent, offsets, used_filaments_m[i], used_filaments_g[i], [this, role, visible]() { + std::vector> columns_offsets; + columns_offsets.push_back({ labels[i], offsets[0] }); + columns_offsets.push_back({ times[i], offsets[1] }); + columns_offsets.push_back({ percents[i], offsets[2] }); + append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast(role)], columns_offsets, + true, visible, [this, role, visible]() { m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); // update buffers' render paths refresh_render_paths(false, false); @@ -4641,7 +4558,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } for(auto item : options_items) { - append_option_item(item,offsets); + append_option_item(item, offsets); } break; } @@ -4652,10 +4569,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::Spacing(); ImGui::Dummy({ window_padding, window_padding }); ImGui::SameLine(); - append_headers({_u8L("Options"), "", "", "", _u8L("Display")}, offsets); + offsets = calculate_offsets({ { _u8L("Options"), { _u8L("Travel")}}, { _u8L("Display"), {""}} }, icon_size); + append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); const bool travel_visible = m_buffers[buffer_id(EMoveType::Travel)].visible; ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f)); - append_item(EItemType::None, Travel_Colors[0], _u8L("travel"), travel_visible, "", 0.0f, 0.0f, offsets, 0.0, 0.0, [this, travel_visible]() { + 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); @@ -4671,10 +4589,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv case EViewType::Tool: { // shows only extruders actually used + char buf[64]; size_t i = 0; for (unsigned char extruder_id : m_extruder_ids) { - append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1), - true, "", 0.0f, 0.0f, offsets, used_filaments_m[i], used_filaments_g[i]); + ::sprintf(buf, imperial_units ? "%.2f in %.2f g" : "%.2f m %.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); + append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_id], { { _u8L("Extruder") + " " + std::to_string(extruder_id + 1), offsets[0]}, {buf, offsets[1]} }); i++; } break; @@ -4692,119 +4611,146 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv // add scrollable region, if needed if (need_scrollable) ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); - if (m_extruders_count == 1) { // single extruder use case + 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 - append_item(EItemType::Rect, m_tools.m_tool_colors.front(), _u8L("Filament 1")); + std::vector> columns_offsets; + columns_offsets.push_back({ std::to_string(extruder_idx + 1), offsets[0] }); + + 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]); + 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)); + 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)); + 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)); + 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 - int extruder_idx = 0; - for (unsigned char i : m_extruder_ids) { - const std::vector>> cp_values = color_print_ranges(i, custom_gcode_per_print_z); + 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[i]; - if (extruder_idx < used_filaments_m.size() && extruder_idx < used_filaments_g.size()) { - append_item(EItemType::Rect, m_tools.m_tool_colors[i], _u8L("Filament") + " " + std::to_string(i + 1), filament_visible, "", 0.0f, 0.0f, offsets, - used_filaments_m[extruder_idx], used_filaments_g[extruder_idx], [this, i]() { - m_tools.m_tool_visibles[i] = !m_tools.m_tool_visibles[i]; - // update buffers' render paths - refresh_render_paths(false, false); - update_moves_slider(); - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); - }); + 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 g" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); + columns_offsets.push_back({ buf, offsets[1] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f g" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i]); + columns_offsets.push_back({ buf, offsets[2] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f g" : "%.2f m\n%.2f g", model_used_filaments_m[i] + flushed_filaments_m[i], model_used_filaments_g[i] + flushed_filaments_g[i]); + 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]); + columns_offsets.push_back({ buf, offsets[2] }); + } + + 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(); + }); } } else { for (int j = items_cnt; j >= 0; --j) { // create label for color change item - std::string label = _u8L("Filament") + " " + std::to_string(i + 1); + 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[i], label); + 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); + append_item(EItemType::Rect, cp_values[j - 1].first, { { label, 0 } }, false); continue; } label += " " + fromto_label(cp_values[j - 1].second.second, cp_values[j].second.first); - append_item(EItemType::Rect, cp_values[j - 1].first, label); + append_item(EItemType::Rect, cp_values[j - 1].first, { { label, 0 } }, false); } } - extruder_idx++; + i++; } } if (need_scrollable) ImGui::EndChild(); - for (auto item : options_items) - append_option_item(item,offsets); + char buf[64]; + if (m_extruder_ids.size() > 1) { + // Separator + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImRect separator(ImVec2(window->Pos.x + window_padding * 3, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x - window_padding * 3, window->DC.CursorPos.y + 1.0f)); + ImGui::ItemSize(ImVec2(0.0f, 0.0f)); + const bool item_visible = ImGui::ItemAdd(separator, 0); + window->DrawList->AddLine(separator.Min, ImVec2(separator.Max.x, separator.Min.y), ImGui::GetColorU32(ImGuiCol_Separator)); - //BBS display filament change times - if (m_print_statistics.total_filamentchanges > 0 && ( total_flushed_filament_m > 0 || total_flushed_filament_g > 0)) { - std::string flushed_filament_title_str = _u8L("Flushed filament"); - std::string flushed_filament_str = _u8L("Filament"); - std::string total_flushed_filament_str = _u8L("Total"); - std::string filament_change_str = _u8L("Filament change times"); - ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1)); - ImGui::Dummy({ window_padding, window_padding }); - ImGui::SameLine(); - imgui.title(flushed_filament_title_str); - //BBS: calculate total flushed filaments data - float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x; - max_len += ImGui::CalcTextSize(filament_change_str.c_str()).x; - 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 [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id); - append_item(EItemType::Rect, m_tools.m_tool_colors[extruder_id], flushed_filament_str + " " + std::to_string(extruder_id + 1), true, "", 0.0f, 0.0f, offsets, - used_filament_m, used_filament_g); - } + std::vector> columns_offsets; + columns_offsets.push_back({ _u8L("Total"), offsets[0] }); + if (!show_flushed_filaments) { + ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", total_model_used_filament_m, total_model_used_filament_g); + columns_offsets.push_back({ buf, offsets[2] }); - //BBS: display total flushed filament - { - ImGui::Dummy({window_padding, window_padding}); - ImGui::SameLine(); - imgui.text(total_flushed_filament_str + ":"); - ImGui::SameLine(offsets[0]); - char buf[64]; - ::sprintf(buf, "%.2f m", total_flushed_filament_m); - imgui.text(buf); - ImGui::SameLine(offsets[1]); - ::sprintf(buf, "%.2f g", total_flushed_filament_g); - imgui.text(buf); + append_item(EItemType::None, m_tools.m_tool_colors[0], columns_offsets); } - //BBS display filament change times - { - ImGui::Dummy({window_padding, window_padding}); - ImGui::SameLine(); - imgui.text(filament_change_str + ":"); - ImGui::SameLine(max_len); - char temp_buf[64]; - ::sprintf(temp_buf, "%d", m_print_statistics.total_filamentchanges); - imgui.text(temp_buf); + else { + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", total_model_used_filament_m, total_model_used_filament_g); + 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); + 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) * 1000 / /*1000*/koef, (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); } } + + //BBS display filament change times + ImGui::Dummy({window_padding, window_padding}); + ImGui::SameLine(); + imgui.text(_u8L("Filament change times") + ":"); + ImGui::SameLine(); + ::sprintf(buf, "%d", m_print_statistics.total_filamentchanges); + imgui.text(buf); + + //BBS display cost + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.text(_u8L("Cost")+":"); + ImGui::SameLine(); + ::sprintf(buf, "%.2f", ps.total_cost); + imgui.text(buf); + break; } default: { break; } @@ -5009,24 +4955,26 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } // wipe paths section - if (m_buffers[buffer_id(EMoveType::Wipe)].visible) { - switch (m_view_type) - { - case EViewType::Feedrate: - case EViewType::Tool: - case EViewType::ColorPrint: { break; } - default: { - // title - ImGui::Spacing(); - imgui.title(_u8L("Wipe")); + //if (m_buffers[buffer_id(EMoveType::Wipe)].visible) { + // switch (m_view_type) + // { + // case EViewType::Feedrate: + // case EViewType::Tool: + // case EViewType::ColorPrint: { break; } + // default: { + // // title + // ImGui::Spacing(); + // ImGui::Dummy({ window_padding, window_padding }); + // ImGui::SameLine(); + // imgui.title(_u8L("Wipe")); - // items - append_item(EItemType::Line, Wipe_Color, _u8L("Wipe")); + // // items + // append_item(EItemType::Line, Wipe_Color, { {_u8L("Wipe"), 0} }); - break; - } - } - } + // break; + // } + // } + //} auto any_option_available = [this]() { auto available = [this](EMoveType type) { @@ -5043,11 +4991,11 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv available(EMoveType::Seam); }; - auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { - const TBuffer& buffer = m_buffers[buffer_id(move_type)]; - if (buffer.visible && buffer.has_data()) - append_item(EItemType::Circle, Options_Colors[static_cast(color)], text); - }; + //auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { + // const TBuffer& buffer = m_buffers[buffer_id(move_type)]; + // if (buffer.visible && buffer.has_data()) + // append_item(EItemType::Circle, Options_Colors[static_cast(color)], text); + //}; /* BBS GUI refactor */ // options section @@ -5127,9 +5075,9 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } // total estimated printing time section - if (show_estimated_time) { + if (show_estimated) { ImGui::Spacing(); - std::string time_title = _u8L("Total Estimation"); + std::string time_title = m_view_type == EViewType::FeatureType ? _u8L("Total Estimation") : _u8L("Time Estimation"); auto can_show_mode_button = [this](PrintEstimatedStatistics::ETimeMode mode) { bool show = false; if (m_print_statistics.modes.size() > 1 && m_print_statistics.modes[static_cast(mode)].roles_times.size() > 0) { @@ -5160,51 +5108,52 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv std::string cost_str = _u8L("Cost"); std::string prepare_str = _u8L("Prepare time"); std::string print_str = _u8L("Model printing time"); - std::string total_str = _u8L("Total"); + std::string total_str = _u8L("Total time"); - float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x; + float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x; if (time_mode.layers_times.empty()) max_len += ImGui::CalcTextSize(total_str.c_str()).x; else { - max_len += std::max(ImGui::CalcTextSize(cost_str.c_str()).x, - std::max(ImGui::CalcTextSize(print_str.c_str()).x, - std::max(std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x), - ImGui::CalcTextSize(filament_str.c_str()).x))); + if (m_view_type == EViewType::FeatureType) + max_len += std::max(ImGui::CalcTextSize(cost_str.c_str()).x, + std::max(ImGui::CalcTextSize(print_str.c_str()).x, + std::max(std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x), + ImGui::CalcTextSize(filament_str.c_str()).x))); + else + max_len += std::max(ImGui::CalcTextSize(print_str.c_str()).x, + (std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x))); } - //BBS display filament cost - ImGui::Dummy({ window_padding, window_padding }); - ImGui::SameLine(); - imgui.text(filament_str + ":"); - ImGui::SameLine(max_len); + if (m_view_type == EViewType::FeatureType) { + //BBS display filament cost + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.text(filament_str + ":"); + ImGui::SameLine(max_len); - //BBS: use current plater's print statistics - const PrintStatistics& ps = wxGetApp().plater()->get_partplate_list().get_current_fff_print().print_statistics(); - bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; - char buf[64]; - double koef = imperial_units ? GizmoObjectManipulation::in_to_mm : 1000.0; - ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / /*1000*/koef); - imgui.text(buf); - ImGui::SameLine(); - double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1; - ::sprintf(buf, imperial_units ?" %.2f oz":" %.2f g", ps.total_weight / unit_conver); - imgui.text(buf); + //BBS: use current plater's print statistics + bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + char buf[64]; + ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / /*1000*/koef); + imgui.text(buf); + ImGui::SameLine(); + ::sprintf(buf, imperial_units ? " %.2f oz" : " %.2f g", ps.total_weight / unit_conver); + imgui.text(buf); + + //BBS: display cost of filaments + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.text(cost_str + ":"); + ImGui::SameLine(max_len); + + ::sprintf(buf, "%.2f", ps.total_cost); + imgui.text(buf); + } auto role_time = [time_mode](ExtrusionRole role) { auto it = std::find_if(time_mode.roles_times.begin(), time_mode.roles_times.end(), [role](const std::pair& item) { return role == item.first; }); return (it != time_mode.roles_times.end()) ? it->second : 0.0f; }; - - //BBS: display cost of filaments - ImGui::Dummy({window_padding, window_padding}); - ImGui::SameLine(); - imgui.text(cost_str + ":"); - ImGui::SameLine(max_len); - - //char buf[64]; - ::sprintf(buf, "%.2f", ps.total_cost); - imgui.text(buf); - //BBS: start gcode is prepeare time if (role_time(erCustom) != 0.0f) { ImGui::Dummy({ window_padding, window_padding }); @@ -5249,7 +5198,18 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } default : { assert(false); break; } } + + if (m_view_type == EViewType::ColorPrint) { + ImGui::Spacing(); + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + offsets = calculate_offsets({ { _u8L("Options"), { ""}}, { _u8L("Display"), {""}} }, icon_size); + append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); + for (auto item : options_items) + append_option_item(item, offsets); + } } + legend_height = ImGui::GetCurrentWindow()->Size.y; ImGui::Dummy({ window_padding, window_padding}); imgui.end(); @@ -5425,4 +5385,3 @@ GCodeViewer::Color GCodeViewer::option_color(EMoveType move_type) const } // namespace GUI } // namespace Slic3r - diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 02656fa59b..351d25b87a 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -614,6 +614,7 @@ public: Vec3f m_world_offset; float m_z_offset{ 0.5f }; bool m_visible{ true }; + bool m_is_dark = false; public: float m_scale = 1.0f; @@ -630,6 +631,7 @@ public: //BBS: GUI refactor: add canvas size void render(int canvas_width, int canvas_height, const EViewType& view_type, const std::vector& moves, uint64_t curr_line_id) const; + void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; } }; class GCodeWindow @@ -689,7 +691,7 @@ public: float m_scale = 1.0; //BBS: GUI refactor: add canvas size - void render(float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector& moves) const; + void render(const bool has_render_path, float legend_height, int canvas_width, int canvas_height, const EViewType& view_type, const std::vector& moves) const; }; struct ETools @@ -771,11 +773,13 @@ private: bool m_contained_in_bed{ true }; mutable bool m_no_render_path { false }; + bool m_is_dark = false; public: GCodeViewer(); ~GCodeViewer(); + void on_change_color_mode(bool is_dark); float m_scale = 1.0; void set_scale(float scale = 1.0); void init(ConfigOptionMode mode, Slic3r::PresetBundle* preset_bundle); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8f7b29ad65..f5e4c104af 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -74,11 +74,13 @@ static constexpr const float TRACKBALLSIZE = 0.8f; static const float SLIDER_DEFAULT_RIGHT_MARGIN = 10.0f; static const float SLIDER_DEFAULT_BOTTOM_MARGIN = 10.0f; -static const float SLIDER_RIGHT_MARGIN = 105.0f; +static const float SLIDER_RIGHT_MARGIN = 115.0f; static const float SLIDER_BOTTOM_MARGIN = 90.0f; float GLCanvas3D::DEFAULT_BG_LIGHT_COLOR[3] = { 0.906f, 0.906f, 0.906f }; +float GLCanvas3D::DEFAULT_BG_LIGHT_COLOR_DARK[3] = { 0.329f, 0.329f, 0.353f }; float GLCanvas3D::ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f }; +float GLCanvas3D::ERROR_BG_LIGHT_COLOR_DARK[3] = { 0.753f, 0.192f, 0.039f }; void GLCanvas3D::update_render_colors() { @@ -119,6 +121,503 @@ float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleF #undef Convex #endif +GLCanvas3D::LayersEditing::~LayersEditing() +{ + if (m_z_texture_id != 0) { + glsafe(::glDeleteTextures(1, &m_z_texture_id)); + m_z_texture_id = 0; + } + delete m_slicing_parameters; +} + +const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f; + +void GLCanvas3D::LayersEditing::init() +{ + glsafe(::glGenTextures(1, (GLuint*)&m_z_texture_id)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); +} + +void GLCanvas3D::LayersEditing::set_config(const DynamicPrintConfig* config) +{ + m_config = config; + delete m_slicing_parameters; + m_slicing_parameters = nullptr; + m_layers_texture.valid = false; + m_layer_height_profile.clear(); +} + +void GLCanvas3D::LayersEditing::select_object(const Model& model, int object_id) +{ + const ModelObject* model_object_new = (object_id >= 0) ? model.objects[object_id] : nullptr; + // Maximum height of an object changes when the object gets rotated or scaled. + // Changing maximum height of an object will invalidate the layer heigth editing profile. + // m_model_object->bounding_box() is cached, therefore it is cheap even if this method is called frequently. + const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast(model_object_new->bounding_box().max.z()); + if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z || + (model_object_new != nullptr && m_model_object->id() != model_object_new->id())) { + m_layer_height_profile.clear(); + delete m_slicing_parameters; + m_slicing_parameters = nullptr; + m_layers_texture.valid = false; + this->last_object_id = object_id; + m_model_object = model_object_new; + m_object_max_z = new_max_z; + } +} + +bool GLCanvas3D::LayersEditing::is_allowed() const +{ + return wxGetApp().get_shader("variable_layer_height") != nullptr && m_z_texture_id > 0; +} + +bool GLCanvas3D::LayersEditing::is_enabled() const +{ + return m_enabled; +} + +void GLCanvas3D::LayersEditing::set_enabled(bool enabled) +{ + m_enabled = is_allowed() && enabled; +} + +float GLCanvas3D::LayersEditing::s_overlay_window_width; + +void GLCanvas3D::LayersEditing::show_tooltip_information(const GLCanvas3D& canvas, std::map captions_texts, float x, float y) +{ + ImTextureID normal_id = canvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP); + ImTextureID hover_id = canvas.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER); + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + float caption_max = 0.f; + for (auto caption_text : captions_texts) { + caption_max = std::max(imgui.calc_text_size(caption_text.first).x, caption_max); + } + caption_max += GImGui->Style.WindowPadding.x + imgui.scaled(1); + + float font_size = ImGui::GetFontSize(); + ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0.0f, GImGui->Style.FramePadding.y}); + ImGui::ImageButton3(normal_id, hover_id, button_size); + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip2(ImVec2(x, y)); + auto draw_text_with_caption = [this, &caption_max, &imgui](const wxString& caption, const wxString& text) { + imgui.text_colored(ImGuiWrapper::COL_ACTIVE, caption); + ImGui::SameLine(caption_max); + imgui.text_colored(ImGuiWrapper::COL_WINDOW_BG, text); + }; + + for (const auto& caption_text : captions_texts) draw_text_with_caption(caption_text.first, caption_text.second); + + ImGui::EndTooltip(); + } + ImGui::PopStyleVar(2); +} + +void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(const GLCanvas3D& canvas) { + if (!m_enabled) + return; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + const Size& cnv_size = canvas.get_canvas_size(); + float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); + float left_pos = canvas.m_main_toolbar.get_item("layersediting")->render_left_pos; + const float x = 0.5 * cnv_size.get_width() + left_pos * zoom; + imgui.set_next_window_pos(x, canvas.m_main_toolbar.get_height(), ImGuiCond_Always, 0.0f, 0.0f); + + imgui.push_toolbar_style(canvas.get_scale()); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f * canvas.get_scale(), 4.0f * canvas.get_scale())); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f * canvas.get_scale(), 10.0f * canvas.get_scale())); + imgui.begin(_L("Variable layer height"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse); + const float sliders_width = imgui.scaled(7.0f); + const float input_box_width = 1.5 * imgui.get_slider_icon_size().x; + + if (imgui.button(_L("Adaptive"))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality)); + ImGui::SameLine(); + static float text_align = ImGui::GetCursorPosX(); + ImGui::AlignTextToFramePadding(); + text_align = std::max(text_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(text_align); + imgui.text(_L("Quality / Speed")); + if (ImGui::IsItemHovered()) { + //ImGui::BeginTooltip(); + //ImGui::TextUnformatted(_L("Higher print quality versus higher print speed.").ToUTF8()); + //ImGui::EndTooltip(); + } + ImGui::SameLine(); + static float slider_align = ImGui::GetCursorPosX(); + ImGui::PushItemWidth(sliders_width); + m_adaptive_quality = std::clamp(m_adaptive_quality, 0.0f, 1.f); + slider_align = std::max(slider_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(slider_align); + imgui.bbl_slider_float_style("##adaptive_slider", &m_adaptive_quality, 0.0f, 1.f, "%.2f"); + ImGui::SameLine(); + static float input_align = ImGui::GetCursorPosX(); + ImGui::PushItemWidth(input_box_width); + input_align = std::max(input_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(input_align); + ImGui::BBLDragFloat("##adaptive_input", &m_adaptive_quality, 0.05f, 0.0f, 0.0f, "%.2f"); + + if (imgui.button(_L("Smooth"))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), HeightProfileSmoothEvent(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, m_smooth_params)); + ImGui::SameLine(); + text_align = std::max(text_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(text_align); + ImGui::AlignTextToFramePadding(); + imgui.text(_L("Radius")); + ImGui::SameLine(); + slider_align = std::max(slider_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(slider_align); + ImGui::PushItemWidth(sliders_width); + int radius = (int)m_smooth_params.radius; + int v_min = 1, v_max = 10; + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.81f, 0.81f, 0.81f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); + if(ImGui::BBLSliderScalar("##radius_slider", ImGuiDataType_S32, &radius, &v_min, &v_max)){ + radius = std::clamp(radius, 1, 10); + m_smooth_params.radius = (unsigned int)radius; + } + ImGui::PopStyleColor(4); + ImGui::PopStyleVar(); + ImGui::SameLine(); + input_align = std::max(input_align, ImGui::GetCursorPosX()); + ImGui::SetCursorPosX(input_align); + ImGui::PushItemWidth(input_box_width); + ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.00f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.00f, 0.68f, 0.26f, 0.00f)); + ImGui::BBLDragScalar("##radius_input", ImGuiDataType_S32, &radius, 1, &v_min, &v_max); + ImGui::PopStyleColor(3); + + imgui.bbl_checkbox("##keep_min", m_smooth_params.keep_min); + ImGui::SameLine(); + ImGui::AlignTextToFramePadding(); + imgui.text(_L("Keep min")); + + ImGui::Separator(); + + float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + canvas.m_main_toolbar.get_height(); + std::map captions_texts = { + {_L("Left mouse button:") ,_L("Add detail")}, + {_L("Right mouse button:"), _L("Remove detail")}, + {_L("Shift + Left mouse button:"),_L("Reset to base")}, + {_L("Shift + Right mouse button:"), _L("Smoothing")}, + {_L("Mouse wheel:"), _L("Increase/decrease edit area")} + }; + show_tooltip_information(canvas, captions_texts, x, get_cur_y); + ImGui::SameLine(); + if (imgui.button(_L("Reset"))) + wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE)); + + GLCanvas3D::LayersEditing::s_overlay_window_width = ImGui::GetWindowSize().x; + imgui.end(); + ImGui::PopStyleVar(2); + imgui.pop_toolbar_style(); +} + +void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) +{ + render_variable_layer_height_dialog(canvas); + const Rect& bar_rect = get_bar_rect_viewport(canvas); + render_background_texture(canvas, bar_rect); + render_curve(bar_rect); +} + +float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) +{ + const Vec2d mouse_pos = canvas.get_local_mouse_position(); + const Rect& rect = get_bar_rect_screen(canvas); + float x = (float)mouse_pos.x(); + float y = (float)mouse_pos.y(); + float t = rect.get_top(); + float b = rect.get_bottom(); + + return (rect.get_left() <= x && x <= rect.get_right() && t <= y && y <= b) ? + // Inside the bar. + (b - y - 1.0f) / (b - t - 1.0f) : + // Outside the bar. + -1000.0f; +} + +bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, float x, float y) +{ + const Rect& rect = get_bar_rect_screen(canvas); + return rect.get_left() <= x && x <= rect.get_right() && rect.get_top() <= y && y <= rect.get_bottom(); +} + +Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas) +{ + const Size& cnv_size = canvas.get_canvas_size(); + float w = (float)cnv_size.get_width(); + float h = (float)cnv_size.get_height(); + + return { w - thickness_bar_width(canvas), 0.0f, w, h }; +} + +Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) +{ + const Size& cnv_size = canvas.get_canvas_size(); + float half_w = 0.5f * (float)cnv_size.get_width(); + float half_h = 0.5f * (float)cnv_size.get_height(); + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); + return { (half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom }; +} + +bool GLCanvas3D::LayersEditing::is_initialized() const +{ + return wxGetApp().get_shader("variable_layer_height") != nullptr; +} + +std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) const +{ + std::string ret; + if (m_enabled && m_layer_height_profile.size() >= 4) { + float z = get_cursor_z_relative(canvas); + if (z != -1000.0f) { + z *= m_object_max_z; + + float h = 0.0f; + for (size_t i = m_layer_height_profile.size() - 2; i >= 2; i -= 2) { + const float zi = static_cast(m_layer_height_profile[i]); + const float zi_1 = static_cast(m_layer_height_profile[i - 2]); + if (zi_1 <= z && z <= zi) { + float dz = zi - zi_1; + h = (dz != 0.0f) ? static_cast(lerp(m_layer_height_profile[i - 1], m_layer_height_profile[i + 1], (z - zi_1) / dz)) : + static_cast(m_layer_height_profile[i + 1]); + break; + } + } + if (h > 0.0f) + ret = std::to_string(h); + } + } + return ret; +} + +void GLCanvas3D::LayersEditing::render_background_texture(const GLCanvas3D& canvas, const Rect& bar_rect) +{ + if (!m_enabled) + return; + + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); + if (shader == nullptr) + return; + + shader->start_using(); + + shader->set_uniform("z_to_texture_row", float(m_layers_texture.cells - 1) / (float(m_layers_texture.width) * m_object_max_z)); + shader->set_uniform("z_texture_row_to_normalized", 1.0f / (float)m_layers_texture.height); + shader->set_uniform("z_cursor", m_object_max_z * this->get_cursor_z_relative(canvas)); + shader->set_uniform("z_cursor_band_width", band_width); + shader->set_uniform("object_max_z", m_object_max_z); + + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); + + // Render the color bar + const float l = bar_rect.get_left(); + const float r = bar_rect.get_right(); + const float t = bar_rect.get_top(); + const float b = bar_rect.get_bottom(); + + ::glBegin(GL_QUADS); + ::glNormal3f(0.0f, 0.0f, 1.0f); + ::glTexCoord2f(0.0f, 0.0f); ::glVertex2f(l, b); + ::glTexCoord2f(1.0f, 0.0f); ::glVertex2f(r, b); + ::glTexCoord2f(1.0f, 1.0f); ::glVertex2f(r, t); + ::glTexCoord2f(0.0f, 1.0f); ::glVertex2f(l, t); + glsafe(::glEnd()); + + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + + shader->stop_using(); +} + +void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect) +{ + if (!m_enabled) + return; + + //FIXME show some kind of legend. + if (!m_slicing_parameters) + return; + + // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region. + const float scale_x = bar_rect.get_width() / float(1.12 * m_slicing_parameters->max_layer_height); + const float scale_y = bar_rect.get_height() / m_object_max_z; + const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x; + + // Baseline + glsafe(::glColor3f(0.0f, 0.0f, 0.0f)); + ::glBegin(GL_LINE_STRIP); + ::glVertex2f(x, bar_rect.get_bottom()); + ::glVertex2f(x, bar_rect.get_top()); + glsafe(::glEnd()); + + // Curve + glsafe(::glColor3f(0.0f, 0.0f, 1.0f)); + ::glBegin(GL_LINE_STRIP); + for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2) + ::glVertex2f(bar_rect.get_left() + (float)m_layer_height_profile[i + 1] * scale_x, bar_rect.get_bottom() + (float)m_layer_height_profile[i] * scale_y); + glsafe(::glEnd()); +} + +void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const GLVolumeCollection & volumes)//render volume and layer height texture (has mapping relation with each other) +{ + assert(this->is_allowed()); + assert(this->last_object_id != -1); + + GLShaderProgram* current_shader = wxGetApp().get_current_shader(); + ScopeGuard guard([current_shader]() { if (current_shader != nullptr) current_shader->start_using(); }); + if (current_shader != nullptr) + current_shader->stop_using(); + + GLShaderProgram* shader = wxGetApp().get_shader("variable_layer_height"); + if (shader == nullptr) + return; + + shader->start_using(); + + generate_layer_height_texture(); + + // Uniforms were resolved, go ahead using the layer editing shader. + shader->set_uniform("z_to_texture_row", float(m_layers_texture.cells - 1) / (float(m_layers_texture.width) * float(m_object_max_z))); + shader->set_uniform("z_texture_row_to_normalized", 1.0f / float(m_layers_texture.height)); + shader->set_uniform("z_cursor", float(m_object_max_z) * float(this->get_cursor_z_relative(canvas))); + shader->set_uniform("z_cursor_band_width", float(this->band_width)); + + // Initialize the layer height texture mapping. + const GLsizei w = (GLsizei)m_layers_texture.width; + const GLsizei h = (GLsizei)m_layers_texture.height; + const GLsizei half_w = w / 2; + const GLsizei half_h = h / 2; + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_z_texture_id)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data())); + glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4)); + for (GLVolume* glvolume : volumes.volumes) { + // Render the object using the layer editing shader and texture. + if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) + continue; + + shader->set_uniform("volume_world_matrix", glvolume->world_matrix()); + shader->set_uniform("object_max_z", 0.0f); + + glvolume->render(); + } + // Revert back to the previous shader. + glBindTexture(GL_TEXTURE_2D, 0); +} + +void GLCanvas3D::LayersEditing::adjust_layer_height_profile() +{ + this->update_slicing_parameters(); + PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile); + Slic3r::adjust_layer_height_profile(*m_slicing_parameters, m_layer_height_profile, this->last_z, this->strength, this->band_width, this->last_action); + m_layers_texture.valid = false; +} + +void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D & canvas) +{ + const_cast(m_model_object)->layer_height_profile.clear(); + m_layer_height_profile.clear(); + m_layers_texture.valid = false; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); +} + +void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D & canvas, float quality_factor) +{ + this->update_slicing_parameters(); + m_layer_height_profile = layer_height_profile_adaptive(*m_slicing_parameters, *m_model_object, quality_factor); + const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); + m_layers_texture.valid = false; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); +} + +void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D & canvas, const HeightProfileSmoothingParams & smoothing_params) +{ + this->update_slicing_parameters(); + m_layer_height_profile = smooth_height_profile(m_layer_height_profile, *m_slicing_parameters, smoothing_params); + const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); + m_layers_texture.valid = false; + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); +} + +void GLCanvas3D::LayersEditing::generate_layer_height_texture() +{ + this->update_slicing_parameters(); + // Always try to update the layer height profile. + bool update = !m_layers_texture.valid; + if (PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile)) { + // Initialized to the default value. + update = true; + } + // Update if the layer height profile was changed, or when the texture is not valid. + if (!update && !m_layers_texture.data.empty() && m_layers_texture.cells > 0) + // Texture is valid, don't update. + return; + + if (m_layers_texture.data.empty()) { + m_layers_texture.width = 1024; + m_layers_texture.height = 1024; + m_layers_texture.levels = 2; + m_layers_texture.data.assign(m_layers_texture.width * m_layers_texture.height * 5, 0); + } + + bool level_of_detail_2nd_level = true; + m_layers_texture.cells = Slic3r::generate_layer_height_texture( + *m_slicing_parameters, + Slic3r::generate_object_layers(*m_slicing_parameters, m_layer_height_profile), + m_layers_texture.data.data(), m_layers_texture.height, m_layers_texture.width, level_of_detail_2nd_level); + m_layers_texture.valid = true; +} + +void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D & canvas) +{ + if (last_object_id >= 0) { + wxGetApp().plater()->take_snapshot("Variable layer height - Manual edit"); + const_cast(m_model_object)->layer_height_profile.set(m_layer_height_profile); + canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().obj_list()->update_info_items(last_object_id); + } +} + +void GLCanvas3D::LayersEditing::update_slicing_parameters() +{ + if (m_slicing_parameters == nullptr) { + m_slicing_parameters = new SlicingParameters(); + *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z); + } +} + +float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D & canvas) +{ + return +#if ENABLE_RETINA_GL + canvas.get_canvas_size().get_scale_factor() +#else + canvas.get_wxglcanvas()->GetContentScaleFactor() +#endif + * THICKNESS_BAR_WIDTH; +} + Size::Size() : m_width(0) , m_height(0) @@ -185,7 +684,7 @@ GLCanvas3D::Mouse::Mouse() void GLCanvas3D::Labels::render(const std::vector& sorted_instances) const { - if (!m_enabled || !is_shown()) + if (!m_enabled || !is_shown() || m_canvas.get_gizmos_manager().is_running()) return; const Camera& camera = wxGetApp().plater()->get_camera(); @@ -213,10 +712,14 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_ // collect owners world bounding boxes and data from volumes std::vector owners; const GLVolumeCollection& volumes = m_canvas.get_volumes(); + PartPlate* cur_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate(); for (const GLVolume* volume : volumes.volumes) { int obj_idx = volume->object_idx(); if (0 <= obj_idx && obj_idx < (int)model->objects.size()) { int inst_idx = volume->instance_idx(); + //only show current plate's label + if (!cur_plate->contain_instance(obj_idx, inst_idx)) + continue; std::vector::iterator it = std::find_if(owners.begin(), owners.end(), [obj_idx, inst_idx](const Owner& owner) { return (owner.obj_idx == obj_idx) && (owner.inst_idx == inst_idx); }); @@ -307,13 +810,8 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_ } // force re-render while the windows gets to its final size (it takes several frames) -#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x) imgui.set_requires_extra_frame(); -#else - if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x) - m_canvas.request_extra_frame(); -#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT imgui.end(); ImGui::PopStyleColor(); @@ -535,6 +1033,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, wxTimerEvent); wxDEFINE_EVENT(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, wxTimerEvent); wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE, SimpleEvent); wxDEFINE_EVENT(EVT_CUSTOMEVT_TICKSCHANGED, wxCommandEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); +wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; const double GLCanvas3D::DefaultCameraZoomToBedMarginFactor = 2.00; @@ -660,6 +1161,9 @@ bool GLCanvas3D::init() if (m_canvas == nullptr || m_context == nullptr) return false; + // init dark mode status + on_change_color_mode(wxGetApp().app_config->get("dark_color_mode") == "1", false); + BOOST_LOG_TRIVIAL(info) <<__FUNCTION__<< " enter"; glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f)); glsafe(::glClearDepth(1.0f)); @@ -704,6 +1208,10 @@ bool GLCanvas3D::init() if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": before m_layers_editing init"; + if (m_main_toolbar.is_enabled()) + m_layers_editing.init(); + // on linux the gl context is not valid until the canvas is not shown on screen // we defer the geometry finalization of volumes until the first call to render() m_volumes.finalize_geometry(true); @@ -730,12 +1238,48 @@ bool GLCanvas3D::init() GLCanvas3D::load_render_colors(); Bed3D::load_render_colors(); #endif - + //if (!wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) + // wxGetApp().plater()->enable_wireframe(false); m_initialized = true; return true; } +void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) { + m_is_dark = is_dark; + // Bed color + m_bed.on_change_color_mode(is_dark); + // GcodeViewer color + m_gcode_viewer.on_change_color_mode(is_dark); + // ImGui Style + wxGetApp().imgui()->on_change_color_mode(is_dark); + // Notification + wxGetApp().plater()->get_notification_manager()->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(); + m_layers_slider->on_change_color_mode(is_dark); + m_moves_slider->on_change_color_mode(is_dark); + // Partplate + wxGetApp().plater()->get_partplate_list().on_change_color_mode(is_dark); + + // Toolbar + if (m_canvas_type == CanvasView3D) { + m_gizmos.on_change_color_mode(is_dark); + if (reinit) { + // reset svg + _switch_toolbars_icon_filename(); + m_gizmos.switch_gizmos_icon_filename(); + // set dirty to re-generate icon texture + m_separator_toolbar.set_icon_dirty(); + m_main_toolbar.set_icon_dirty(); + wxGetApp().plater()->get_collapse_toolbar().set_icon_dirty(); + m_assemble_view_toolbar.set_icon_dirty(); + m_gizmos.set_icon_dirty(); + } + } +} + void GLCanvas3D::set_as_dirty() { m_dirty = true; @@ -889,6 +1433,7 @@ void GLCanvas3D::update_instance_printable_state_for_objects(const std::vectortake_snapshot("Variable layer height - Reset"); + m_layers_editing.reset_layer_height_profile(*this); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} + +void GLCanvas3D::adaptive_layer_height_profile(float quality_factor) +{ + wxGetApp().plater()->take_snapshot("Variable layer height - Adaptive"); + m_layers_editing.adaptive_layer_height_profile(*this, quality_factor); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} + +void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params) +{ + wxGetApp().plater()->take_snapshot("Variable layer height - Smooth all"); + m_layers_editing.smooth_layer_height_profile(*this, smoothing_params); + m_layers_editing.state = LayersEditing::Completed; + m_dirty = true; +} + bool GLCanvas3D::is_reload_delayed() const { return m_reload_delayed; } +void GLCanvas3D::enable_layers_editing(bool enable) +{ + m_layers_editing.set_enabled(enable); + set_as_dirty(); +} + void GLCanvas3D::enable_legend_texture(bool enable) { m_gcode_viewer.enable_legend(enable); @@ -1296,6 +1881,8 @@ void GLCanvas3D::render(bool only_init) _render_overlays(); if (wxGetApp().plater()->is_render_statistic_dialog_visible()) { + ImGui::ShowMetricsWindow(); + ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); imgui.text("FPS (SwapBuffers() calls per second):"); @@ -1331,6 +1918,9 @@ void GLCanvas3D::render(bool only_init) // Negative coordinate means out of the window, likely because the window was deactivated. // In that case the tooltip should be hidden. if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.) { + if (tooltip.empty()) + tooltip = m_layers_editing.get_tooltip(*this); + if (tooltip.empty()) tooltip = m_gizmos.get_tooltip(); @@ -1365,12 +1955,7 @@ void GLCanvas3D::render(bool only_init) right_margin = SLIDER_RIGHT_MARGIN; bottom_margin = SLIDER_BOTTOM_MARGIN; } - #if ENABLE_RETINA_GL - float sc = m_retina_helper->get_scale_factor(); - wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin * sc, right_margin); - #else - wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); - #endif + wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin); } wxGetApp().imgui()->render(); @@ -1812,7 +2397,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_color_by, m_initialized); + 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 { @@ -2021,7 +2606,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // If no object is selected, deactivate the active gizmo, if any // Otherwise it may be shown after cleaning the scene (if it was active while the objects were deleted) m_gizmos.reset_all_states(); - // BBS #if 0 // If no object is selected, reset the objects manipulator on the sidebar @@ -2289,7 +2873,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #else /* __APPLE__ */ case WXK_CONTROL_A: #endif /* __APPLE__ */ - if (!is_in_painting_mode) + if (!is_in_painting_mode && !m_layers_editing.is_enabled()) post_event(SimpleEvent(EVT_GLCANVAS_SELECT_ALL)); break; #ifdef __APPLE__ @@ -2381,6 +2965,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) break; // BBS +#ifdef __APPLE__ + case 'E': + case 'e': +#else /* __APPLE__ */ + case WXK_CONTROL_E: +#endif /* __APPLE__ */ + { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } case '0': { select_view("plate"); zoom_to_bed(); @@ -2477,8 +3068,6 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'C': case 'c': { m_gcode_viewer.toggle_gcode_window_visibility(); m_dirty = true; request_extra_frame(); break; } #endif - //case 'E': - //case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } //case 'G': //case 'g': { // if ((evt.GetModifiers() & shiftMask) != 0) { @@ -2670,10 +3259,8 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) #endif } else if (evt.ShiftDown() && evt.ControlDown() && keyCode == WXK_RETURN) { -#if !BBL_RELEASE_TO_PUBLIC wxGetApp().plater()->toggle_show_wireframe(); m_dirty = true; -#endif } else if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) { // Enable switching between 3D and Preview with Tab @@ -2809,11 +3396,21 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) IMSlider *m_layers_slider = get_gcode_viewer().get_layers_slider(); IMSlider *m_moves_slider = get_gcode_viewer().get_moves_slider(); if (evt.CmdDown() || evt.ShiftDown()) { + if (evt.GetKeyCode() == 'G') { + m_layers_slider->show_go_to_layer(true); + } IMSlider *m_layers_slider = get_gcode_viewer().get_layers_slider(); IMSlider *m_moves_slider = get_gcode_viewer().get_moves_slider(); if (keyCode == WXK_UP || keyCode == WXK_DOWN) { - const int new_pos = keyCode == WXK_UP ? m_layers_slider->GetHigherValue() + 5 : m_layers_slider->GetHigherValue() - 5; - m_layers_slider->SetHigherValue(new_pos); + int new_pos; + if (m_layers_slider->GetSelection() == ssHigher) { + new_pos = keyCode == WXK_UP ? m_layers_slider->GetHigherValue() + 5 : m_layers_slider->GetHigherValue() - 5; + m_layers_slider->SetHigherValue(new_pos); + } + else if (m_layers_slider->GetSelection() == ssLower) { + new_pos = keyCode == WXK_UP ? m_layers_slider->GetLowerValue() + 5 : m_layers_slider->GetLowerValue() - 5; + m_layers_slider->SetLowerValue(new_pos); + } if (m_layers_slider->is_one_layer()) m_layers_slider->SetLowerValue(m_layers_slider->GetHigherValue()); // BBS set as dirty, update in render_gcode() m_layers_slider->set_as_dirty(); @@ -2825,8 +3422,15 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) } } else if (keyCode == WXK_UP || keyCode == WXK_DOWN) { - const int new_pos = keyCode == WXK_UP ? m_layers_slider->GetHigherValue() + 1 : m_layers_slider->GetHigherValue() - 1; - m_layers_slider->SetHigherValue(new_pos); + int new_pos; + if (m_layers_slider->GetSelection() == ssHigher) { + new_pos = keyCode == WXK_UP ? m_layers_slider->GetHigherValue() + 1 : m_layers_slider->GetHigherValue() - 1; + m_layers_slider->SetHigherValue(new_pos); + } + else if (m_layers_slider->GetSelection() == ssLower) { + new_pos = keyCode == WXK_UP ? m_layers_slider->GetLowerValue() + 1 : m_layers_slider->GetLowerValue() - 1; + m_layers_slider->SetLowerValue(new_pos); + } if (m_layers_slider->is_one_layer()) m_layers_slider->SetLowerValue(m_layers_slider->GetHigherValue()); // BBS set as dirty, update in render_gcode() m_layers_slider->set_as_dirty(); @@ -2874,6 +3478,13 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) #endif if (wxGetApp().imgui()->update_mouse_data(evt)) { + if (m_canvas_type == CanvasPreview) { + IMSlider* m_layers_slider = get_gcode_viewer().get_layers_slider(); + IMSlider* m_moves_slider = get_gcode_viewer().get_moves_slider(); + m_layers_slider->on_mouse_wheel(evt); + m_moves_slider->on_mouse_wheel(evt); + } + render(); m_dirty = true; return; } @@ -2885,6 +3496,22 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) wxWakeUpIdle(); #endif /* __WXMSW__ */ + // Performs layers editing updates, if enabled + if (is_layers_editing_enabled()) { + int object_idx_selected = m_selection.get_object_idx(); + if (object_idx_selected != -1) { + // A volume is selected. Test, whether hovering over a layer thickness bar. + if (m_layers_editing.bar_rect_contains(*this, (float)evt.GetX(), (float)evt.GetY())) { + // Adjust the width of the selection. + m_layers_editing.band_width = std::max(std::min(m_layers_editing.band_width * (1.0f + 0.1f * (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta()), 10.0f), 1.5f); + if (m_canvas != nullptr) + m_canvas->Refresh(); + + return; + } + } + } + // Inform gizmos about the event so they have the opportunity to react. if (m_gizmos.on_mouse_wheel(evt)) return; @@ -2900,6 +3527,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) void GLCanvas3D::on_timer(wxTimerEvent& evt) { + if (m_layers_editing.state == LayersEditing::Editing) + _perform_layer_editing_action(); } void GLCanvas3D::on_render_timer(wxTimerEvent& evt) @@ -3123,6 +3752,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_gizmos.is_running()) { _deactivate_arrange_menu(); _deactivate_orient_menu(); + _deactivate_layersediting_menu(); } if (wxWindow::FindFocus() != m_canvas) // Grab keyboard focus for input in gizmo dialogs. @@ -3175,6 +3805,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) bool any_gizmo_active = m_gizmos.get_current() != nullptr; int selected_object_idx = m_selection.get_object_idx(); + int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; + + if (m_mouse.drag.move_requires_threshold && m_mouse.is_move_start_threshold_position_2D_defined() && m_mouse.is_move_threshold_met(pos)) { m_mouse.drag.move_requires_threshold = false; m_mouse.set_move_start_threshold_position_2D_as_invalid(); @@ -3221,75 +3854,86 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) return; } - // BBS: define Alt key to enable volume selection mode - m_selection.set_volume_selection_mode(evt.AltDown() ? Selection::Volume : Selection::Instance); - if (evt.LeftDown() && evt.ShiftDown() && m_picking_enabled) { - if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports - && m_gizmos.get_current_type() != GLGizmosManager::FdmSupports - && m_gizmos.get_current_type() != GLGizmosManager::Seam - && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { - m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); - m_dirty = true; - } + // If user pressed left or right button we first check whether this happened on a volume or not. + m_layers_editing.state = LayersEditing::Unknown; + if (layer_editing_object_idx != -1 && m_layers_editing.bar_rect_contains(*this, pos(0), pos(1))) { + // A volume is selected and the mouse is inside the layer thickness bar. + // Start editing the layer height. + m_layers_editing.state = LayersEditing::Editing; + _perform_layer_editing_action(&evt); } + else { - // Select volume in this 3D canvas. - // Don't deselect a volume if layer editing is enabled or any gizmo is active. We want the object to stay selected - // during the scene manipulation. - - if (m_picking_enabled && (!any_gizmo_active || !evt.CmdDown()) && (!m_hover_volume_idxs.empty())) { - if (evt.LeftDown() && !m_hover_volume_idxs.empty()) { - int volume_idx = get_first_hover_volume_idx(); - bool already_selected = m_selection.contains_volume(volume_idx); - bool ctrl_down = evt.CmdDown(); - - Selection::IndicesList curr_idxs = m_selection.get_volume_idxs(); - - if (already_selected && ctrl_down) - m_selection.remove(volume_idx); - else { - m_selection.add(volume_idx, !ctrl_down, true); - m_mouse.drag.move_requires_threshold = !already_selected; - if (already_selected) - m_mouse.set_move_start_threshold_position_2D_as_invalid(); - else - m_mouse.drag.move_start_threshold_position_2D = pos; - } - - // propagate event through callback - if (curr_idxs != m_selection.get_volume_idxs()) { - if (m_selection.is_empty()) - m_gizmos.reset_all_states(); - else - m_gizmos.refresh_on_off_state(); - - m_gizmos.update_data(); - post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); - m_dirty = true; - } + // BBS: define Alt key to enable volume selection mode + m_selection.set_volume_selection_mode(evt.AltDown() ? Selection::Volume : Selection::Instance); + if (evt.LeftDown() && evt.ShiftDown() && m_picking_enabled && m_layers_editing.state != LayersEditing::Editing) { + if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports + && m_gizmos.get_current_type() != GLGizmosManager::FdmSupports + && m_gizmos.get_current_type() != GLGizmosManager::Seam + && m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation) { + m_rectangle_selection.start_dragging(m_mouse.position, evt.ShiftDown() ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); + m_dirty = true; } } + else { + // Select volume in this 3D canvas. + // Don't deselect a volume if layer editing is enabled or any gizmo is active. We want the object to stay selected + // during the scene manipulation. - if (!m_hover_volume_idxs.empty()) { - if (evt.LeftDown() && m_moving_enabled && m_mouse.drag.move_volume_idx == -1) { - // Only accept the initial position, if it is inside the volume bounding box. - int volume_idx = get_first_hover_volume_idx(); - BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); - volume_bbox.offset(1.0); - if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position)) { - m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; - // The dragging operation is initiated. - m_mouse.drag.move_volume_idx = volume_idx; - m_selection.start_dragging(); - m_mouse.drag.start_position_3D = m_mouse.scene_position; - m_sequential_print_clearance_first_displacement = true; - m_moving = true; + if (m_picking_enabled && (!any_gizmo_active || !evt.CmdDown()) && (!m_hover_volume_idxs.empty())) { + if (evt.LeftDown() && !m_hover_volume_idxs.empty()) { + int volume_idx = get_first_hover_volume_idx(); + bool already_selected = m_selection.contains_volume(volume_idx); + bool ctrl_down = evt.CmdDown(); + + Selection::IndicesList curr_idxs = m_selection.get_volume_idxs(); + + if (already_selected && ctrl_down) + m_selection.remove(volume_idx); + else { + m_selection.add(volume_idx, !ctrl_down, true); + m_mouse.drag.move_requires_threshold = !already_selected; + if (already_selected) + m_mouse.set_move_start_threshold_position_2D_as_invalid(); + else + m_mouse.drag.move_start_threshold_position_2D = pos; + } + + // propagate event through callback + if (curr_idxs != m_selection.get_volume_idxs()) { + if (m_selection.is_empty()) + m_gizmos.reset_all_states(); + else + m_gizmos.refresh_on_off_state(); + + m_gizmos.update_data(); + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + m_dirty = true; + } + } + } + + if (!m_hover_volume_idxs.empty()) { + if (evt.LeftDown() && m_moving_enabled && m_mouse.drag.move_volume_idx == -1) { + // Only accept the initial position, if it is inside the volume bounding box. + int volume_idx = get_first_hover_volume_idx(); + BoundingBoxf3 volume_bbox = m_volumes.volumes[volume_idx]->transformed_bounding_box(); + volume_bbox.offset(1.0); + if ((!any_gizmo_active || !evt.CmdDown()) && volume_bbox.contains(m_mouse.scene_position)) { + m_volumes.volumes[volume_idx]->hover = GLVolume::HS_None; + // The dragging operation is initiated. + m_mouse.drag.move_volume_idx = volume_idx; + m_selection.start_dragging(); + m_mouse.drag.start_position_3D = m_mouse.scene_position; + m_sequential_print_clearance_first_displacement = true; + m_moving = true; + } } } } } } - else if (evt.Dragging() && evt.LeftIsDown() && m_mouse.drag.move_volume_idx != -1) { + else if (evt.Dragging() && evt.LeftIsDown() && m_mouse.drag.move_volume_idx != -1 && m_layers_editing.state == LayersEditing::Unknown) { if (m_canvas_type != ECanvasType::CanvasAssembleView) { if (!m_mouse.drag.move_requires_threshold) { m_mouse.dragging = true; @@ -3347,8 +3991,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else if (evt.Dragging()) { m_mouse.dragging = true; + if (m_layers_editing.state != LayersEditing::Unknown && layer_editing_object_idx != -1) { + if (m_layers_editing.state == LayersEditing::Editing) { + _perform_layer_editing_action(&evt); + m_mouse.position = pos.cast(); + } + } // do not process the dragging if the left mouse was set down in another canvas - if (evt.LeftIsDown()) { + else if (evt.LeftIsDown()) { // if dragging over blank area with left button, rotate if ((any_gizmo_active || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) { const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.); @@ -3363,8 +4013,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) //BBS do not limit rotate in assemble view camera.rotate_local_with_target(Vec3d(rot.y(), rot.x(), 0.), rotate_target); //camera.rotate_on_sphere_with_target(rot.x(), rot.y(), false, rotate_target); - auto clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position(); - m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(clp_dist, true); } else { #ifdef SUPPORT_FEEE_CAMERA @@ -3449,7 +4097,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_rotation_center(0) = m_rotation_center(1) = m_rotation_center(2) = 0.f; } - if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) { + if (m_layers_editing.state != LayersEditing::Unknown) { + m_layers_editing.state = LayersEditing::Unknown; + _stop_timer(); + m_layers_editing.accept_changes(*this); + } + else if (m_mouse.drag.move_volume_idx != -1 && m_mouse.dragging) { do_move(L("Move Object")); // BBS //wxGetApp().obj_manipul()->set_dirty(); @@ -3457,7 +4110,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // of the scene with the background processing data should be performed. post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED)); } - else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging()) { + else if (evt.LeftUp() && m_picking_enabled && m_rectangle_selection.is_dragging() && m_layers_editing.state != LayersEditing::Editing) { //BBS: don't use alt as de-select //if (evt.ShiftDown() || evt.AltDown()) if (evt.ShiftDown()) @@ -3465,13 +4118,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_rectangle_selection.stop_dragging(); } - else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && m_hover_plate_idxs.empty()) { + else if (evt.LeftUp() && !m_mouse.ignore_left_up && !m_mouse.dragging && m_hover_volume_idxs.empty() && m_hover_plate_idxs.empty() && !is_layers_editing_enabled()) { // deselect and propagate event through callback if (!evt.ShiftDown() && (!any_gizmo_active || !evt.CmdDown()) && m_picking_enabled) deselect_all(); } //BBS Select plate in this 3D canvas. - else if (evt.LeftUp() && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D)) + else if (evt.LeftUp() && !m_mouse.dragging && m_picking_enabled && !m_hover_plate_idxs.empty() && (m_canvas_type == CanvasView3D) && !is_layers_editing_enabled()) { int hover_idx = m_hover_plate_idxs.front(); wxGetApp().plater()->select_plate_by_hover_id(hover_idx); @@ -3480,7 +4133,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) if (m_hover_volume_idxs.empty()) deselect_all(); } - else if (evt.RightUp()) { + else if (evt.RightUp() && !is_layers_editing_enabled()) { m_mouse.position = pos.cast(); // forces a frame render to ensure that m_hover_volume_idxs is updated even when the user right clicks while // the context menu is already shown @@ -3574,7 +4227,7 @@ void GLCanvas3D::on_set_focus(wxFocusEvent& evt) m_tooltip_enabled = false; if (m_canvas_type == ECanvasType::CanvasPreview) { // update thumbnails and update plate toolbar - wxGetApp().plater()->update_platplate_thumbnails(); + wxGetApp().plater()->update_all_plate_thumbnails(); _update_imgui_select_plate_toolbar(); } _refresh_if_shown_on_screen(); @@ -4597,10 +5250,17 @@ bool GLCanvas3D::_render_arrange_menu(float left, float right, float bottom, flo settings_changed = true; } - if (imgui->bbl_checkbox(_L("Avoid extrusion calibration region"), settings.avoid_extrusion_cali_region)) { - settings_out.avoid_extrusion_cali_region = settings.avoid_extrusion_cali_region; - appcfg->set("arrange", avoid_extrusion_key.c_str(), settings_out.avoid_extrusion_cali_region ? "1" : "0"); - settings_changed = true; + // only show this option if the printer has micro Lidar and can do first layer scan + DynamicPrintConfig ¤t_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + auto op = current_config.option("scan_first_layer"); + if (op && op->getBool()) { + if (imgui->bbl_checkbox(_L("Avoid extrusion calibration region"), settings.avoid_extrusion_cali_region)) { + settings_out.avoid_extrusion_cali_region = settings.avoid_extrusion_cali_region; + appcfg->set("arrange", avoid_extrusion_key.c_str(), settings_out.avoid_extrusion_cali_region ? "1" : "0"); + settings_changed = true; + } + } else { + settings_out.avoid_extrusion_cali_region = false; } ImGui::Separator(); @@ -5016,6 +5676,55 @@ void GLCanvas3D::render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned } //BBS: GUI refractor + +void GLCanvas3D::_switch_toolbars_icon_filename() +{ + BackgroundTexture::Metadata background_data; + background_data.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; + background_data.left = 16; + background_data.top = 16; + background_data.right = 16; + background_data.bottom = 16; + m_main_toolbar.init(background_data); + m_assemble_view_toolbar.init(background_data); + m_separator_toolbar.init(background_data); + wxGetApp().plater()->get_collapse_toolbar().init(background_data); + + // main toolbar + { + GLToolbarItem* item; + item = m_main_toolbar.get_item("add"); + item->set_icon_filename(m_is_dark ? "toolbar_open_dark.svg" : "toolbar_open.svg"); + + item = m_main_toolbar.get_item("addplate"); + item->set_icon_filename(m_is_dark ? "toolbar_add_plate_dark.svg" : "toolbar_add_plate.svg"); + + item = m_main_toolbar.get_item("orient"); + item->set_icon_filename(m_is_dark ? "toolbar_orient_dark.svg" : "toolbar_orient.svg"); + + item = m_main_toolbar.get_item("addplate"); + item->set_icon_filename(m_is_dark ? "toolbar_add_plate_dark.svg" : "toolbar_add_plate.svg"); + + item = m_main_toolbar.get_item("arrange"); + item->set_icon_filename(m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg"); + + item = m_main_toolbar.get_item("splitobjects"); + item->set_icon_filename(m_is_dark ? "split_objects_dark.svg" : "split_objects.svg"); + + item = m_main_toolbar.get_item("splitvolumes"); + item->set_icon_filename(m_is_dark ? "split_parts_dark.svg" : "split_parts.svg"); + + item = m_main_toolbar.get_item("layersediting"); + item->set_icon_filename(m_is_dark ? "toolbar_variable_layer_height_dark.svg" : "toolbar_variable_layer_height.svg"); + } + + // assemble view toolbar + { + GLToolbarItem* item; + item = m_assemble_view_toolbar.get_item("assembly_view"); + item->set_icon_filename(m_is_dark ? "toolbar_assemble_dark.svg" : "toolbar_assemble.svg"); + } +} bool GLCanvas3D::_init_toolbars() { if (!_init_main_toolbar()) @@ -5049,7 +5758,7 @@ bool GLCanvas3D::_init_main_toolbar() return true; BackgroundTexture::Metadata background_data; - background_data.filename = "toolbar_background.png"; + background_data.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; background_data.left = 16; background_data.top = 16; background_data.right = 16; @@ -5086,10 +5795,12 @@ bool GLCanvas3D::_init_main_toolbar() m_main_toolbar.set_separator_size(5); m_main_toolbar.set_gap_size(4); + m_main_toolbar.del_all_item(); + GLToolbarItem::Data item; item.name = "add"; - item.icon_filename = "toolbar_open.svg"; + item.icon_filename = m_is_dark ? "toolbar_open_dark.svg" : "toolbar_open.svg"; item.tooltip = _utf8(L("Add")) + " [" + GUI::shortkey_ctrl_prefix() + "I]"; item.sprite_id = 0; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); }; @@ -5098,7 +5809,7 @@ bool GLCanvas3D::_init_main_toolbar() return false; item.name = "addplate"; - item.icon_filename = "toolbar_add_plate.svg"; + item.icon_filename = m_is_dark ? "toolbar_add_plate_dark.svg" : "toolbar_add_plate.svg"; item.tooltip = _utf8(L("Add plate")); item.sprite_id++; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD_PLATE)); }; @@ -5107,7 +5818,7 @@ bool GLCanvas3D::_init_main_toolbar() return false; item.name = "orient"; - item.icon_filename = "toolbar_orient.svg"; + item.icon_filename = m_is_dark ? "toolbar_orient_dark.svg" : "toolbar_orient.svg"; item.tooltip = _utf8(L("Auto orient")); item.sprite_id++; item.left.render_callback = nullptr; @@ -5127,7 +5838,7 @@ bool GLCanvas3D::_init_main_toolbar() return false; item.name = "arrange"; - item.icon_filename = "toolbar_arrange.svg"; + item.icon_filename = m_is_dark ? "toolbar_arrange_dark.svg" : "toolbar_arrange.svg"; item.tooltip = _utf8(L("Arrange all objects")) + " [A]\n" + _utf8(L("Arrange objects on selected plates")) + " [Shift+A]"; item.sprite_id++; item.left.action_callback = []() {}; @@ -5151,7 +5862,7 @@ bool GLCanvas3D::_init_main_toolbar() return false; item.name = "splitobjects"; - item.icon_filename = "split_objects.svg"; + item.icon_filename = m_is_dark ? "split_objects_dark.svg" : "split_objects.svg"; item.tooltip = _utf8(L("Split to objects")); item.sprite_id++; item.left.render_callback = nullptr; @@ -5162,7 +5873,7 @@ bool GLCanvas3D::_init_main_toolbar() return false; item.name = "splitvolumes"; - item.icon_filename = "split_parts.svg"; + item.icon_filename = m_is_dark ? "split_parts_dark.svg" : "split_parts.svg"; item.tooltip = _utf8(L("Split to parts")); item.sprite_id++; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; @@ -5171,6 +5882,23 @@ bool GLCanvas3D::_init_main_toolbar() if (!m_main_toolbar.add_item(item)) return false; + item.name = "layersediting"; + item.icon_filename = m_is_dark ? "toolbar_variable_layer_height_dark.svg" : "toolbar_variable_layer_height.svg"; + item.tooltip = _utf8(L("Variable layer height")); + item.sprite_id++; + item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; + item.visibility_callback = [this]()->bool { + bool res = current_printer_technology() == ptFFF; + // turns off if changing printer technology + if (!res && m_main_toolbar.is_item_visible("layersediting") && m_main_toolbar.is_item_pressed("layersediting")) + force_main_toolbar_left_action(get_main_toolbar_item_id("layersediting")); + + return res; + }; + item.enabling_callback = []()->bool { return wxGetApp().plater()->can_layers_editing(); }; + if (!m_main_toolbar.add_item(item)) + return false; + return true; } @@ -5213,7 +5941,7 @@ bool GLCanvas3D::_init_assemble_view_toolbar() return true; BackgroundTexture::Metadata background_data; - background_data.filename = "toolbar_background.png"; + background_data.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; background_data.left = 16; background_data.top = 16; background_data.right = 16; @@ -5234,9 +5962,11 @@ bool GLCanvas3D::_init_assemble_view_toolbar() m_assemble_view_toolbar.set_separator_size(10); m_assemble_view_toolbar.set_gap_size(4); + m_assemble_view_toolbar.del_all_item(); + GLToolbarItem::Data item; item.name = "assembly_view"; - item.icon_filename = "toolbar_assemble.svg"; + item.icon_filename = m_is_dark ? "toolbar_assemble_dark.svg" : "toolbar_assemble.svg"; item.tooltip = _utf8(L("Assembly View")); item.sprite_id = 1; item.left.toggable = false; @@ -5267,9 +5997,8 @@ bool GLCanvas3D::_init_separator_toolbar() if (!m_separator_toolbar.is_enabled()) return true; - BackgroundTexture::Metadata background_data; - background_data.filename = "toolbar_background.png"; + background_data.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; background_data.left = 0; background_data.top = 0; background_data.right = 0; @@ -5288,6 +6017,8 @@ bool GLCanvas3D::_init_separator_toolbar() m_separator_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Top); m_separator_toolbar.set_border(5.0f); + m_separator_toolbar.del_all_item(); + GLToolbarItem::Data sperate_item; sperate_item.name = "start_seperator"; sperate_item.icon_filename = "seperator.svg"; @@ -5619,18 +6350,21 @@ void GLCanvas3D::_render_background() const ::glBegin(GL_QUADS); + float* background_color = m_is_dark ? DEFAULT_BG_LIGHT_COLOR_DARK : DEFAULT_BG_LIGHT_COLOR; + float* error_background_color = m_is_dark ? ERROR_BG_LIGHT_COLOR_DARK : ERROR_BG_LIGHT_COLOR; + if (use_error_color) - ::glColor3fv(ERROR_BG_LIGHT_COLOR); + ::glColor3fv(error_background_color); else - ::glColor3fv(DEFAULT_BG_LIGHT_COLOR); + ::glColor3fv(background_color); ::glVertex2f(-1.0f, -1.0f); ::glVertex2f(1.0f, -1.0f); if (use_error_color) - ::glColor3fv(ERROR_BG_LIGHT_COLOR); + ::glColor3fv(error_background_color); else - ::glColor3fv(DEFAULT_BG_LIGHT_COLOR); + ::glColor3fv(background_color); ::glVertex2f(1.0f, 1.0f); ::glVertex2f(-1.0f, 1.0f); @@ -5699,6 +6433,10 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with m_camera_clipping_plane = m_gizmos.get_clipping_plane(); + if (m_picking_enabled) + // Update the layer editing selection to the first object selected, update the current object maximum Z. + m_layers_editing.select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1); + if (const BuildVolume &build_volume = m_bed.build_volume(); build_volume.valid()) { switch (build_volume.type()) { case BuildVolume::Type::Rectangle: { @@ -5754,25 +6492,39 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with case GLVolumeCollection::ERenderType::Opaque: { const GLGizmosManager& gm = get_gizmos_manager(); - // GLGizmosManager::EType type = gm.get_current_type(); if (dynamic_cast(gm.get_current()) == nullptr) { - //BBS:add assemble view related logic - // do not cull backfaces to show broken geometry, if any - m_volumes.render(type, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { - if (canvas_type == ECanvasType::CanvasAssembleView) { - return !volume.is_modifier && !volume.is_wipe_tower; - } - else { - return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); - } - }, with_outline); + if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { + int object_id = m_layers_editing.last_object_id; + m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) { + // Which volume to paint without the layer height profile shader? + return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); + }); + m_layers_editing.render_volumes(*this, m_volumes); + } + else { + /*if (wxGetApp().plater()->is_wireframe_enabled()) { + if (wxGetApp().plater()->is_show_wireframe()) + shader->set_uniform("show_wireframe", true); + else + shader->set_uniform("show_wireframe", false); + }*/ + //BBS:add assemble view related logic + // do not cull backfaces to show broken geometry, if any + m_volumes.render(type, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { + if (canvas_type == ECanvasType::CanvasAssembleView) { + return !volume.is_modifier && !volume.is_wipe_tower; + } + else { + return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); + } + }, with_outline); + } } else { // In case a painting gizmo is open, it should render the painted triangles // before transparent objects are rendered. Otherwise they would not be // visible when inside modifier meshes etc. - // GLGizmosManager::EType type = gm.get_current_type(); if (dynamic_cast(gm.get_current())) { shader->stop_using(); @@ -5785,6 +6537,12 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } case GLVolumeCollection::ERenderType::Transparent: { + /*if (wxGetApp().plater()->is_wireframe_enabled()) { + if (wxGetApp().plater()->is_show_wireframe()) + shader->set_uniform("show_wireframe", true); + else + shader->set_uniform("show_wireframe", false); + }*/ //BBS:add assemble view related logic m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { @@ -5804,6 +6562,10 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } } + /*if (wxGetApp().plater()->is_wireframe_enabled()) { + shader->set_uniform("show_wireframe", false); + }*/ + shader->stop_using(); } @@ -6016,10 +6778,10 @@ void GLCanvas3D::_render_overlays() _render_separator_toolbar_right(); _render_separator_toolbar_left(); _render_main_toolbar(); - //BBS: GUI refactor: GLToolbar - _render_imgui_select_plate_toolbar(); _render_collapse_toolbar(); _render_assemble_view_toolbar(); + //BBS: GUI refactor: GLToolbar + _render_imgui_select_plate_toolbar(); _render_return_toolbar(); // BBS //_render_view_toolbar(); @@ -6029,6 +6791,9 @@ void GLCanvas3D::_render_overlays() //move gizmos behind of main _render_gizmos_overlay(); + if (m_layers_editing.last_object_id >= 0 && m_layers_editing.object_max_z() > 0.0f) + m_layers_editing.render_overlay(*this); + const ConfigOptionEnum* opt = dynamic_cast*>(m_config->option>("print_sequence")); bool sequential_print = opt != nullptr && (opt->value == PrintSequence::ByObject); std::vector sorted_instances; @@ -6717,7 +7482,8 @@ void GLCanvas3D::_render_assemble_control() const auto canvas_h = float(get_canvas_size().get_height()); const float text_padding = 7.0f; - const float text_size_x = std::max(imgui->calc_text_size(_L("Explosion Ratio")).x, imgui->calc_text_size(_L("Section View")).x); + const float text_size_x = std::max(imgui->calc_text_size(_L("Reset direction")).x + 2 * ImGui::GetStyle().FramePadding.x, + std::max(imgui->calc_text_size(_L("Explosion Ratio")).x, imgui->calc_text_size(_L("Section View")).x)); const float slider_width = 75.0f; const float value_size = imgui->calc_text_size("3.00").x + text_padding * 2; const float item_spacing = imgui->get_item_spacing().x; @@ -6729,11 +7495,21 @@ void GLCanvas3D::_render_assemble_control() const ImGui::AlignTextToFramePadding(); { - imgui->text(_L("Section View")); + float clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position(); + if (clp_dist == 0.f) { + ImGui::AlignTextToFramePadding(); + imgui->text(_L("Section View")); + } + else { + if (imgui->button(_L("Reset direction"))) { + wxGetApp().CallAfter([this]() { + m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(-1., false); + }); + } + } ImGui::SameLine(window_padding.x + text_size_x + item_spacing); ImGui::PushItemWidth(slider_width); - static float clp_dist = 0.f; bool view_slider_changed = imgui->bbl_slider_float_style("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f", 1.0f, true); ImGui::SameLine(window_padding.x + text_size_x + slider_width + item_spacing * 2); @@ -7046,6 +7822,29 @@ void GLCanvas3D::_update_volumes_hover_state() } } +void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt) +{ + int object_idx_selected = m_layers_editing.last_object_id; + if (object_idx_selected == -1) + return; + + // A volume is selected. Test, whether hovering over a layer thickness bar. + if (evt != nullptr) { + const Rect& rect = LayersEditing::get_bar_rect_screen(*this); + float b = rect.get_bottom(); + m_layers_editing.last_z = m_layers_editing.object_max_z() * (b - evt->GetY() - 1.0f) / (b - rect.get_top()); + m_layers_editing.last_action = + evt->ShiftDown() ? (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_SMOOTH : LAYER_HEIGHT_EDIT_ACTION_REDUCE) : + (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_INCREASE : LAYER_HEIGHT_EDIT_ACTION_DECREASE); + } + + m_layers_editing.adjust_layer_height_profile(); + _refresh_if_shown_on_screen(); + + // Automatic action on mouse down with the same coordinate. + _start_timer(); +} + Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z) { if (m_canvas == nullptr) @@ -7743,7 +8542,7 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) break; case SLICING_ERROR: if (state) - notification_manager.push_slicing_error_notification(text); + notification_manager.push_slicing_error_notification(text, nullptr); else notification_manager.close_slicing_error_notification(text); break; @@ -7867,6 +8666,17 @@ bool GLCanvas3D::_deactivate_orient_menu() return false; } +//BBS: add deactivate layersediting menu +bool GLCanvas3D::_deactivate_layersediting_menu() +{ + if (m_main_toolbar.is_item_pressed("layersediting")) { + m_main_toolbar.force_left_action(m_main_toolbar.get_item_id("layersediting"), *this); + return true; + } + + return false; +} + bool GLCanvas3D::_deactivate_collapse_toolbar_items() { GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 452cd0add2..e91588b72e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -188,6 +188,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, wxTimerEvent); wxDECLARE_EVENT(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, wxTimerEvent); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE, SimpleEvent); wxDECLARE_EVENT(EVT_CUSTOMEVT_TICKSCHANGED, wxCommandEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); +wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); class GLCanvas3D { @@ -198,10 +201,116 @@ class GLCanvas3D static float DEFAULT_BG_LIGHT_COLOR[3]; static float ERROR_BG_LIGHT_COLOR[3]; + static float DEFAULT_BG_LIGHT_COLOR_LIGHT[3]; + static float ERROR_BG_LIGHT_COLOR_LIGHT[3]; + static float DEFAULT_BG_LIGHT_COLOR_DARK[3]; + static float ERROR_BG_LIGHT_COLOR_DARK[3]; static void update_render_colors(); static void load_render_colors(); + class LayersEditing + { + public: + enum EState : unsigned char + { + Unknown, + Editing, + Completed, + Num_States + }; + + static const float THICKNESS_BAR_WIDTH; + + private: + bool m_enabled{ false }; + unsigned int m_z_texture_id{ 0 }; + // Not owned by LayersEditing. + const DynamicPrintConfig* m_config{ nullptr }; + // ModelObject for the currently selected object (Model::objects[last_object_id]). + const ModelObject* m_model_object{ nullptr }; + // Maximum z of the currently selected object (Model::objects[last_object_id]). + float m_object_max_z{ 0.0f }; + // Owned by LayersEditing. + SlicingParameters* m_slicing_parameters{ nullptr }; + std::vector m_layer_height_profile; + + mutable float m_adaptive_quality{ 0.5f }; + mutable HeightProfileSmoothingParams m_smooth_params; + + static float s_overlay_window_width; + + struct LayersTexture + { + // Texture data + std::vector data; + // Width of the texture, top level. + size_t width{ 0 }; + // Height of the texture, top level. + size_t height{ 0 }; + // For how many levels of detail is the data allocated? + size_t levels{ 0 }; + // Number of texture cells allocated for the height texture. + size_t cells{ 0 }; + // Does it need to be refreshed? + bool valid{ false }; + }; + LayersTexture m_layers_texture; + + public: + EState state{ Unknown }; + float band_width{ 2.0f }; + float strength{ 0.005f }; + int last_object_id{ -1 }; + float last_z{ 0.0f }; + LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE }; + + LayersEditing() = default; + ~LayersEditing(); + + void init(); + + void set_config(const DynamicPrintConfig* config); + void select_object(const Model& model, int object_id); + + bool is_allowed() const; + + bool is_enabled() const; + void set_enabled(bool enabled); + + void show_tooltip_information(const GLCanvas3D& canvas, std::map captions_texts, float x, float y); + void render_variable_layer_height_dialog(const GLCanvas3D& canvas); + void render_overlay(const GLCanvas3D& canvas); + void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes); + + void adjust_layer_height_profile(); + void accept_changes(GLCanvas3D& canvas); + void reset_layer_height_profile(GLCanvas3D& canvas); + void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor); + void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params); + + static float get_cursor_z_relative(const GLCanvas3D& canvas); + static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); + static Rect get_bar_rect_screen(const GLCanvas3D& canvas); + static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); + static float get_overlay_window_width() { return LayersEditing::s_overlay_window_width; } + + float object_max_z() const { return m_object_max_z; } + + std::string get_tooltip(const GLCanvas3D& canvas) const; + + private: + bool is_initialized() const; + void generate_layer_height_texture(); + + void render_background_texture(const GLCanvas3D& canvas, const Rect& bar_rect); + void render_curve(const Rect& bar_rect); + + void update_slicing_parameters(); + + static float thickness_bar_width(const GLCanvas3D& canvas); + }; + struct Mouse { struct Drag @@ -385,6 +494,7 @@ public: }; private: + bool m_is_dark = false; wxGLCanvas* m_canvas; wxGLContext* m_context; Bed3D &m_bed; @@ -394,6 +504,7 @@ private: unsigned int m_last_w, m_last_h; bool m_in_render; wxTimer m_timer; + LayersEditing m_layers_editing; Mouse m_mouse; GLGizmosManager m_gizmos; //BBS: GUI refactor: GLToolbar @@ -593,6 +704,8 @@ public: bool init(); void post_event(wxEvent &&event); + void on_change_color_mode(bool is_dark, bool reinit = true); + const bool get_dark_mode_status() { return m_is_dark; } void set_as_dirty(); void requires_check_outside_state() { m_requires_check_outside_state = true; } @@ -655,8 +768,16 @@ public: BoundingBoxf3 scene_bounding_box() const; BoundingBoxf3 plate_scene_bounding_box(int plate_idx) const; + bool is_layers_editing_enabled() const; + bool is_layers_editing_allowed() const; + + void reset_layer_height_profile(); + void adaptive_layer_height_profile(float quality_factor); + void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params); + bool is_reload_delayed() const; + void enable_layers_editing(bool enable); void enable_legend_texture(bool enable); void enable_picking(bool enable); void enable_moving(bool enable); @@ -914,6 +1035,8 @@ public: bool is_object_sinking(int object_idx) const; + void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); + // Convert the screen space coordinate to an object space coordinate. // If the Z screen space coordinate is not provided, a depth buffer value is substituted. Vec3d _mouse_to_3d(const Point& mouse_pos, float* z = nullptr); @@ -921,6 +1044,7 @@ public: private: bool _is_shown_on_screen() const; + void _switch_toolbars_icon_filename(); bool _init_toolbars(); bool _init_main_toolbar(); bool _init_select_plate_toolbar(); @@ -1030,9 +1154,11 @@ private: bool _deactivate_arrange_menu(); //BBS: add deactivate_orient_menu bool _deactivate_orient_menu(); + //BBS: add _deactivate_layersediting_menu + bool _deactivate_layersediting_menu(); // BBS FIXME - float get_overlay_window_width() { return 100.f; } + float get_overlay_window_width() { return 0; /*LayersEditing::get_overlay_window_width();*/ } static std::vector> _parse_colors(const std::vector& colors); }; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 74668fb20b..e4ed4555cb 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -45,6 +45,7 @@ std::pair GLShadersManager::init() // used to render extrusion and travel paths as lines in gcode preview valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" }); // used to render objects in 3d editor + //if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) { if (0) { valid &= append_shader("gouraud", { "gouraud_130.vs", "gouraud_130.fs" } #if ENABLE_ENVIRONMENT_MAP @@ -69,10 +70,18 @@ std::pair GLShadersManager::init() // Based on https://stackoverflow.com/a/66206648, the similar behavior was also spotted on some other devices with Arm CPU. // Since macOS 12 (Monterey), this issue with the opposite direction on Apple's Arm CPU seems to be fixed, and computed // triangle normals inside fragment shader have the right direction. - if (platform_flavor() == PlatformFlavor::OSXOnArm && wxPlatformInfo::Get().GetOSMajorVersion() < 12) - valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}, {"FLIP_TRIANGLE_NORMALS"sv}); - else - valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}); + if (platform_flavor() == PlatformFlavor::OSXOnArm && wxPlatformInfo::Get().GetOSMajorVersion() < 12) { + //if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) + valid &= append_shader("mm_gouraud", {"mm_gouraud_130.vs", "mm_gouraud_130.fs"}, {"FLIP_TRIANGLE_NORMALS"sv}); + //else + // valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}, {"FLIP_TRIANGLE_NORMALS"sv}); + } + else { + //if (GUI::wxGetApp().is_gl_version_greater_or_equal_to(3, 0)) + valid &= append_shader("mm_gouraud", {"mm_gouraud_wireframe.vs", "mm_gouraud_wireframe.fs"}); + //else + // valid &= append_shader("mm_gouraud", {"mm_gouraud.vs", "mm_gouraud.fs"}); + } //BBS: add shader for outline valid &= append_shader("outline", { "outline.vs", "outline.fs" }); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index e45795e363..d5082c8862 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -26,7 +26,8 @@ #include "nanosvg/nanosvgrast.h" #include "libslic3r/Utils.hpp" - +#include "GUI_App.hpp" +#include namespace Slic3r { namespace GUI { @@ -244,6 +245,8 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorget("dark_color_mode") == "1"; + // every tile needs to have a 1px border around it to avoid artifacts when linear sampling on its edges unsigned int sprite_size_px_ex = sprite_size_px + 1; @@ -262,14 +265,23 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector data(n_pixels * 4, 0); std::vector sprite_data(sprite_bytes, 0); - std::vector sprite_white_only_data(sprite_bytes, 0); - std::vector sprite_gray_only_data(sprite_bytes, 0); + std::vector sprite_white_only_data(sprite_bytes, 0); // normal + std::vector sprite_gray_only_data(sprite_bytes, 0); // disable std::vector output_data(sprite_bytes, 0); //BBS - std::vector pressed_data(sprite_bytes, 0); + std::vector pressed_data(sprite_bytes, 0); // (gizmo) pressed std::vector disable_data(sprite_bytes, 0); - std::vector hover_data(sprite_bytes, 0); + std::vector hover_data(sprite_bytes, 0); // hover + + const unsigned char pressed_color[3] = {255, 255, 255}; + const unsigned char hover_color[3] = {255, 255, 255}; + const unsigned char normal_color[3] = {43, 52, 54}; + const unsigned char disable_color[3] = {200, 200, 200}; + const unsigned char pressed_color_dark[3] = {60, 60, 65}; + const unsigned char hover_color_dark[3] = {60, 60, 65}; + const unsigned char normal_color_dark[3] = {182, 182, 182}; + const unsigned char disable_color_dark[3] = {76, 76, 85}; NSVGrasterizer* rast = nsvgCreateRasterizer(); if (rast == nullptr) { @@ -299,12 +311,13 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector data(4 * m_width * m_height, 0); - const unsigned char *src = image.GetData(); + const unsigned char* src = image.GetData(); /* for debug use std::ofstream fout; fout.open(text_str+std::to_string(m_width)+"_"+std::to_string(m_height)+".rgb", std::ios::out); @@ -506,7 +527,7 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f *dst++ = foreground.Red(); *dst++ = foreground.Green(); *dst++ = foreground.Blue(); - *dst++ = (unsigned char)std::min(255, *src); + *dst++ = (unsigned char)std::min(255, *src); src += 3; } } @@ -516,9 +537,9 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); if (GLEW_EXT_texture_compression_s3tc) - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -527,6 +548,111 @@ bool GLTexture::generate_from_text_string(const std::string &text_str, wxFont &f return true; } +bool GLTexture::generate_texture_from_text(const std::string& text_str, wxFont& font, int& ww, int& hh, int& hl, wxColor background, wxColor foreground) +{ + if (text_str.empty()) + { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":no text string, should not happen\n"; + return false; + } + + wxString msg = _(text_str); + wxMemoryDC memDC; + + memDC.SetFont(font); + + // calculates texture size + wxCoord w, h, ll; + wxClientDC dc(wxGetApp().GetTopWindow()); + dc.SetFont(font); + dc.GetMultiLineTextExtent(msg, &w, &h, &ll, &font); + + + m_original_width = (int)w; + m_original_height = (int)h; + m_width = (int)next_highest_power_of_2((uint32_t)w); + m_height = (int)next_highest_power_of_2((uint32_t)h); + ww = m_width; + hh = m_height; + hl = ll; + // generates bitmap + wxBitmap bitmap(m_width, m_height); + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(background)); + memDC.Clear(); + + // draw message + memDC.SetTextForeground(*wxWHITE); + + wxGCDC dc2(memDC); + dc2.SetFont(font); + dc2.SetBackground(wxBrush(background)); + dc2.SetTextForeground(*wxWHITE); + dc2.DrawLabel(msg, wxRect(0, 0, m_width, m_height), wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + + memDC.SelectObject(wxNullBitmap); + + // Convert the bitmap into a linear data ready to be loaded into the GPU. + wxImage image = bitmap.ConvertToImage(); + + // prepare buffer + std::vector data(4 * m_width * m_height, 0); + const unsigned char* src = image.GetData(); + /* for debug use + std::ofstream fout; + fout.open(text_str+std::to_string(m_width)+"_"+std::to_string(m_height)+".rgb", std::ios::out); + fout.write((const char*)src, 3 * m_width * m_height); + fout.close();*/ + bool found = false; + for (int h = 0; h < m_height; ++h) { + unsigned char* dst = data.data() + 4 * h * m_width; + for (int w = 0; w < m_width; ++w) { + *dst++ = foreground.Red(); + *dst++ = foreground.Green(); + *dst++ = foreground.Blue(); + *dst++ = (unsigned char)std::min(255, *src); + if ((*src) != background.Red() && !found) { + found = true; + if (m_height - h < font.GetPointSize()) + return false; + } + src += 3; + } + } + if (!found) + return false; + + found = false; + src -= 3; + for (int h = m_height; h > 0; --h) { + for (int w = m_width; w > 0; --w) { + if ((*src) != background.Red() && !found) { + found = true; + if (h < font.GetPointSize()) + return false; + } + src -= 3; + } + } + if (!found) + return false; + + // sends buffer to gpu + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + glsafe(::glGenTextures(1, &m_id)); + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); + if (GLEW_EXT_texture_compression_s3tc) + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + else + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); + + return true; +} void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { @@ -776,7 +902,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo int lod_w = m_width; int lod_h = m_height; GLint level = 0; - while (lod_w > 1 || lod_h > 1) { + while (lod_w >= 4 && lod_h >= 4) { ++level; lod_w = std::max(lod_w / 2, 1); diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index 4649b9f68e..53fbe1a6ad 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -106,7 +106,10 @@ namespace GUI { //BBS: add generate logic for text strings int m_original_width; int m_original_height; - bool generate_from_text_string(const std::string &text_str, wxFont &font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + + bool generate_texture_from_text(const std::string& text_str, wxFont& font, int& ww, int& hh, int &hl, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + bool generate_from_text(const std::string& text_str, wxFont& font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); + bool generate_from_text_string(const std::string& text_str, wxFont& font, wxColor background = *wxBLACK, wxColor foreground = *wxWHITE); unsigned int get_id() const { return m_id; } int get_width() const { return m_width; } diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 24e84ef535..6a78edd907 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -27,8 +27,10 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_EXPORT_GCODE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SEND_GCODE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_UPLOAD_GCODE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_EXPORT_SLICED_FILE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_PRINT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER, SimpleEvent); +wxDEFINE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); @@ -40,13 +42,13 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); +wxDEFINE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); //BBS: add clone event wxDEFINE_EVENT(EVT_GLTOOLBAR_CLONE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_VOLUMES, SimpleEvent); -wxDEFINE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_FILLCOLOR, IntEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_SELECT_SLICED_PLATE, wxCommandEvent); @@ -267,9 +269,6 @@ GLToolbar::~GLToolbar() bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture) { - if (m_background_texture.texture.get_id() != 0) - return true; - std::string path = resources_dir() + "/images/"; bool res = false; diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 3c96d9f860..09da22d3cd 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -27,8 +27,10 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_EXPORT_GCODE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SEND_GCODE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_UPLOAD_GCODE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_EXPORT_SLICED_FILE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_PRINT_SELECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER, SimpleEvent); +wxDECLARE_EVENT(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); @@ -40,6 +42,7 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); +wxDECLARE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); //BBS: add clone event wxDECLARE_EVENT(EVT_GLTOOLBAR_CLONE, SimpleEvent); wxDECLARE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); @@ -183,6 +186,7 @@ public: const std::string& get_name() const { return m_data.name; } const std::string& get_icon_filename() const { return m_data.icon_filename; } + void set_icon_filename(const std::string& filename) { m_data.icon_filename = filename; } const std::string& get_tooltip() const { return m_data.tooltip; } const std::string& get_additional_tooltip() const { return m_data.additional_tooltip; } void set_additional_tooltip(const std::string& text) { m_data.additional_tooltip = text; } @@ -354,6 +358,7 @@ public: Layout::EType get_layout_type() const; void set_layout_type(Layout::EType type); + void set_icon_dirty() { m_icons_texture_dirty = true; } Layout::EHorizontalOrientation get_horizontal_orientation() const { return m_layout.horizontal_orientation; } void set_horizontal_orientation(Layout::EHorizontalOrientation orientation) { m_layout.horizontal_orientation = orientation; } Layout::EVerticalOrientation get_vertical_orientation() const { return m_layout.vertical_orientation; } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 1d9fa035da..567a1e9191 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -4,7 +4,9 @@ #include "I18N.hpp" #include "libslic3r/LocalesUtils.hpp" - +#ifdef __APPLE__ +#include "slic3r/Utils/MacDarkMode.hpp" +#endif #include #include @@ -545,11 +547,9 @@ void desktop_open_any_folder( const std::string path ) #ifdef _WIN32 const wxString widepath = from_u8(path); - const wchar_t *argv[] = {L"explorer", widepath.GetData(), nullptr}; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + ::wxExecute(L"explorer /select," + widepath, wxEXEC_ASYNC, nullptr); #elif __APPLE__ - const char *argv[] = {"open", path.data(), nullptr}; - ::wxExecute(const_cast(argv), wxEXEC_ASYNC, nullptr); + openFolderForFile(from_u8(path)); #else const char *argv[] = {"xdg-open", path.data(), nullptr}; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index d195402015..994852ca30 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -88,6 +88,7 @@ #include "WebGuideDialog.hpp" #include "WebUserLoginDialog.hpp" #include "ReleaseNote.hpp" +#include "ModelMall.hpp" //#ifdef WIN32 //#include "BaseException.h" @@ -97,9 +98,15 @@ #ifdef __WXMSW__ #include #include + +#ifdef __WINDOWS__ #ifdef _MSW_DARK_MODE -#include +#include "dark_mode.hpp" +#include "wx/headerctrl.h" +#include "wx/msw/headerctrl.h" #endif // _MSW_DARK_MODE +#endif // __WINDOWS__ + #endif #ifdef _WIN32 #include @@ -223,6 +230,7 @@ public: // draw logo and constant info text Decorate(m_main_bitmap); + wxGetApp().UpdateFrameDarkUI(this); } void SetText(const wxString& text) @@ -234,7 +242,7 @@ public: wxMemoryDC memDC; memDC.SelectObject(bitmap); memDC.SetFont(m_action_font); - memDC.SetTextForeground(wxColour(144, 144, 144)); + memDC.SetTextForeground(StateColor::darkModeColorFor(wxColour(144, 144, 144))); int width = bitmap.GetWidth(); int text_height = memDC.GetTextExtent(text).GetHeight(); int text_width = memDC.GetTextExtent(text).GetWidth(); @@ -271,13 +279,13 @@ public: int version_width = memDc.GetTextExtent(m_constant_text.version).GetWidth(); int split_width = (width + title_width - version_width) / 2; wxRect title_rect(wxPoint(0, top_margin), wxPoint(split_width - text_padding, top_margin + title_height)); - memDc.SetTextForeground(wxColour(38, 46, 48)); + memDc.SetTextForeground(StateColor::darkModeColorFor(wxColour(38, 46, 48))); memDc.SetFont(m_constant_text.title_font); memDc.DrawLabel(m_constant_text.title, title_rect, wxALIGN_RIGHT | wxALIGN_BOTTOM); //BBS align bottom of title and version text wxRect version_rect(wxPoint(split_width + text_padding, top_margin), wxPoint(width, top_margin + title_height - text_padding)); memDc.SetFont(m_constant_text.version_font); - memDc.SetTextForeground(wxColor(134, 134, 134)); + memDc.SetTextForeground(StateColor::darkModeColorFor(wxColor(134, 134, 134))); memDc.DrawLabel(m_constant_text.version, version_rect, wxALIGN_LEFT | wxALIGN_BOTTOM); // #if BBL_INTERNAL_TESTING @@ -294,9 +302,10 @@ public: BitmapCache bmp_cache; int logo_margin = FromDIP(72 * m_scale); int logo_size = FromDIP(122 * m_scale); + int logo_width = FromDIP(94 * m_scale); wxBitmap logo_bmp = *bmp_cache.load_svg("splash_logo", logo_size, logo_size); int logo_y = top_margin + title_rect.GetHeight() + logo_margin; - memDc.DrawBitmap(logo_bmp, (width - logo_size) / 2, logo_y, true); + memDc.DrawBitmap(logo_bmp, (width - logo_width) / 2, logo_y, true); // calculate position for the dynamic text int text_margin = FromDIP(80 * m_scale); @@ -313,7 +322,7 @@ public: wxMemoryDC memDC; memDC.SelectObject(new_bmp); - memDC.SetBrush(*wxWHITE); + memDC.SetBrush(StateColor::darkModeColorFor(*wxWHITE)); memDC.DrawRectangle(-1, -1, width + 2, height + 2); memDC.DrawBitmap(new_bmp, 0, 0, true); return new_bmp; @@ -387,7 +396,7 @@ private: title = wxGetApp().is_editor() ? SLIC3R_APP_FULL_NAME : GCODEVIEWER_APP_NAME; // dynamically get the version to display - version = _L("V") + " " + std::string(SLIC3R_VERSION); + version = _L("V") + " " + GUI_App::format_display_version(); // credits infornation credits = ""; @@ -720,7 +729,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = { /* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } }, /* FT_3MF */ { "3MF files"sv, { ".3mf"sv } }, /* FT_GCODE */ { "G-code files"sv, { ".gcode"sv } }, - /* FT_MODEL */ { "Supported files"sv, { ".3mf"sv, ".stl"sv, ".stp"sv, ".step"sv, ".amf"sv, ".obj"sv } }, + /* FT_MODEL */ {"Supported files"sv, {".3mf"sv, ".stl"sv, ".stp"sv, ".step"sv, ".svg"sv, ".amf"sv, ".obj"sv }}, /* FT_PROJECT */ { "Project files"sv, { ".3mf"sv} }, /* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } }, @@ -994,7 +1003,12 @@ void GUI_App::post_init() } } } -#if BBL_HAS_FIRST_PAGE +//#if BBL_HAS_FIRST_PAGE + bool slow_bootup = false; + if (app_config->get("slow_bootup") == "true") { + slow_bootup = true; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", slow bootup, won't render gl here."; + } if (!switch_to_3d) { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", begin load_gl_resources"; mainframe->Freeze(); @@ -1015,17 +1029,19 @@ void GUI_App::post_init() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished init imgui frame"; plater_->canvas3D()->enable_render(true); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", start to render a first frame for test"; - plater_->canvas3D()->render(false); - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test"; + if (!slow_bootup) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", start to render a first frame for test"; + plater_->canvas3D()->render(false); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished rendering a first frame for test"; + } if (is_editor()) mainframe->select_tab(size_t(0)); mainframe->Thaw(); plater_->trigger_restore_project(1); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", end load_gl_resources"; } -#endif +//#endif //BBS: remove GCodeViewer as seperate APP logic /*if (this->init_params->start_as_gcodeviewer) { @@ -1068,8 +1084,9 @@ void GUI_App::post_init() // BBS: to be checked #if 1 // show "Did you know" notification - if (app_config->get("show_hints") == "true" && ! is_gcode_viewer()) - plater_->get_notification_manager()->push_hint_notification(true); + if (app_config->get("show_hints") == "true" && !is_gcode_viewer()) { + plater_->get_notification_manager()->push_hint_notification(false); + } #endif if (m_networking_need_update) { @@ -1146,8 +1163,11 @@ void GUI_App::post_init() std::vector> files_vec; for (auto& it : boost::filesystem::directory_iterator(log_folder)) { auto temp_path = it.path(); - std::time_t lw_t = boost::filesystem::last_write_time(temp_path) ; - files_vec.push_back({ lw_t, temp_path.filename().string() }); + try { + std::time_t lw_t = boost::filesystem::last_write_time(temp_path) ; + files_vec.push_back({ lw_t, temp_path.filename().string() }); + } catch (const std::exception &ex) { + } } std::sort(files_vec.begin(), files_vec.end(), []( std::pair &a, std::pair &b) { @@ -1167,7 +1187,6 @@ void GUI_App::post_init() } } } - BOOST_LOG_TRIVIAL(info) << "finished post_init"; //BBS: remove the single instance currently /*#ifdef _WIN32 @@ -1179,7 +1198,7 @@ void GUI_App::post_init() wxDEFINE_EVENT(EVT_ENTER_FORCE_UPGRADE, wxCommandEvent); wxDEFINE_EVENT(EVT_SHOW_NO_NEW_VERSION, wxCommandEvent); wxDEFINE_EVENT(EVT_SHOW_DIALOG, wxCommandEvent); - +wxDEFINE_EVENT(EVT_CONNECT_LAN_MODE_PRINT, wxCommandEvent); IMPLEMENT_APP(GUI_App) //BBS: remove GCodeViewer as seperate APP logic @@ -1256,13 +1275,13 @@ std::string GUI_App::get_http_url(std::string country_code) return url; } -std::string GUI_App::get_plugin_url(std::string country_code) +std::string GUI_App::get_plugin_url(std::string name, std::string country_code) { std::string url = get_http_url(country_code); std::string curr_version = SLIC3R_VERSION; std::string using_version = curr_version.substr(0, 9) + "00"; - url += (boost::format("?slicer/plugins/cloud=%1%") % using_version).str(); + url += (boost::format("?slicer/%1%/cloud=%2%") % name % using_version).str(); //url += (boost::format("?slicer/plugins/cloud=%1%") % "01.01.00.00").str(); return url; } @@ -1282,7 +1301,7 @@ static std::string decode(std::string const& extra, std::string const& path = {} return Slic3r::decode_path(path.c_str()); } -int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn) +int GUI_App::download_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn, WasCancelledFn cancel_fn) { int result = 0; // get country_code @@ -1293,16 +1312,18 @@ int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn) BOOST_LOG_TRIVIAL(info) << "[download_plugin]: enter"; m_networking_cancel_update = false; // get temp path - fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip"); + fs::path target_file_path = (fs::temp_directory_path() / package_name); fs::path tmp_path = target_file_path; tmp_path += format(".%1%%2%", get_current_pid(), ".tmp"); // get_url - std::string url = get_plugin_url(app_config->get_country_code()); + std::string url = get_plugin_url(name, app_config->get_country_code()); std::string download_url; Slic3r::Http http_url = Slic3r::Http::get(url); BOOST_LOG_TRIVIAL(info) << "[download_plugin]: check the plugin from " << url; - http_url.on_complete( + http_url.timeout_connect(TIMEOUT_CONNECT) + .timeout_max(TIMEOUT_RESPONSE) + .on_complete( [&download_url](std::string body, unsigned status) { try { json j = json::parse(body); @@ -1415,16 +1436,16 @@ int GUI_App::download_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn) return result; } -int GUI_App::install_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn) +int GUI_App::install_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn, WasCancelledFn cancel_fn) { bool cancel = false; - std::string target_file_path = (fs::temp_directory_path() / "network_plugin.zip").string(); + std::string target_file_path = (fs::temp_directory_path() / package_name).string(); BOOST_LOG_TRIVIAL(info) << "[install_plugin] enter"; // get plugin folder std::string data_dir_str = data_dir(); boost::filesystem::path data_dir_path(data_dir_str); - auto plugin_folder = data_dir_path / "plugins"; + auto plugin_folder = data_dir_path / name; //auto plugin_folder = boost::filesystem::path(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()) / "plugins"; auto backup_folder = plugin_folder/"backup"; if (!boost::filesystem::exists(plugin_folder)) { @@ -1531,7 +1552,8 @@ int GUI_App::install_plugin(InstallProgressFn pro_fn, WasCancelledFn cancel_fn) if (pro_fn) pro_fn(InstallStatusInstallCompleted, 100, cancel); - app_config->set_str("app", "installed_networking", "1"); + if (name == "plugins") + app_config->set_str("app", "installed_networking", "1"); BOOST_LOG_TRIVIAL(info) << "[install_plugin] success"; return 0; } @@ -1674,13 +1696,19 @@ void GUI_App::init_networking_callbacks() } /* request_pushing */ MachineObject* obj = m_device_manager->get_my_machine(dev_id); + wxCommandEvent event(EVT_CONNECT_LAN_MODE_PRINT); + if (obj) { + if (obj->is_lan_mode_printer()) { if (state == ConnectStatus::ConnectStatusOk) { obj->command_request_push_all(); obj->command_get_version(); + event.SetInt(1); + event.SetString(obj->dev_id); } else if (state == ConnectStatus::ConnectStatusFailed) { obj->set_access_code(""); + m_device_manager->set_selected_machine(""); wxString text; if (msg == "5") { text = wxString::Format(_L("Incorrect password")); @@ -1689,14 +1717,21 @@ void GUI_App::init_networking_callbacks() text = wxString::Format(_L("Connect %s failed! [SN:%s, code=%s]"), from_u8(obj->dev_name), obj->dev_id, msg); wxGetApp().show_dialog(text); } + event.SetInt(0); } else if (state == ConnectStatus::ConnectStatusLost) { m_device_manager->set_selected_machine(""); + event.SetInt(0); BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = lost"; } else { + event.SetInt(0); BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = " << state; } + + obj->set_lan_mode_connection_state(false); } } + event.SetEventObject(this); + wxPostEvent(this, event); }); } ); @@ -1729,14 +1764,15 @@ void GUI_App::init_networking_callbacks() CallAfter([this, dev_id, msg] { if (m_is_closing) return; + MachineObject* obj = m_device_manager->get_my_machine(dev_id); - if (!obj) { + if (!obj || !obj->is_lan_mode_printer()) { obj = m_device_manager->get_local_machine(dev_id); } if (obj) { obj->parse_json(msg); - if (obj->is_ams_need_update) { + if (this->m_device_manager->get_selected_machine() == obj && obj->is_ams_need_update) { GUI::wxGetApp().sidebar().load_ams_list(obj->amsList); } } @@ -1749,14 +1785,23 @@ void GUI_App::init_networking_callbacks() GUI_App::~GUI_App() { - if (app_config != nullptr) + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": enter"); + if (app_config != nullptr) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": destroy app_config"); delete app_config; + } - if (preset_bundle != nullptr) + if (preset_bundle != nullptr) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": destroy preset_bundle"); delete preset_bundle; + } - if (preset_updater != nullptr) + if (preset_updater != nullptr) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": destroy preset updater"); delete preset_updater; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": exit"); } // If formatted for github, plaintext with OpenGL extensions enclosed into
. @@ -1930,6 +1975,25 @@ void GUI_App::init_http_extra_header() m_agent->set_extra_http_header(extra_headers); } +std::string GUI_App::get_local_models_path() +{ + std::string local_path = ""; + if (data_dir().empty()) { + return local_path; + } + + auto models_folder = (boost::filesystem::path(data_dir()) / "models"); + local_path = models_folder.string(); + + if (!fs::exists(models_folder)) { + if (!fs::create_directory(models_folder)) { + local_path = ""; + } + BOOST_LOG_TRIVIAL(info) << "create models folder:" << models_folder.string(); + } + return local_path; +} + /*void GUI_App::init_single_instance_checker(const std::string &name, const std::string &path) { BOOST_LOG_TRIVIAL(debug) << "init wx instance checker " << name << " "<< path; @@ -1963,6 +2027,9 @@ bool GUI_App::on_init_inner() // Set initialization of image handlers before any UI actions - See GH issue #7469 wxInitAllImageHandlers(); +#ifdef NDEBUG + wxImage::SetDefaultLoadFlags(0); // ignore waring in release build +#endif #if defined(_WIN32) && ! defined(_WIN64) // BBS: remove 32bit build prompt @@ -2044,15 +2111,46 @@ bool GUI_App::on_init_inner() // If load_language() fails, the application closes. load_language(wxString(), true); -#ifdef SUPPORT_DARK_MODE #ifdef _MSW_DARK_MODE - NppDarkMode::InitDarkMode(app_config->get("dark_color_mode") == "1", app_config->get("sys_menu_enabled") == "1"); -#endif -#endif +#ifdef __APPLE__ + wxSystemAppearance app = wxSystemSettings::GetAppearance(); + GUI::wxGetApp().app_config->set("dark_color_mode", app.IsDark() ? "1" : "0"); + GUI::wxGetApp().app_config->save(); +#endif // __APPLE__ + + + bool init_dark_color_mode = app_config->get("dark_color_mode") == "1"; + bool init_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; +#ifdef __WINDOWS__ + NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled); +#endif // __WINDOWS__ + +#endif // initialize label colors and fonts init_label_colours(); init_fonts(); + wxGetApp().Update_dark_mode_flag(); + + +#ifdef _MSW_DARK_MODE + // app_config can be updated in check_older_app_config(), so check if dark_color_mode and sys_menu_enabled was changed + if (bool new_dark_color_mode = app_config->get("dark_color_mode") == "1"; + init_dark_color_mode != new_dark_color_mode) { + +#ifdef __WINDOWS__ + NppDarkMode::SetDarkMode(new_dark_color_mode); +#endif // __WINDOWS__ + + init_label_colours(); + //update_label_colours_from_appconfig(); + } + if (bool new_sys_menu_enabled = app_config->get("sys_menu_enabled") == "1"; + init_sys_menu_enabled != new_sys_menu_enabled) +#ifdef __WINDOWS__ + NppDarkMode::SetSystemMenuForApp(new_sys_menu_enabled); +#endif +#endif if (m_last_config_version) { int last_major = m_last_config_version->maj(); @@ -2303,7 +2401,7 @@ bool GUI_App::on_init_inner() mainframe->Show(true); BOOST_LOG_TRIVIAL(info) << "main frame firstly shown"; -#if BBL_HAS_FIRST_PAGE +//#if BBL_HAS_FIRST_PAGE //BBS: set tp3DEditor firstly /*plater_->canvas3D()->enable_render(false); mainframe->select_tab(size_t(MainFrame::tp3DEditor)); @@ -2319,9 +2417,9 @@ bool GUI_App::on_init_inner() plater_->canvas3D()->render(); if (is_editor()) mainframe->select_tab(size_t(0));*/ -#else - plater_->trigger_restore_project(1); -#endif +//#else + //plater_->trigger_restore_project(1); +//#endif obj_list()->set_min_height(); @@ -2413,6 +2511,10 @@ void GUI_App::copy_network_if_available() #endif BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": checking network_library " << network_library << ", player_library " << player_library; + if (!boost::filesystem::exists(plugin_folder)) { + BOOST_LOG_TRIVIAL(info)<< __FUNCTION__ << ": create directory "<set_config_dir(data_directory); } - //BBS set cert dir - if (m_agent) - m_agent->set_cert_file(resources_dir() + "/cert", "slicer_base64.cer"); - //BBS start http log if (m_agent) { m_agent->init_log(); } + //BBS set cert dir + if (m_agent) + m_agent->set_cert_file(resources_dir() + "/cert", "slicer_base64.cer"); + init_http_extra_header(); if (m_agent) { @@ -2570,10 +2672,10 @@ const wxColour GUI_App::get_label_default_clr_modified() void GUI_App::init_label_colours() { - m_color_label_modified = wxColour("#F1754E"); - m_color_label_sys = wxColour("#323A3D"); - bool is_dark_mode = dark_mode(); + m_color_label_modified = is_dark_mode ? wxColour("#F1754E") : wxColour("#F1754E"); + m_color_label_sys = is_dark_mode ? wxColour("#B2B3B5") : wxColour("#363636"); + #ifdef _WIN32 m_color_label_default = is_dark_mode ? wxColour(250, 250, 250) : m_color_label_sys; // wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT); @@ -2584,11 +2686,22 @@ void GUI_App::init_label_colours() m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); #endif m_color_window_default = is_dark_mode ? wxColour(43, 43, 43) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + StateColor::SetDarkMode(is_dark_mode); } void GUI_App::update_label_colours_from_appconfig() { - ; + if (app_config->has("label_clr_sys")) { + auto str = app_config->get("label_clr_sys"); + if (str != "") + m_color_label_sys = wxColour(str); + } + + if (app_config->has("label_clr_modified")) { + auto str = app_config->get("label_clr_modified"); + if (str != "") + m_color_label_modified = wxColour(str); + } } void GUI_App::update_label_colours() @@ -2599,84 +2712,111 @@ void GUI_App::update_label_colours() void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool just_font/* = false*/) { - //BBS disable DarkUI mode - return; + if (wxButton *btn = dynamic_cast(window)) { + if (btn->GetWindowStyleFlag() & wxBU_AUTODRAW) + return; + } -#ifdef _WIN32 - if (wxButton* btn = dynamic_cast(window)) { - if (!(btn->GetWindowStyle() & wxNO_BORDER)) { - btn->SetWindowStyle(btn->GetWindowStyle() | wxNO_BORDER); - highlited = true; + if (Button* btn = dynamic_cast(window)) { + if (btn->GetWindowStyleFlag() & wxBU_AUTODRAW) + return; + } + + + /*if (m_is_dark_mode != dark_mode() ) + m_is_dark_mode = dark_mode();*/ + + + if (m_is_dark_mode) { + auto original_col = window->GetBackgroundColour(); + auto bg_col = StateColor::darkModeColorFor(original_col); + + if (bg_col != original_col) { + window->SetBackgroundColour(bg_col); } - // hovering for buttons - { - auto focus_button = [this, btn](const bool focus) { - btn->SetForegroundColour(focus ? m_color_hovered_btn_label : m_color_label_default); - btn->Refresh(); - btn->Update(); - }; - btn->Bind(wxEVT_ENTER_WINDOW, [focus_button](wxMouseEvent& event) { focus_button(true); event.Skip(); }); - btn->Bind(wxEVT_LEAVE_WINDOW, [focus_button](wxMouseEvent& event) { focus_button(false); event.Skip(); }); + original_col = window->GetForegroundColour(); + auto fg_col = StateColor::darkModeColorFor(original_col); + + if (fg_col != original_col) { + window->SetForegroundColour(fg_col); } } - else if (wxTextCtrl* text = dynamic_cast(window)) { - if (text->GetBorder() != wxBORDER_SIMPLE) - text->SetWindowStyle(text->GetWindowStyle() | wxBORDER_SIMPLE); - } - else if (wxCheckListBox* list = dynamic_cast(window)) { - list->SetWindowStyle(list->GetWindowStyle() | wxBORDER_SIMPLE); - list->SetBackgroundColour(highlited ? m_color_highlight_default : m_color_window_default); - for (size_t i = 0; i < list->GetCount(); i++) - if (wxOwnerDrawn* item = list->GetItem(i)) { - item->SetBackgroundColour(highlited ? m_color_highlight_default : m_color_window_default); - item->SetTextColour(m_color_label_default); - } - return; - } - else if (dynamic_cast(window)) - window->SetWindowStyle(window->GetWindowStyle() | wxBORDER_SIMPLE); + else { + auto original_col = window->GetBackgroundColour(); + auto bg_col = StateColor::lightModeColorFor(original_col); - if (!just_font) - window->SetBackgroundColour(highlited ? m_color_highlight_default : m_color_window_default); - window->SetForegroundColour(m_color_label_default); -#endif + if (bg_col != original_col) { + window->SetBackgroundColour(bg_col); + } + + original_col = window->GetForegroundColour(); + auto fg_col = StateColor::lightModeColorFor(original_col); + + if (fg_col != original_col) { + window->SetForegroundColour(fg_col); + } + } } // recursive function for scaling fonts for all controls in Window -#ifdef _WIN32 static void update_dark_children_ui(wxWindow* window, bool just_buttons_update = false) { - bool is_btn = dynamic_cast(window) != nullptr; - if (!(just_buttons_update && !is_btn)) - wxGetApp().UpdateDarkUI(window, is_btn); + /*bool is_btn = dynamic_cast(window) != nullptr; + is_btn = false;*/ + if (!window) return; + + wxGetApp().UpdateDarkUI(window); auto children = window->GetChildren(); for (auto child : children) { update_dark_children_ui(child); } } -#endif // Note: Don't use this function for Dialog contains ScalableButtons -void GUI_App::UpdateDlgDarkUI(wxDialog* dlg, bool just_buttons_update/* = false*/) +void GUI_App::UpdateDarkUIWin(wxWindow* win) { - //BBS disable DarkUI mode - return; - -#ifdef _WIN32 - update_dark_children_ui(dlg, just_buttons_update); -#endif + update_dark_children_ui(win); } + +void GUI_App::Update_dark_mode_flag() +{ + m_is_dark_mode = dark_mode(); +} + +void GUI_App::UpdateDlgDarkUI(wxDialog* dlg) +{ +#ifdef __WINDOWS__ + NppDarkMode::SetDarkExplorerTheme(dlg->GetHWND()); + NppDarkMode::SetDarkTitleBar(dlg->GetHWND()); +#endif + update_dark_children_ui(dlg); +} + +void GUI_App::UpdateFrameDarkUI(wxFrame* dlg) +{ +#ifdef __WINDOWS__ + NppDarkMode::SetDarkExplorerTheme(dlg->GetHWND()); + NppDarkMode::SetDarkTitleBar(dlg->GetHWND()); +#endif + update_dark_children_ui(dlg); +} + void GUI_App::UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited/* = false*/) { - //BBS disable DarkUI mode - return; - -#ifdef _WIN32 +#ifdef __WINDOWS__ UpdateDarkUI(dvc, highlited ? dark_mode() : false); #ifdef _MSW_DARK_MODE - dvc->RefreshHeaderDarkMode(&m_normal_font); + //dvc->RefreshHeaderDarkMode(&m_normal_font); + HWND hwnd = (HWND)dvc->GenericGetHeader()->GetHandle(); + hwnd = GetWindow(hwnd, GW_CHILD); + if (hwnd != NULL) + NppDarkMode::SetDarkListViewHeader(hwnd); + wxItemAttr attr; + attr.SetTextColour(NppDarkMode::GetTextColor()); + attr.SetFont(m_normal_font); + dvc->SetHeaderAttr(attr); #endif //_MSW_DARK_MODE if (dvc->HasFlag(wxDV_ROW_LINES)) dvc->SetAlternateRowColour(m_color_highlight_default); @@ -2687,10 +2827,7 @@ void GUI_App::UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited/* = false*/) void GUI_App::UpdateAllStaticTextDarkUI(wxWindow* parent) { - //BBS disable DarkUI mode - return; - -#ifdef _WIN32 +#ifdef __WINDOWS__ wxGetApp().UpdateDarkUI(parent); auto children = parent->GetChildren(); @@ -2974,8 +3111,7 @@ void fatal_error(wxWindow* parent) // exit 1; // #ys_FIXME } -#ifdef _WIN32 - +#ifdef __WINDOWS__ #ifdef _MSW_DARK_MODE static void update_scrolls(wxWindow* window) { @@ -3001,36 +3137,49 @@ void GUI_App::force_menu_update() NppDarkMode::SetSystemMenuForApp(app_config->get("sys_menu_enabled") == "1"); } #endif //_MSW_DARK_MODE +#endif //__WINDOWS__ void GUI_App::force_colors_update() { #ifdef _MSW_DARK_MODE +#ifdef __WINDOWS__ NppDarkMode::SetDarkMode(app_config->get("dark_color_mode") == "1"); if (WXHWND wxHWND = wxToolTip::GetToolTipCtrl()) NppDarkMode::SetDarkExplorerTheme((HWND)wxHWND); NppDarkMode::SetDarkTitleBar(mainframe->GetHWND()); + + + //NppDarkMode::SetDarkExplorerTheme((HWND)mainframe->m_settings_dialog.GetHWND()); + //NppDarkMode::SetDarkTitleBar(mainframe->m_settings_dialog.GetHWND()); + +#endif // __WINDOWS__ #endif //_MSW_DARK_MODE m_force_colors_update = true; } -#endif //_WIN32 // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void GUI_App::update_ui_from_settings() { update_label_colours(); -#ifdef _WIN32 // Upadte UI colors before Update UI from settings if (m_force_colors_update) { m_force_colors_update = false; - mainframe->force_color_changed(); - mainframe->diff_dialog.force_color_changed(); -#ifdef _MSW_DARK_MODE - update_scrolls(mainframe); + //UpdateDlgDarkUI(&mainframe->m_settings_dialog); + //mainframe->m_settings_dialog.Refresh(); + //mainframe->m_settings_dialog.Update(); + + if (mainframe) { +#ifdef __WINDOWS__ + mainframe->force_color_changed(); + update_scrolls(mainframe); + update_scrolls(&mainframe->m_settings_dialog); #endif //_MSW_DARK_MODE + update_dark_children_ui(mainframe); + } } -#endif - mainframe->update_ui_from_settings(); + + if (mainframe) {mainframe->update_ui_from_settings();} } void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_maximized) @@ -3070,7 +3219,7 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const { input_files.Clear(); wxFileDialog dialog(parent ? parent : GetTopWindow(), - _L("Choose one or more files (3mf/step/stl/obj/amf):"), + _L("Choose one or more files (3mf/step/stl/svg/obj/amf):"), from_u8(app_config->get_last_dir()), "", file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST); @@ -3090,6 +3239,14 @@ void GUI_App::load_gcode(wxWindow* parent, wxString& input_file) const input_file = dialog.GetPath(); } +wxString GUI_App::transition_tridid(int trid_id) +{ + wxString maping_dict[8] = { "A", "B", "C", "D", "E", "F", "G" }; + int id_index = ceil(trid_id / 4); + int id_suffix = (trid_id + 1) % 4 == 0 ? 4 : (trid_id + 1) % 4; + return wxString::Format("%s%d", maping_dict[id_index], id_suffix); +} + //BBS void GUI_App::request_login(bool show_user_info) { @@ -3157,12 +3314,19 @@ void GUI_App::request_user_logout() m_agent->user_logout(); m_agent->set_user_selected_machine(""); - app_config->set("preset_folder", ""); + BOOST_LOG_TRIVIAL(info) << "preset_folder: set to empty, user_logout"; + enable_user_preset_folder(false); /* delete old user settings */ m_device_manager->clean_user_info(); GUI::wxGetApp().sidebar().load_ams_list({}); GUI::wxGetApp().remove_user_presets(); GUI::wxGetApp().stop_sync_user_preset(); + +#ifdef __WINDOWS__ + wxGetApp().mainframe->topbar()->show_publish_button(false); +#else + wxGetApp().mainframe->show_publish_button(false); +#endif } } @@ -3184,15 +3348,22 @@ std::string GUI_App::handle_web_request(std::string cmd) json j = json::parse(cmd); std::string web_cmd = j["command"].get(); + if (web_cmd == "request_model_download") { - json j_data = j["data"]; - json import_j; - import_j["model_id"] = j["data"]["model_id"].get(); - import_j["profile_id"] = j["data"]["profile_id"].get(); - import_j["design_id"] = ""; - if (j["data"].contains("design_id")) - import_j["design_id"] = j["data"]["design_id"].get(); - this->request_model_download(import_j.dump()); + /* json j_data = j["data"]; + json import_j;*/ + /* import_j["model_id"] = j["data"]["model_id"].get(); + import_j["profile_id"] = j["data"]["profile_id"].get();*/ + + std::string download_url = ""; + if (j["data"].contains("download_url")) + download_url = j["data"]["download_url"].get(); + + std::string filename = ""; + if (j["data"].contains("filename")) + download_url = j["data"]["filename"].get(); + + this->request_model_download(download_url, filename); } std::stringstream ss(cmd), oss; @@ -3238,6 +3409,11 @@ std::string GUI_App::handle_web_request(std::string cmd) wxGetApp().request_user_logout(); }); } + else if (command_str.compare("homepage_modeldepot") == 0) { + CallAfter([this] { + wxGetApp().open_mall_page_dialog(); + }); + } else if (command_str.compare("homepage_newproject") == 0) { this->request_open_project(""); } @@ -3280,8 +3456,8 @@ std::string GUI_App::handle_web_request(std::string cmd) { boost::filesystem::path NowFile(path.value()); - std::string FolderPath = NowFile.parent_path().make_preferred().string(); - desktop_open_any_folder(FolderPath); + std::string FilePath = NowFile.make_preferred().string(); + desktop_open_any_folder(FilePath); } } } @@ -3328,7 +3504,17 @@ std::string GUI_App::handle_web_request(std::string cmd) } } } + else if (command_str.compare("homepage_open_ccabin") == 0) { + if (root.get_child_optional("data") != boost::none) { + pt::ptree data_node = root.get_child("data"); + boost::optional path = data_node.get_optional("file"); + if (path.has_value()) { + std::string Fullpath = resources_dir() + "/web/homepage/model/" + path.value(); + this->request_open_project(Fullpath); + } + } + } } } catch (...) { @@ -3359,12 +3545,12 @@ void GUI_App::handle_script_message(std::string msg) } } -void GUI_App::request_model_download(std::string import_json) +void GUI_App::request_model_download(std::string url, std::string filename) { if (!check_login()) return; if (plater_) { - plater_->request_model_download(import_json); + plater_->request_model_download(url, filename); } } @@ -3461,14 +3647,24 @@ void GUI_App::on_http_error(wxCommandEvent &evt) } } +void GUI_App::enable_user_preset_folder(bool enable) +{ + if (enable) { + std::string user_id = m_agent->get_user_id(); + app_config->set("preset_folder", user_id); + GUI::wxGetApp().preset_bundle->update_user_presets_directory(user_id); + } else { + BOOST_LOG_TRIVIAL(info) << "preset_folder: set to empty"; + app_config->set("preset_folder", ""); + GUI::wxGetApp().preset_bundle->update_user_presets_directory(DEFAULT_USER_FOLDER_NAME); + } +} + void GUI_App::on_user_login(wxCommandEvent &evt) { if (!m_agent) { return; } int online_login = evt.GetInt(); - std::string user_id = m_agent->get_user_id(); - BOOST_LOG_TRIVIAL(info) << "set_preset: set preset_folder = " << user_id; - GUI::wxGetApp().app_config->set("preset_folder", user_id); m_agent->connect_server(); // get machine list @@ -3477,9 +3673,29 @@ void GUI_App::on_user_login(wxCommandEvent &evt) dev->update_user_machine_list_info(); dev->set_selected_machine(m_agent->get_user_selected_machine()); - GUI::wxGetApp().preset_bundle->update_user_presets_directory(user_id); + if (app_config->get("sync_user_preset") == "true") { + enable_user_preset_folder(true); + } else { + enable_user_preset_folder(false); + } + if (online_login) GUI::wxGetApp().mainframe->show_sync_dialog(); + + //show publish button + if (m_agent->is_user_login() && mainframe) { + int identifier; + int result = m_agent->get_user_info(&identifier); + auto publish_identifier = identifier & 1; + +#ifdef __WINDOWS__ + if (result == 0 && publish_identifier >= 0) { + mainframe->m_topbar->show_publish_button(publish_identifier == 0 ? false : true); + } +#else + mainframe->show_publish_button(publish_identifier == 0 ? false : true); +#endif + } } bool GUI_App::is_studio_active() @@ -3545,7 +3761,8 @@ void GUI_App::check_new_version(bool show_tips, int by_user) Slic3r::Http http = Slic3r::Http::get(url); http.header("accept", "application/json") - .timeout_max(10) + .timeout_connect(TIMEOUT_CONNECT) + .timeout_max(TIMEOUT_RESPONSE) .on_complete([this, show_tips, by_user](std::string body, unsigned) { try { json j = json::parse(body); @@ -3616,6 +3833,25 @@ void GUI_App::no_new_version() GUI::wxGetApp().QueueEvent(evt); } +std::string GUI_App::version_display = ""; +std::string GUI_App::format_display_version() +{ + if (!version_display.empty()) return version_display; + + auto version_text = std::string(SLIC3R_VERSION); + int len = version_text.length(); + for (int i = 0, j = 0; i < len; ++i) { + if (!(version_text[i] == '0' && j == 0)) + version_display += version_text[i]; + + if (version_text[i] == '.') + j = 0; + else + ++j; + } + return version_display; +} + void GUI_App::show_dialog(wxString msg) { wxCommandEvent* evt = new wxCommandEvent(EVT_SHOW_DIALOG); @@ -3654,6 +3890,7 @@ void GUI_App::sync_preset(Preset* preset) std::string updated_info; // 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; @@ -3757,6 +3994,8 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) { if (!m_agent) return; + enable_user_preset_folder(true); + // has already start sync if (enable_sync) return; @@ -3847,6 +4086,8 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg) void GUI_App::stop_sync_user_preset() { + enable_user_preset_folder(false); + if (!enable_sync) return; @@ -4148,7 +4389,7 @@ bool GUI_App::load_language(wxString language, bool initial) else if (initial) { // bbs supported languages //TODO: use a global one with Preference - wxLanguage supported_languages[] { + wxLanguage supported_languages[]{ wxLANGUAGE_ENGLISH, wxLANGUAGE_CHINESE_SIMPLIFIED, wxLANGUAGE_GERMAN, @@ -4156,7 +4397,7 @@ bool GUI_App::load_language(wxString language, bool initial) wxLANGUAGE_SPANISH, wxLANGUAGE_SWEDISH, wxLANGUAGE_DUTCH, - wxLANGUAGE_HUNGARIAN }; + wxLANGUAGE_HUNGARIAN}; std::string cur_language = app_config->get("language"); if (cur_language != "") { //cleanup the language wrongly set before @@ -4748,10 +4989,16 @@ void GUI_App::OSXStoreOpenFiles(const wxArrayString &fileNames) void GUI_App::MacOpenFiles(const wxArrayString &fileNames) { if (m_post_initialized) { + bool has3mf = false; std::vector names; - for (auto & n : fileNames) names.push_back(n); - start_new_slicer(names); - return; + for (auto & n : fileNames) { + has3mf |= n.EndsWith(".3mf"); + names.push_back(n); + } + if (has3mf) { + start_new_slicer(names); + return; + } } std::vector files; std::vector gcode_files; @@ -4855,6 +5102,63 @@ void GUI_App::load_url(wxString url) return mainframe->load_url(url); } +void GUI_App::open_mall_page_dialog() +{ + std::string url; + + if (getAgent() && mainframe) { + getAgent()->get_model_mall_home_url(&url); + + if (!m_mall_home_dialog) { + m_mall_home_dialog = new ModelMallDialog(); + m_mall_home_dialog->go_to_mall(url); + } + else { + if (m_mall_home_dialog->IsIconized()) + m_mall_home_dialog->Iconize(false); + + //m_mall_home_dialog->go_to_mall(url); + } + m_mall_home_dialog->Raise(); + m_mall_home_dialog->Show(); + } +} + +void GUI_App::open_publish_page_dialog() +{ + std::string url; + if (getAgent() && mainframe) { + getAgent()->get_model_publish_url(&url); + + if (!m_mall_publish_dialog) { + m_mall_publish_dialog = new ModelMallDialog(); + m_mall_publish_dialog->go_to_mall(url); + } + else { + if (m_mall_publish_dialog->IsIconized()) + m_mall_publish_dialog->Iconize(false); + + //m_mall_publish_dialog->go_to_publish(url); + } + m_mall_publish_dialog->Raise(); + m_mall_publish_dialog->Show(); + } +} + +void GUI_App::remove_mall_system_dialog() +{ + if (m_mall_publish_dialog != nullptr) { + m_mall_publish_dialog->Destroy(); + delete m_mall_publish_dialog; + } + + + if (m_mall_home_dialog != nullptr) { + m_mall_home_dialog->Destroy(); + delete m_mall_home_dialog; + } +} + void GUI_App::run_script(wxString js) { if (mainframe) @@ -4945,14 +5249,14 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage { wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null"); - if (reason == ConfigWizard::RR_USER) { - //TODO: turn off it currently, maybe need to turn on in the future - //if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED) - // return false; - } + //if (reason == ConfigWizard::RR_USER) { + // //TODO: turn off it currently, maybe need to turn on in the future + // if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED) + // return false; + //} - //auto wizard = new ConfigWizard(mainframe); - //const bool res = wizard->run(reason, start_page); + //auto wizard_t = new ConfigWizard(mainframe); + //const bool res = wizard_t->run(reason, start_page); std::string strFinish = wxGetApp().app_config->get("firstguide", "finish"); long pStyle = wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 7c83ed45c7..c0fac3700d 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -26,9 +26,16 @@ #include #include -#define BBL_HAS_FIRST_PAGE 1 +//#define BBL_HAS_FIRST_PAGE 1 #define STUDIO_INACTIVE_TIMEOUT 15*60*1000 #define LOG_FILES_MAX_NUM 30 +#define TIMEOUT_CONNECT 15 +#define TIMEOUT_RESPONSE 15 + +#define BE_UNACTED_ON 0x00200001 +#ifndef _MSW_DARK_MODE + #define _MSW_DARK_MODE 1 +#endif // _MSW_DARK_MODE class wxMenuItem; class wxMenuBar; @@ -65,6 +72,7 @@ class NotificationManager; struct GUI_InitParams; class ParamsDialog; class HMSQuery; +class ModelMallDialog; enum FileType @@ -219,14 +227,15 @@ private: bool m_opengl_initialized{ false }; #endif + +//#ifdef _WIN32 wxColour m_color_label_modified; wxColour m_color_label_sys; wxColour m_color_label_default; wxColour m_color_window_default; - // BBS -//#ifdef _WIN32 wxColour m_color_highlight_label_default; wxColour m_color_hovered_btn_label; + wxColour m_color_default_btn_label; wxColour m_color_highlight_default; wxColour m_color_selected_btn_bg; bool m_force_colors_update { false }; @@ -268,14 +277,15 @@ private: std::shared_ptr m_upgrade_network_job; VersionInfo version_info; + static std::string version_display; HMSQuery *hms_query { nullptr }; boost::thread m_sync_update_thread; bool enable_sync = false; - + bool m_is_dark_mode{ false }; bool m_adding_script_handler { false }; - public: + std::string get_local_models_path(); bool OnInit() override; bool initialized() const { return m_initialized; } @@ -315,8 +325,11 @@ public: void update_label_colours(); // update color mode for window void UpdateDarkUI(wxWindow *window, bool highlited = false, bool just_font = false); + void UpdateDarkUIWin(wxWindow* win); + void Update_dark_mode_flag(); // update color mode for whole dialog including all children - void UpdateDlgDarkUI(wxDialog* dlg, bool just_buttons_update = false); + void UpdateDlgDarkUI(wxDialog* dlg); + void UpdateFrameDarkUI(wxFrame* dlg); // update color mode for DataViewControl void UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited = false); // update color mode for panel including all static texts controls @@ -362,6 +375,7 @@ public: void import_model(wxWindow *parent, wxArrayString& input_files) const; void load_gcode(wxWindow* parent, wxString& input_file) const; + wxString transition_tridid(int trid_id); void ShowUserGuide(); void ShowDownNetPluginDlg(); void ShowUserLogin(); @@ -377,7 +391,7 @@ public: int request_user_unbind(std::string dev_id); std::string handle_web_request(std::string cmd); void handle_script_message(std::string msg); - void request_model_download(std::string import_json); + void request_model_download(std::string url, std::string filename); void download_project(std::string project_id); void request_project_download(std::string project_id); void request_open_project(std::string project_id); @@ -386,6 +400,7 @@ public: void handle_http_error(unsigned int status, std::string body); void on_http_error(wxCommandEvent &evt); void on_user_login(wxCommandEvent &evt); + void enable_user_preset_folder(bool enable); // BBS bool is_studio_active(); @@ -399,6 +414,7 @@ public: void enter_force_upgrade(); void set_skip_version(bool skip = true); void no_new_version(); + static std::string format_display_version(); void show_dialog(wxString msg); void reload_settings(); void remove_user_presets(); @@ -463,9 +479,15 @@ public: ParamsDialog* params_dialog(); Model& model(); NotificationManager * notification_manager(); - //BBS + + ModelMallDialog* m_mall_home_dialog{ nullptr }; + ModelMallDialog* m_mall_publish_dialog{ nullptr }; + void load_url(wxString url); - void run_script(wxString js); + void open_mall_page_dialog(); + void open_publish_page_dialog(); + void remove_mall_system_dialog(); + void run_script(wxString js); bool is_adding_script_handler() { return m_adding_script_handler; } void set_adding_script_handler(bool status) { m_adding_script_handler = status; } @@ -526,9 +548,9 @@ public: void associate_files(std::wstring extend); void disassociate_files(std::wstring extend); #endif // __WXMSW__ - std::string get_plugin_url(std::string country_code); - int download_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); - int install_plugin(InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); + std::string get_plugin_url(std::string name, std::string country_code); + int download_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); + int install_plugin(std::string name, std::string package_name, InstallProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr); std::string get_http_url(std::string country_code); bool is_compatibility_version(); bool check_networking_version(); @@ -564,7 +586,7 @@ private: }; DECLARE_APP(GUI_App) - +wxDECLARE_EVENT(EVT_CONNECT_LAN_MODE_PRINT, wxCommandEvent); } // GUI } // Slic3r diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 17a08fada7..7c30f17e68 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -50,15 +50,15 @@ static bool is_improper_category(const std::string& category, const int filament static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = { //BBS - { L("Quality"), { "layer_height" , "adaptive_layer_height" } }, + { L("Quality"), { "layer_height" } }, { L("Shell"), { "wall_loops", "top_shell_layers", "bottom_shell_layers"} }, { L("Infill") , { "sparse_infill_density", "sparse_infill_pattern" } }, // BBS { L("Support") , { "enable_support", "support_type", "support_threshold_angle", "support_base_pattern", "support_on_build_plate_only","support_critical_regions_only", - "support_base_pattern_spacing" } } + "support_base_pattern_spacing", "support_expansion"}}, //BBS - //{ L("Wipe options") , { "flush_into_infill", "flush_into_objects" } } + { L("Flush options") , { "flush_into_infill", "flush_into_objects", "flush_into_support"} } }; // pt_SLA @@ -72,14 +72,15 @@ std::map> SettingsFactory::OBJECT_C { { L("Quality"), {{"layer_height", "",1}, //{"initial_layer_print_height", "",2}, - {"adaptive_layer_height", "",2},{"seam_position", "",3}, - {"xy_hole_compensation", "",4}, {"xy_contour_compensation", "",5}, {"elefant_foot_compensation", "",6} + {"seam_position", "",2}, + {"slice_closing_radius", "",3}, {"resolution", "",4}, + {"xy_hole_compensation", "",5}, {"xy_contour_compensation", "",6}, {"elefant_foot_compensation", "",7} }}, { 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}, - {"support_filament", "",8},{"support_interface_filament", "",9}, - {"tree_support_branch_angle", "",10}, {"tree_support_wall_count", "",11},{"tree_support_with_infill", "",12},//tree support - {"support_top_z_distance", "",13},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15}, + {"support_filament", "",8},{"support_interface_filament", "",9},{"support_expansion", "",24}, + {"tree_support_branch_angle", "",10}, {"tree_support_wall_count", "",11},//tree support + {"support_top_z_distance", "",13},{"support_bottom_z_distance", "",12},{"support_base_pattern", "",14},{"support_base_pattern_spacing", "",15}, {"support_interface_top_layers", "",16},{"support_interface_bottom_layers", "",17},{"support_interface_spacing", "",18},{"support_bottom_interface_spacing", "",19}, {"support_object_xy_distance", "",20}, {"bridge_no_support", "",21},{"max_bridge_length", "",22},{"support_critical_regions_only", "",23} }}, @@ -89,7 +90,7 @@ std::map> SettingsFactory::OBJECT_C std::map> SettingsFactory::PART_CATEGORY_SETTINGS= { - { L("Quality"), {{"ironing_type", "",7},{"ironing_flow", "",8},{"ironing_spacing", "",9},{"bridge_flow", "",10} + { L("Quality"), {{"ironing_type", "",8},{"ironing_flow", "",9},{"ironing_spacing", "",10},{"bridge_flow", "",11} }}, { L("Strength"), {{"wall_loops", "",1},{"top_shell_layers", L("Top Solid Layers"),1},{"top_shell_thickness", L("Top Minimum Shell Thickness"),1}, {"bottom_shell_layers", L("Bottom Solid Layers"),1}, {"bottom_shell_thickness", L("Bottom Minimum Shell Thickness"),1}, @@ -140,7 +141,7 @@ std::vector SettingsFactory::get_visible_options(const std::s //Support "enable_support", "support_type", "support_threshold_angle", "support_on_build_plate_only", "support_critical_regions_only", "enforce_support_layers", //tree support - "tree_support_wall_count", "tree_support_with_infill", + "tree_support_wall_count", //support "support_top_z_distance", "support_base_pattern", "support_base_pattern_spacing", "support_interface_top_layers", "support_interface_bottom_layers", "support_interface_spacing", "support_bottom_interface_spacing", "support_object_xy_distance", //adhesion @@ -438,7 +439,7 @@ void MenuFactory::append_menu_item_delete(wxMenu* menu) [](wxCommandEvent&) { plater()->remove_selected(); }, "menu_delete", nullptr, []() { return plater()->can_delete(); }, m_parent); #else - append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Delete the selected object"), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tBackSpace", _L("Delete the selected object"), [](wxCommandEvent&) { plater()->remove_selected(); }, "", nullptr, []() { return plater()->can_delete(); }, m_parent); #endif @@ -723,6 +724,72 @@ void MenuFactory::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* m [](wxCommandEvent&) { plater()->scale_selection_to_fit_print_volume(); }, "", menu); } +void MenuFactory::append_menu_items_flush_options(wxMenu* menu) +{ + const wxString name = _L("Flush Options"); + // Delete old menu item + const int item_id = menu->FindItem(name); + if (item_id != wxNOT_FOUND) + menu->Destroy(item_id); + + bool show_flush_option_menu = false; + ObjectList* object_list = obj_list(); + const Selection& selection = get_selection(); + if (wxGetApp().plater()->get_partplate_list().get_curr_plate()->contains(selection.get_bounding_box())) { + auto plate_extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_extruders(); + for (auto extruder : plate_extruders) { + if (extruder != plate_extruders[0]) + show_flush_option_menu = true; + } + } + if (!show_flush_option_menu) + return; + + DynamicPrintConfig& global_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + ModelConfig& select_object_config = object_list->object(selection.get_object_idx())->config; + + auto keys = select_object_config.keys(); + for (auto key : FREQ_SETTINGS_BUNDLE_FFF["Flush options"]) { + if (find(keys.begin(), keys.end(), key) == keys.end()) { + const ConfigOption* option = global_config.option(key); + select_object_config.set_key_value(key, option->clone()); + } + } + + + wxMenu* flush_options_menu = new wxMenu(); + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' infill"), "", + [&select_object_config](wxCommandEvent&) { + const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); + select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0], new ConfigOptionBool(!option->getBool())); + wxGetApp().obj_settings()->UpdateAndShow(true); + }, menu, []() {return true; }, [&select_object_config]() {const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][0]); return option->getBool(); }, m_parent); + + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into this object"), "", + [&select_object_config](wxCommandEvent&) { + const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); + select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1], new ConfigOptionBool(!option->getBool())); + wxGetApp().obj_settings()->UpdateAndShow(true); + }, menu, []() {return true; }, [&select_object_config]() {const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][1]); return option->getBool(); }, m_parent); + + append_menu_check_item(flush_options_menu, wxID_ANY, _L("Flush into objects' support"), "", + [&select_object_config](wxCommandEvent&) { + const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); + select_object_config.set_key_value(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2], new ConfigOptionBool(!option->getBool())); + wxGetApp().obj_settings()->UpdateAndShow(true); + }, menu, []() {return true; }, [&select_object_config]() {const ConfigOption* option = select_object_config.option(FREQ_SETTINGS_BUNDLE_FFF["Flush options"][2]); return option->getBool(); }, m_parent); + + size_t i = 0; + for (auto node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext()) + { + i++; + wxMenuItem* item = node->GetData(); + if (item->GetItemLabelText() == "Edit in Parameter Table") + break; + } + menu->Insert(i, wxID_ANY, _L("Flush Options"), flush_options_menu); +} + void MenuFactory::append_menu_items_convert_unit(wxMenu* menu) { std::vector obj_idxs, vol_idxs; @@ -838,6 +905,12 @@ void MenuFactory::create_default_menu() append_submenu(&m_default_menu, sub_menu, wxID_ANY, _L("Add Primitive"), "", "", []() {return true; }, m_parent); #endif + + m_default_menu.AppendSeparator(); + + append_menu_check_item(&m_default_menu, wxID_ANY, _L("Show Labels"), "", + [](wxCommandEvent&) { plater()->show_view3D_labels(!plater()->are_view3D_labels_shown()); plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, &m_default_menu, + []() { return plater()->is_view3D_shown(); }, [this]() { return plater()->are_view3D_labels_shown(); }, m_parent); } void MenuFactory::create_common_object_menu(wxMenu* menu) @@ -875,7 +948,7 @@ void MenuFactory::create_object_menu() []() { return plater()->can_split(false); }, m_parent); append_submenu(&m_object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", - []() { return plater()->can_split(true); }, m_parent); + []() { return plater()->can_split(true) || plater()->can_split(false); }, m_parent); m_object_menu.AppendSeparator(); // BBS: remove Layers Editing @@ -920,6 +993,7 @@ void MenuFactory::create_bbl_object_menu() // Set filament insert menu item here // Set Printable wxMenuItem* menu_item_printable = append_menu_item_printable(&m_object_menu); + append_menu_item_per_object_process(&m_object_menu); // Enter per object parameters append_menu_item_per_object_settings(&m_object_menu); m_object_menu.AppendSeparator(); @@ -1072,7 +1146,7 @@ void MenuFactory::create_plate_menu() [](wxCommandEvent&) { plater()->delete_plate(); }, "menu_delete", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); #else - append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected plate"), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tBackSpace", _L("Remove the selected plate"), [](wxCommandEvent&) { plater()->delete_plate(); }, "", nullptr, []() { return plater()->can_delete_plate(); }, m_parent); #endif @@ -1131,6 +1205,7 @@ wxMenu* MenuFactory::object_menu() { append_menu_item_change_filament(&m_object_menu); append_menu_items_convert_unit(&m_object_menu); + append_menu_items_flush_options(&m_object_menu); return &m_object_menu; } @@ -1194,6 +1269,7 @@ wxMenu* MenuFactory::multi_selection_menu() append_menu_item_change_filament(menu); append_menu_item_set_printable(menu); + append_menu_item_per_object_process(menu); menu->AppendSeparator(); append_menu_items_convert_unit(menu); menu->AppendSeparator(); @@ -1303,6 +1379,24 @@ void MenuFactory::append_menu_item_center(wxMenu* menu) }, m_parent); } +void MenuFactory::append_menu_item_per_object_process(wxMenu* menu) +{ + const std::vector names = { _L("Edit Process Settings"), _L("Edit Process Settings") }; + append_menu_item(menu, wxID_ANY, names[0], names[1], + [](wxCommandEvent&) { + wxGetApp().obj_list()->switch_to_object_process(); + }, "", nullptr, + []() { + Selection& selection = plater()->canvas3D()->get_selection(); + return selection.is_single_full_object() || + selection.is_multiple_full_object() || + selection.is_single_full_instance() || + selection.is_multiple_full_instance() || + selection.is_single_volume() || + selection.is_multiple_volume(); + }, m_parent); +} + void MenuFactory::append_menu_item_per_object_settings(wxMenu* menu) { const std::vector names = { _L("Edit in Parameter Table"), _L("Edit print parameters for a single object") }; @@ -1342,6 +1436,12 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) if (sels.IsEmpty()) return; + if (sels.Count() == 1) { + const auto sel_vol = obj_list()->get_selected_model_volume(); + if (sel_vol && sel_vol->type() != ModelVolumeType::MODEL_PART && sel_vol->type() != ModelVolumeType::PARAMETER_MODIFIER) + return; + } + std::vector icons = get_extruder_color_icons(true); if (icons.size() < filaments_cnt) { BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%")%icons.size()%filaments_cnt; @@ -1356,22 +1456,34 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu) int initial_extruder = -1; // negative value for multiple object/part selection if (sels.Count() == 1) { const ModelConfig& config = obj_list()->get_item_config(sels[0]); - // BBS: set default extruder to 1 - initial_extruder = config.has("extruder") ? config.extruder() : 1; + // BBS + const auto sel_vol = obj_list()->get_selected_model_volume(); + if (sel_vol && sel_vol->type() == ModelVolumeType::PARAMETER_MODIFIER) + initial_extruder = config.has("extruder") ? config.extruder() : 0; + else + initial_extruder = config.has("extruder") ? config.extruder() : 1; } - for (int i = 1; i <= filaments_cnt; i++) + // BBS + bool has_modifier = false; + for (auto sel : sels) { + if (obj_list()->GetModel()->GetVolumeType(sel) == ModelVolumeType::PARAMETER_MODIFIER) { + has_modifier = true; + break; + } + } + + for (int i = has_modifier ? 0 : 1; i <= filaments_cnt; i++) { // BBS //bool is_active_extruder = i == initial_extruder; bool is_active_extruder = false; - int icon_idx = i == 0 ? 0 : i - 1; - const wxString& item_name = wxString::Format(_L("Filament %d"), i) + + const wxString& item_name = (i == 0 ? _L("Default") : wxString::Format(_L("Filament %d"), i)) + (is_active_extruder ? " (" + _L("current") + ")" : ""); append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "", - [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, *icons[icon_idx], menu, + [i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, i == 0 ? wxNullBitmap : *icons[i - 1], menu, [is_active_extruder]() { return !is_active_extruder; }, m_parent); } menu->Append(wxID_ANY, name, extruder_selection_menu, _L("Change Filament")); @@ -1441,9 +1553,11 @@ void MenuFactory::update_object_menu() void MenuFactory::update_default_menu() { - const auto menu_item_id = m_default_menu.FindItem(_("Add Primitive")); - if (menu_item_id != wxNOT_FOUND) - m_default_menu.Destroy(menu_item_id); + for (auto& name : { _L("Add Primitive") , _L("Show Labels") }) { + const auto menu_item_id = m_default_menu.FindItem(name); + if (menu_item_id != wxNOT_FOUND) + m_default_menu.Destroy(menu_item_id); + } create_default_menu(); } diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 1200729dd9..a2e2e73d25 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -129,6 +129,7 @@ private: void append_menu_item_delete(wxMenu* menu); void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu); void append_menu_items_convert_unit(wxMenu* menu); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk" + void append_menu_items_flush_options(wxMenu* menu); void append_menu_item_merge_to_multipart_object(wxMenu *menu); void append_menu_item_merge_to_single_object(wxMenu* menu); void append_menu_item_merge_parts_to_single_part(wxMenu *menu); @@ -139,6 +140,7 @@ private: void append_menu_item_clone(wxMenu* menu); void append_menu_item_simplify(wxMenu* menu); void append_menu_item_center(wxMenu* menu); + void append_menu_item_per_object_process(wxMenu* menu); void append_menu_item_per_object_settings(wxMenu* menu); void append_menu_item_change_filament(wxMenu* menu); void append_menu_item_set_printable(wxMenu* menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index fffe2a805c..9c88c68bc1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -80,7 +80,7 @@ ObjectList::ObjectList(wxWindow* parent) : #ifdef __WXMSW__ GenericGetHeader()->SetFont(Label::sysFont(13)); #endif - + // create control create_objects_ctrl(); @@ -234,9 +234,9 @@ ObjectList::ObjectList(wxWindow* parent) : Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &ObjectList::OnContextMenu, this); // BBS - //Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, &ObjectList::OnBeginDrag, this); - //Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, &ObjectList::OnDropPossible, this); - //Bind(wxEVT_DATAVIEW_ITEM_DROP, &ObjectList::OnDrop, this); + Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, &ObjectList::OnBeginDrag, this); + Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, &ObjectList::OnDropPossible, this); + Bind(wxEVT_DATAVIEW_ITEM_DROP, &ObjectList::OnDrop, this); Bind(wxEVT_DATAVIEW_ITEM_EDITING_STARTED, &ObjectList::OnEditingStarted, this); Bind(wxEVT_DATAVIEW_ITEM_EDITING_DONE, &ObjectList::OnEditingDone, this); @@ -354,6 +354,9 @@ void ObjectList::create_objects_ctrl() bmp_choice_renderer->set_default_extruder_idx([this]() { return m_objects_model->GetDefaultExtruderIdx(GetSelection()); }); + bmp_choice_renderer->set_has_default_extruder([this]() { + return m_objects_model->GetVolumeType(GetSelection()) == ModelVolumeType::PARAMETER_MODIFIER; + }); AppendColumn(new wxDataViewColumn(_L("Fila."), bmp_choice_renderer, colFilament, m_columns_width[colFilament] * em, wxALIGN_CENTER_HORIZONTAL, 0)); @@ -604,6 +607,11 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) } m_objects_model->SetExtruder(extruder, item); + static const char *keys[] = {"support_filament", "support_interface_filament"}; + for (auto key : keys) + if (object->config.has(key) && object->config.opt_int(key) > filaments_count) + object->config.erase(key); + if (object->volumes.size() > 1) { for (size_t id = 0; id < object->volumes.size(); id++) { item = m_objects_model->GetItemByVolumeId(i, id); @@ -617,6 +625,10 @@ void ObjectList::update_filament_values_for_items(const size_t filaments_count) } m_objects_model->SetExtruder(extruder, item); + + for (auto key : keys) + if (object->volumes[id]->config.has(key) && object->volumes[id]->config.opt_int(key) > filaments_count) + object->volumes[id]->config.erase(key); } } } @@ -847,10 +859,14 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const ModelObject* obj = object(obj_idx); if (m_objects_model->GetItemType(item) & itObject) { - obj->name = m_objects_model->GetName(item).ToUTF8().data(); - // if object has just one volume, rename this volume too - if (obj->volumes.size() == 1) - obj->volumes[0]->name = obj->name; + std::string name = m_objects_model->GetName(item).ToUTF8().data(); + if (obj->name != name) { + obj->name = name; + // if object has just one volume, rename this volume too + if (obj->volumes.size() == 1) + obj->volumes[0]->name = obj->name; + Slic3r::save_object_mesh(*obj); + } return; } @@ -1363,7 +1379,7 @@ void ObjectList::key_event(wxKeyEvent& event) //else if (event.GetUnicodeKey() == 'p') // toggle_printable_state(); else if (filaments_count() > 1) { - std::vector numbers = { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + std::vector numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; wxChar key_char = event.GetUnicodeKey(); if (std::find(numbers.begin(), numbers.end(), key_char) != numbers.end()) { long extruder_number; @@ -1381,17 +1397,28 @@ void ObjectList::key_event(wxKeyEvent& event) void ObjectList::OnBeginDrag(wxDataViewEvent &event) { + bool sequential_print = (wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_enum("print_sequence") == PrintSequence::ByObject); + if (!sequential_print) { + //drag forbidden under bylayer mode + event.Veto(); + return; + } const wxDataViewItem item(event.GetItem()); const bool mult_sel = multiple_selection(); - + const ItemType& type = m_objects_model->GetItemType(item); + if (mult_sel || (type != itObject)) { + //drag only allowed for single object + event.Veto(); + return; + } +#if 0 if ((mult_sel && !selected_instances_of_same_object()) || (!mult_sel && (GetSelection() != item)) ) { event.Veto(); return; } - const ItemType& type = m_objects_model->GetItemType(item); if (!(type & (itVolume | itObject | itInstance))) { event.Veto(); return; @@ -1413,7 +1440,9 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) type&itVolume ? m_objects_model->GetVolumeIdByItem(item) : m_objects_model->GetInstanceIdByItem(item), type); - +#else + m_dragged_data.init(m_objects_model->GetIdByItem(item), type); +#endif /* Under MSW or OSX, DnD moves an item to the place of another selected item * But under GTK, DnD moves an item between another two items. * And as a result - call EVT_CHANGE_SELECTION to unselect all items. @@ -1431,8 +1460,28 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move; } -bool ObjectList::can_drop(const wxDataViewItem& item) const +bool ObjectList::can_drop(const wxDataViewItem& item, int& src_obj_id, int& src_plate, int& dest_obj_id, int& dest_plate) const { +#if 1 + if (!item.IsOk() || (m_objects_model->GetItemType(item) != m_dragged_data.type())) + return false; + + int from_obj_id = m_dragged_data.obj_idx(); + int to_obj_id = m_objects_model->GetIdByItem(item); + PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list(); + + int from_plate = partplate_list.find_instance(from_obj_id, 0); + if (from_plate == -1) + return false; + int to_plate = partplate_list.find_instance(to_obj_id, 0); + if ((to_plate == -1) || (from_plate != to_plate)) + return false; + + src_obj_id = from_obj_id; + dest_obj_id = to_obj_id; + src_plate = from_plate; + dest_plate = to_plate; +#else // move instance(s) or object on "empty place" of ObjectList if ( (m_dragged_data.type() & (itInstance | itObject)) && !item.IsOk() ) return true; @@ -1481,7 +1530,7 @@ bool ObjectList::can_drop(const wxDataViewItem& item) const return false; } - +#endif return true; } @@ -1489,7 +1538,8 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event) { const wxDataViewItem& item = event.GetItem(); - if (!can_drop(item)) { + int src_obj_id, src_plate, dest_obj_id, dest_plate; + if (!can_drop(item, src_obj_id, src_plate, dest_obj_id, dest_plate)) { event.Veto(); m_prevent_list_events = false; } @@ -1499,13 +1549,45 @@ void ObjectList::OnDrop(wxDataViewEvent &event) { const wxDataViewItem& item = event.GetItem(); - if (!can_drop(item)) + int src_obj_id, src_plate, dest_obj_id, dest_plate; + if (!can_drop(item, src_obj_id, src_plate, dest_obj_id, dest_plate)) { event.Veto(); m_dragged_data.clear(); return; } +#if 1 + take_snapshot("Object order changed"); + + int delta = dest_obj_id < src_obj_id ? -1 : 1; + PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list(); + /*int cnt = 0, cur_id = src_obj_id, next_id, total = abs(src_obj_id - dest_obj_id); + //for (cur_id = src_obj_id; cnt < total; id += delta, cnt++) + next_id = src_obj_id + delta; + while (cnt < total) + { + int cur_plate = partplate_list.find_instance(next_id, 0); + if (cur_plate != src_plate) { + cnt ++; + next_id += delta; + continue; + } + std::swap((*m_objects)[cur_id], (*m_objects)[next_id]); + cur_id = next_id; + cnt ++; + next_id += delta; + }*/ + + int cnt = 0; + for (int id = src_obj_id; cnt < abs(src_obj_id - dest_obj_id); id += delta, cnt++) + std::swap((*m_objects)[id], (*m_objects)[id + delta]); + + select_item(m_objects_model->ReorganizeObjects(src_obj_id, dest_obj_id)); + + partplate_list.reload_all_objects(false, src_plate); + changed_object(src_obj_id); +#else if (m_dragged_data.type() == itInstance) { // BBS: remove snapshot name "Instances to Separated Objects" @@ -1546,6 +1628,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event) } changed_object(m_dragged_data.obj_idx()); +#endif m_dragged_data.clear(); @@ -1839,10 +1922,17 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo // Mesh will be centered when loading. ModelVolume* new_volume = model_object.add_volume(std::move(mesh), type); new_volume->name = boost::filesystem::path(input_file).filename().string(); + + // adjust the position according to the bounding box + const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); + new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); + auto offset = Vec3d(instance_bb.max.x(), instance_bb.min.y(), instance_bb.min.z()) + 0.5 * mesh_bb.size() - v->get_instance_offset(); + new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); + // set a default extruder value, since user can't add it manually // BBS int extruder_id = 0; - if (model_object.config.has("extruder")) + if (new_volume->type() == ModelVolumeType::MODEL_PART && model_object.config.has("extruder")) extruder_id = model_object.config.opt_int("extruder"); new_volume->config.set_key_value("extruder", new ConfigOptionInt(extruder_id)); // update source data @@ -1945,10 +2035,11 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode const wxString name = _L("Generic") + "-" + _(type_name); new_volume->name = into_u8(name); + // set a default extruder value, since user can't add it manually // BBS int extruder_id = 0; - if (model_object.config.has("extruder")) + if (new_volume->type() == ModelVolumeType::MODEL_PART && model_object.config.has("extruder")) extruder_id = model_object.config.opt_int("extruder"); new_volume->config.set_key_value("extruder", new ConfigOptionInt(extruder_id)); new_volume->source.is_from_builtin_objects = true; @@ -1979,7 +2070,18 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode //Show Dialog if (wxGetApp().app_config->get("do_not_show_modifer_tips").empty()) { - TipsDialog dlg(wxGetApp().mainframe, _L("Add Modifier")); + TipsDialog dlg(wxGetApp().mainframe, _L("Add Modifier"), _L("Switch to per-object setting mode to edit modifier settings."), "do_not_show_modifer_tips"); + dlg.ShowModal(); + } +} + +void ObjectList::switch_to_object_process() +{ + wxGetApp().params_panel()->switch_to_object(true); + + // Show Dialog + if (wxGetApp().app_config->get("do_not_show_object_process_tips").empty()) { + TipsDialog dlg(wxGetApp().mainframe, _L("Edit Process Settings"), _L("Switch to per-object setting mode to edit process settings of selected objects."), "do_not_show_object_process_tips"); dlg.ShowModal(); } } @@ -2029,6 +2131,9 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name new_object->invalidate_bounding_box(); new_object->translate(-bb.center()); + // BBS: backup + Slic3r::save_object_mesh(*new_object); + // BBS: find an empty cell to put the copied object auto start_point = wxGetApp().plater()->build_volume().bounding_volume2d().center(); auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)}); @@ -2076,7 +2181,7 @@ void ObjectList::load_mesh_part(const TriangleMesh& mesh, const wxString& name, ModelVolume* mv = mo->add_volume(mesh); Vec3d instance_bbox = mo->mesh().bounding_box().size(); - Vec3d offset = mv->get_offset() + Vec3d(0, 0, instance_bbox[2] / 2); + Vec3d offset = Vec3d(0, 0, instance_bbox[2] / 2); mv->set_offset(offset); mv->name = name.ToStdString(); @@ -2291,7 +2396,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con else if (type == itInstance) { if (object->instances.size() == 1) { // BBS: remove snapshot name "Last instance of an object cannot be deleted." - Slic3r::GUI::show_error(nullptr, _L("")); + Slic3r::GUI::show_error(nullptr, ""); return false; } @@ -4036,11 +4141,18 @@ void ObjectList::select_items(const std::vector& ov_ids) void ObjectList::select_items(const wxDataViewItemArray& sels) { m_prevent_list_events = true; - m_last_selected_item = sels.empty() ? wxDataViewItem(nullptr) : sels.back(); UnselectAll(); - SetSelections(sels); + + if (!sels.empty()) { + SetSelections(sels); + } + else { + int curr_plate_idx = wxGetApp().plater()->get_partplate_list().get_curr_plate_index(); + on_plate_selected(curr_plate_idx); + } + part_selection_changed(); m_prevent_list_events = false; @@ -4607,6 +4719,8 @@ void ObjectList::fix_through_netfabb() update_item_error_icon(obj_idx, vol_idx); update_info_items(obj_idx); + object(obj_idx)->ensure_on_bed(); + return true; }; @@ -4805,6 +4919,16 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) ItemType sel_item_type = m_objects_model->GetItemType(sel_item); wxDataViewItem item = (sel_item_type & itInstance) ? m_objects_model->GetObject(item) : sel_item; ItemType type = m_objects_model->GetItemType(item); + if (type & itVolume) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + const int vol_idx = m_objects_model->GetVolumeIdByItem(item); + + if ((obj_idx < m_objects->size()) && (obj_idx < (*m_objects)[obj_idx]->volumes.size())) { + auto volume_type = (*m_objects)[obj_idx]->volumes[vol_idx]->type(); + if (volume_type != ModelVolumeType::MODEL_PART && volume_type != ModelVolumeType::PARAMETER_MODIFIER) + continue; + } + } ModelConfig& config = get_item_config(item); if (config.has("extruder")) @@ -4812,11 +4936,11 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) else config.set_key_value("extruder", new ConfigOptionInt(extruder)); - // for object, clear all its volume's extruder config + // for object, clear all its part volume's extruder config if (type & itObject) { ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID(); for (ModelVolume* mv : node->m_model_object->volumes) { - if (mv->config.has("extruder")) + if (mv->type() == ModelVolumeType::MODEL_PART && mv->config.has("extruder")) mv->config.erase("extruder"); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 0192983ff7..8ce1b81e7a 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -282,6 +282,7 @@ public: void load_shape_object(const std::string &type_name); void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true); // BBS + void switch_to_object_process(); void load_mesh_part(const TriangleMesh& mesh, const wxString& name, bool center = true); void del_object(const int obj_idx, bool refresh_immediately = true); void del_subobject_item(wxDataViewItem& item); @@ -445,7 +446,7 @@ private: void OnBeginDrag(wxDataViewEvent &event); void OnDropPossible(wxDataViewEvent &event); void OnDrop(wxDataViewEvent &event); - bool can_drop(const wxDataViewItem& item) const ; + bool can_drop(const wxDataViewItem& item, int& src_obj_id, int& src_plate, int& dest_obj_id, int& dest_plate) const ; 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. diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 0133fd4e4e..d6662b8b4d 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -204,7 +204,7 @@ bool ObjectSettings::update_settings_list() for (auto item : items) { auto type = objects_model->GetItemType(item); if (type != itObject && type != itVolume) { - return false; + continue; } const int obj_idx = objects_model->GetObjectIdByItem(item); assert(obj_idx >= 0); diff --git a/src/slic3r/GUI/GUI_ObjectTable.cpp b/src/slic3r/GUI/GUI_ObjectTable.cpp index a034741a1e..7212a5534a 100644 --- a/src/slic3r/GUI/GUI_ObjectTable.cpp +++ b/src/slic3r/GUI/GUI_ObjectTable.cpp @@ -2674,7 +2674,7 @@ ObjectTablePanel::ObjectTablePanel( wxWindow* parent, wxWindowID id, const wxPoi { //m_bg_colour = wxColour(0xfa, 0xfa, 0xfa); m_float_validator.SetRange(0, 100); - m_bg_colour = wxColour(0xff, 0xff, 0xff); + m_bg_colour = wxColour("#FFFFFF"); //m_hover_colour = wxColour(61, 70, 72); SetBackgroundColour(m_bg_colour); @@ -2854,8 +2854,8 @@ void ObjectTablePanel::load_data() m_object_grid->SetColLabelValue(ObjectGridTable::col_speed_perimeter, _L("Outer wall speed")); m_object_grid->SetColLabelValue(ObjectGridTable::col_speed_perimeter_reset, ""); m_object_grid->SetLabelFont(Label::Head_13); - m_object_grid->SetLabelTextColour(wxColour(0x30,0x3a,0x3c)); - m_object_grid->SetLabelBackgroundColour(wxColour(0xff, 0xff, 0xff)); + m_object_grid->SetLabelTextColour(StateColor::darkModeColorFor(wxColour("#303A3C"))); + m_object_grid->SetLabelBackgroundColour( wxColour("#FFFFFF")); #else m_object_grid->HideColLabels(); #endif @@ -2866,7 +2866,6 @@ void ObjectTablePanel::load_data() m_object_grid->EnableDragGridSize(false); m_object_grid->EnableDragRowSize(false); - /*set the first row as label*/ //format wxGridCellAttr *attr; @@ -2894,7 +2893,7 @@ void ObjectTablePanel::load_data() //m_object_grid->SetSelectionForeground(wxColour(0xDB,0xFD,0xE7)); //m_object_grid->SetSelectionBackground(*wxWHITE); - + m_object_grid->SetDefaultCellBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); for (int col = 0; col < cols; col++) { ObjectGridTable::ObjectGridCol* grid_col = m_object_grid_table->get_grid_col(col); @@ -2907,7 +2906,8 @@ void ObjectTablePanel::load_data() m_object_grid->SetCellAlignment(row, col, grid_col->horizontal_align, wxALIGN_CENTRE ); m_object_grid->SetCellOverflow(row, col, false); //m_object_grid->SetCellBackgroundColour (row, col, *wxLIGHT_GREY); - m_object_grid->SetCellBackgroundColour (row, col, *wxWHITE); + m_object_grid->SetCellBackgroundColour (row, col, StateColor::darkModeColorFor(*wxWHITE)); + m_object_grid->SetCellTextColour(row, col,StateColor::darkModeColorFor(wxColour(*wxBLACK))); //set the render and editor if (grid_col->b_icon) { m_object_grid->SetCellRenderer(row, col, new GridCellIconRenderer()); @@ -3094,6 +3094,7 @@ ObjectTablePanel::~ObjectTablePanel() }*/ if (m_top_sizer) m_top_sizer->Clear(true); + delete m_object_settings; m_filaments_name.clear(); m_filaments_colors.clear(); @@ -3306,6 +3307,7 @@ ObjectTableDialog::ObjectTableDialog(wxWindow* parent, Plater* platerObj, Model SetSizer(m_main_sizer); Fit(); Layout(); + wxGetApp().UpdateDlgDarkUI(this); } ObjectTableDialog::~ObjectTableDialog() diff --git a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp index b2a2f77e52..37d4f4dc23 100644 --- a/src/slic3r/GUI/GUI_ObjectTableSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectTableSettings.cpp @@ -168,7 +168,7 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ btn->SetToolTip(_(L("Reset parameter"))); #ifdef __WINDOWS__ - btn->SetBackgroundColour(*wxWHITE); + btn->SetBackgroundColour(parent->GetBackgroundColour()); #endif // DEBUG @@ -220,7 +220,8 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ optgroup->sidetext_width = 5; optgroup->set_config_category_and_type(GUI::from_u8(group_category), Preset::TYPE_PRINT); - optgroup->m_on_change = [this, optgroup, is_object, object, config, group_category](const t_config_option_key& opt_id, const boost::any& value) { + std::weak_ptr weak_optgroup(optgroup); + optgroup->m_on_change = [this, is_object, object, config, group_category](const t_config_option_key &opt_id, const boost::any &value) { this->m_parent->Freeze(); this->update_config_values(is_object, object, config, group_category); wxGetApp().obj_list()->changed_object(); @@ -258,10 +259,10 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_ } optgroup->activate(); for (auto& opt : cat.second) - optgroup->get_field(opt.name)->m_on_change = [optgroup](const std::string& opt_id, const boost::any& value) { + optgroup->get_field(opt.name)->m_on_change = [weak_optgroup](const std::string& opt_id, const boost::any& value) { // first of all take a snapshot and then change value in configuration wxGetApp().plater()->take_snapshot((boost::format("Change Option %s") % opt_id).str()); - optgroup->on_change_OG(opt_id, value); + weak_optgroup.lock()->on_change_OG(opt_id, value); }; optgroup->reload_config(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 7e2f8d772f..2730544b7c 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -94,8 +94,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Model* model, DynamicPrintConfig void View3D::set_as_dirty() { - if (m_canvas != nullptr) + if (m_canvas != nullptr) { m_canvas->set_as_dirty(); + } } void View3D::bed_shape_changed() @@ -160,6 +161,22 @@ void View3D::mirror_selection(Axis axis) m_canvas->mirror_selection(axis); } +bool View3D::is_layers_editing_enabled() const +{ + return (m_canvas != nullptr) ? m_canvas->is_layers_editing_enabled() : false; +} + +bool View3D::is_layers_editing_allowed() const +{ + return (m_canvas != nullptr) ? m_canvas->is_layers_editing_allowed() : false; +} + +void View3D::enable_layers_editing(bool enable) +{ + if (m_canvas != nullptr) + m_canvas->enable_layers_editing(enable); +} + bool View3D::is_dragging() const { return (m_canvas != nullptr) ? m_canvas->is_dragging() : false; diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index a61faf157f..88e1336640 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -66,6 +66,10 @@ public: void center_selected(); void mirror_selection(Axis axis); + bool is_layers_editing_enabled() const; + bool is_layers_editing_allowed() const; + void enable_layers_editing(bool enable); + bool is_dragging() const; bool is_reload_delayed() const; diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp index 0667e164cc..7cc0a6bc56 100644 --- a/src/slic3r/GUI/GUI_Utils.cpp +++ b/src/slic3r/GUI/GUI_Utils.cpp @@ -259,15 +259,23 @@ bool check_dark_mode() { void update_dark_ui(wxWindow* window) { #ifdef SUPPORT_DARK_MODE - bool is_dark = wxGetApp().app_config->get("dark_color_mode") == "1";// ? true : check_dark_mode();// #ysDarkMSW - Allow it when we deside to support the sustem colors for application + bool is_dark = wxGetApp().app_config->get("dark_color_mode") == "1"; #else bool is_dark = false; #endif - window->SetBackgroundColour(is_dark ? wxColour(43, 43, 43) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - window->SetForegroundColour(is_dark ? wxColour(250, 250, 250) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + //window->SetBackgroundColour(is_dark ? wxColour(43, 43, 43) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + //window->SetForegroundColour(is_dark ? wxColour(250, 250, 250) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); } #endif +void update_dark_config() +{ + wxSystemAppearance app = wxSystemSettings::GetAppearance(); + GUI::wxGetApp().app_config->set("dark_color_mode", app.IsDark() ? "1" : "0"); + GUI::wxGetApp().app_config->save(); + wxGetApp().Update_dark_mode_flag(); +} + CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY) diff --git a/src/slic3r/GUI/GUI_Utils.hpp b/src/slic3r/GUI/GUI_Utils.hpp index a93009129f..c86f43faa1 100644 --- a/src/slic3r/GUI/GUI_Utils.hpp +++ b/src/slic3r/GUI/GUI_Utils.hpp @@ -82,6 +82,7 @@ wxFont get_default_font_for_dpi(const wxWindow* window, int dpi); inline wxFont get_default_font(const wxWindow* window) { return get_default_font_for_dpi(window, get_dpi_for_window(window)); } bool check_dark_mode(); +void update_dark_config(); #ifdef _WIN32 void update_dark_ui(wxWindow* window); #endif @@ -188,8 +189,9 @@ public: this->Bind(wxEVT_SYS_COLOUR_CHANGED, [this](wxSysColourChangedEvent& event) { - event.Skip(); + update_dark_config(); on_sys_color_changed(); + event.Skip(); }); if (std::is_same::value) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index 5708e7f6ca..b1d98d3dc2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -166,6 +166,10 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u m_cylinder.init_from(its_make_cylinder(1., 1., 2 * PI / 24.)); } +void GLGizmoBase::set_icon_filename(const std::string &filename) { + m_icon_filename = filename; +} + void GLGizmoBase::set_hover_id(int id) { if (m_grabbers.empty() || (id < (int)m_grabbers.size())) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 5e8b1cef5d..6d4359d437 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -126,6 +126,8 @@ protected: GLModel m_cylinder; GLModel m_sphere; + bool m_is_dark_mode = false; + public: GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, @@ -149,20 +151,22 @@ public: const std::string& get_icon_filename() const { return m_icon_filename; } + void set_icon_filename(const std::string& filename); + bool is_activable() const { return on_is_activable(); } bool is_selectable() const { return on_is_selectable(); } CommonGizmosDataID get_requirements() const { return on_get_requirements(); } virtual bool wants_enter_leave_snapshots() const { return false; } virtual std::string get_gizmo_entering_text() const { assert(false); return ""; } virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; } - virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); } + virtual std::string get_action_snapshot_name() { return "Gizmo action"; } void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } unsigned int get_sprite_id() const { return m_sprite_id; } int get_hover_id() const { return m_hover_id; } void set_hover_id(int id); - + void set_highlight_color(const std::array& color); void enable_grabber(unsigned int id); @@ -181,6 +185,7 @@ public: void render() { m_tooltip.clear(); on_render(); } void render_for_picking() { on_render_for_picking(); } void render_input_window(float x, float y, float bottom_limit); + virtual void on_change_color_mode(bool is_dark) { m_is_dark_mode = is_dark; } virtual std::string get_tooltip() const { return ""; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 3164d3cc6b..22bebc27dd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -81,6 +81,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel"); m_desc["clipping_of_view"] = _L("Section view"); + m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel"); m_desc["cursor_size"] = _L("Pen size"); m_desc["enforce_caption"] = _L("Left mouse button"); @@ -98,6 +99,7 @@ bool GLGizmoFdmSupports::on_init() m_desc["tool_type"] = _L("Tool type"); m_desc["smart_fill_angle_caption"] = _L("Ctrl + Mouse wheel"); m_desc["smart_fill_angle"] = _L("Smart fill angle"); + m_desc["on_overhangs_only"] = _L("On overhangs only"); memset(&m_print_instance, sizeof(m_print_instance), 0); return true; @@ -216,6 +218,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float gap_fill_slider_left = m_imgui->calc_text_size(m_desc.at("gap_fill")).x + m_imgui->scaled(1.5f); const float highlight_slider_left = m_imgui->calc_text_size(m_desc.at("highlight_by_angle")).x + m_imgui->scaled(1.5f); + const float reset_button_slider_left = m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2; + const float on_overhangs_only_width = m_imgui->calc_text_size(m_desc["on_overhangs_only"]).x + m_imgui->scaled(1.5f); const float remove_btn_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.5f); const float filter_btn_width = m_imgui->calc_text_size(m_desc.at("perform")).x + m_imgui->scaled(1.5f); const float buttons_width = remove_btn_width + filter_btn_width + m_imgui->scaled(1.5f); @@ -233,7 +237,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l total_text_max += caption_max + m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f); - const float sliders_left_width = std::max(std::max(cursor_slider_left, clipping_slider_left), std::max(highlight_slider_left, gap_fill_slider_left)); + const float sliders_left_width = std::max(reset_button_slider_left, std::max(std::max(cursor_slider_left, clipping_slider_left), std::max(highlight_slider_left, gap_fill_slider_left))); const float slider_icon_width = m_imgui->get_slider_icon_size().x; const float max_tooltip_width = ImGui::GetFontSize() * 20.0f; @@ -244,33 +248,39 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("tool_type")); - std::array tool_icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array icons; + if (m_is_dark_mode) + icons = { ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon }; + else + icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Fill"), _L("Gap Fill") }; - for (int i = 0; i < tool_icons.size(); i++) { + for (int i = 0; i < tool_ids.size(); i++) { std::string str_label = std::string("##"); - std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label); + std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.3f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - if (m_current_tool == tool_icons[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + if (m_current_tool == tool_ids[i]) { + ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); } bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_icons[i]) + if (m_current_tool == tool_ids[i]) { ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); } ImGui::PopStyleVar(1); - if (btn_clicked && m_current_tool != tool_icons[i]) { - m_current_tool = tool_icons[i]; + if (btn_clicked && m_current_tool != tool_ids[i]) { + m_current_tool = tool_ids[i]; for (auto& triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -282,6 +292,11 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l } } + m_imgui->bbl_checkbox(m_desc["on_overhangs_only"], m_paint_on_overhangs_only); + if (ImGui::IsItemHovered()) + m_imgui->tooltip(format_wxstr(_L("Allows painting only on facets selected by: \"%1%\""), m_desc["highlight_by_angle"]), max_tooltip_width); + ImGui::Separator(); + if (m_current_tool != old_tool) this->tool_changed(old_tool, m_current_tool); @@ -379,11 +394,20 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::SameLine(drag_left_width); ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##angle_threshold_deg_input", &m_highlight_by_angle_threshold_deg, 0.05f, 0.0f, 0.0f, "%.2f"); - + if (m_current_tool != ImGui::GapFillIcon) { ImGui::Separator(); - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(sliders_left_width); @@ -468,6 +492,7 @@ void GLGizmoFdmSupports::show_tooltip_information(float caption_max, float x, fl float font_size = ImGui::GetFontSize(); ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, ImGui::GetStyle().FramePadding.y }); ImGui::ImageButton3(normal_id, hover_id, button_size); if (ImGui::IsItemHovered()) { @@ -499,7 +524,7 @@ void GLGizmoFdmSupports::show_tooltip_information(float caption_max, float x, fl ImGui::EndTooltip(); } - ImGui::PopStyleVar(1); + ImGui::PopStyleVar(2); } // BBS @@ -796,7 +821,7 @@ void GLGizmoFdmSupports::update_support_volumes() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "join thread returns "<run_thread();}); + m_thread = create_thread([this]{this->run_thread();}); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ",created thread to generate support volumes"; return; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index f962bad8ae..3cf7184a76 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -34,9 +34,9 @@ protected: void show_tooltip_information(float caption_max, float x, float y); wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; - std::string get_gizmo_entering_text() const override { return _u8L("Entering Paint-on supports"); } - std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Paint-on supports"); } - std::string get_action_snapshot_name() override { return _u8L("Paint-on supports editing"); } + std::string get_gizmo_entering_text() const override { return "Entering Paint-on supports"; } + std::string get_gizmo_leaving_text() const override { return "Leaving Paint-on supports"; } + std::string get_action_snapshot_name() override { return "Paint-on supports editing"; } // BBS wchar_t m_current_tool = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index e4cde96de2..619cebb798 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -13,7 +13,6 @@ namespace Slic3r { namespace GUI { -static double g_normal_precise = 0.0015; GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) @@ -140,8 +139,8 @@ void GLGizmoFlatten::update_planes() const Transform3d& inst_matrix = mo->instances.front()->get_matrix(true); // Following constants are used for discarding too small polygons. - const float minimal_area = 4.f; // in square mm (world coordinates) - const float minimal_side = 2.f; // mm + const float minimal_area = 5.f; // in square mm (world coordinates) + const float minimal_side = 1.f; // mm // Now we'll go through all the facets and append Points of facets sharing the same normal. // This part is still performed in mesh coordinate system. @@ -169,7 +168,7 @@ void GLGizmoFlatten::update_planes() while (facet_queue_cnt > 0) { int facet_idx = facet_queue[-- facet_queue_cnt]; const stl_normal& this_normal = face_normals[facet_idx]; - if (std::abs(this_normal(0) - (*normal_ptr)(0)) <= g_normal_precise && std::abs(this_normal(1) - (*normal_ptr)(1)) <= g_normal_precise && std::abs(this_normal(2) - (*normal_ptr)(2)) <= g_normal_precise) { + if (std::abs(this_normal(0) - (*normal_ptr)(0)) < 0.001 && std::abs(this_normal(1) - (*normal_ptr)(1)) < 0.001 && std::abs(this_normal(2) - (*normal_ptr)(2)) < 0.001) { const Vec3i face = ch.its.indices[facet_idx]; for (int j=0; j<3; ++j) m_planes.back().vertices.emplace_back(ch.its.vertices[face[j]].cast()); @@ -236,28 +235,18 @@ void GLGizmoFlatten::update_planes() discard = true; else { // We also check the inner angles and discard polygons with angles smaller than the following threshold - const double angle_threshold = ::cos(9.0 * (double)PI / 180.0); - int count = 0, side_count = polygon.size(); + const double angle_threshold = ::cos(10.0 * (double)PI / 180.0); - for (unsigned int i = 0; i < side_count; ++i) { + for (unsigned int i = 0; i < polygon.size(); ++i) { const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1]; const Vec3d& curr = polygon[i]; const Vec3d& next = polygon[(i == polygon.size() - 1) ? 0 : i + 1]; - double len = (next - curr).norm(); - if (len >= minimal_side) - count ++; if ((prec - curr).normalized().dot((next - curr).normalized()) > angle_threshold) { discard = true; break; } } - if (!discard - //&& ((side_count == 3) || (side_count == 5)) - && (side_count <= 5) - && (count <= 2)) { - discard = true; - } } if (discard) { @@ -269,14 +258,14 @@ void GLGizmoFlatten::update_planes() Vec3d centroid = std::accumulate(polygon.begin(), polygon.end(), Vec3d(0.0, 0.0, 0.0)); centroid /= (double)polygon.size(); for (auto& vertex : polygon) - vertex = 0.95f*vertex + 0.05f*centroid; + vertex = 0.9f*vertex + 0.1f*centroid; // Polygon is now simple and convex, we'll round the corners to make them look nicer. // The algorithm takes a vertex, calculates middles of respective sides and moves the vertex // towards their average (controlled by 'aggressivity'). This is repeated k times. // In next iterations, the neighbours are not always taken at the middle (to increase the // rounding effect at the corners, where we need it most). - /*const unsigned int k = 10; // number of iterations + const unsigned int k = 10; // number of iterations const float aggressivity = 0.2f; // agressivity const unsigned int N = polygon.size(); std::vector> neighbours; @@ -308,7 +297,7 @@ void GLGizmoFlatten::update_planes() } } polygon = points_out; // replace the coarse polygon with the smooth one that we just created - }*/ + } // Raise a bit above the object surface to avoid flickering: @@ -321,7 +310,7 @@ void GLGizmoFlatten::update_planes() // We'll sort the planes by area and only keep the 254 largest ones (because of the picking pass limitations): std::sort(m_planes.rbegin(), m_planes.rend(), [](const PlaneData& a, const PlaneData& b) { return a.area < b.area; }); - m_planes.resize(std::min((int)m_planes.size(), 512)); + m_planes.resize(std::min((int)m_planes.size(), 254)); // Planes are finished - let's save what we calculated it from: m_volumes_matrices.clear(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 461b5b813e..45d7373d8e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -99,6 +99,7 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["clipping_of_view_caption"] = _L("Alt + Mouse wheel"); m_desc["clipping_of_view"] = _L("Section view"); + m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size_caption"] = _L("Ctrl + Mouse wheel"); m_desc["cursor_size"] = _L("Pen size"); m_desc["cursor_type"] = _L("Pen shape"); @@ -131,6 +132,10 @@ bool GLGizmoMmuSegmentation::on_init() m_desc["height_range_caption"] = _L("Ctrl + Mouse wheel"); m_desc["height_range"] = _L("Height range"); + //add toggle wire frame hint + m_desc["toggle_wireframe_caption"] = _L("Ctrl + Shift + Enter"); + m_desc["toggle_wireframe"] = _L("Toggle Wireframe"); + init_extruders_data(); return true; @@ -302,6 +307,7 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x float font_size = ImGui::GetFontSize(); ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, ImGui::GetStyle().FramePadding.y }); ImGui::ImageButton3(normal_id, hover_id, button_size); if (ImGui::IsItemHovered()) { @@ -315,16 +321,16 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x std::vector tip_items; switch (m_tool_type) { case ToolType::BRUSH: - tip_items = {"paint", "erase", "cursor_size", "clipping_of_view"}; + tip_items = {"paint", "erase", "cursor_size", "clipping_of_view", "toggle_wireframe"}; break; case ToolType::BUCKET_FILL: - tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view"}; + tip_items = {"paint", "erase", "smart_fill_angle", "clipping_of_view", "toggle_wireframe"}; break; case ToolType::SMART_FILL: // TODO: break; case ToolType::GAP_FILL: - tip_items = {"gap_area"}; + tip_items = {"gap_area", "toggle_wireframe"}; break; default: break; @@ -332,7 +338,7 @@ void GLGizmoMmuSegmentation::show_tooltip_information(float caption_max, float x for (const auto &t : tip_items) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); ImGui::EndTooltip(); } - ImGui::PopStyleVar(1); + ImGui::PopStyleVar(2); } void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bottom_limit) @@ -351,7 +357,8 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; - const float clipping_slider_left = m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f); + const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f), + m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2); const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f); const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f); const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f); @@ -411,7 +418,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx); std::string item_text = std::to_string(extruder_idx + 1); const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true); - + const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f); float button_offset = start_pos_x; @@ -459,32 +466,38 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc.at("tool_type")); - std::array tool_icons = { ImGui::CircleButtonIcon,ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array tool_ids; + tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; + std::array icons; + if (m_is_dark_mode) + icons = { ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon, ImGui::TriangleButtonDarkIcon, ImGui::HeightRangeDarkIcon, ImGui::FillButtonDarkIcon, ImGui::GapFillDarkIcon }; + else + icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon, ImGui::TriangleButtonIcon, ImGui::HeightRangeIcon, ImGui::FillButtonIcon, ImGui::GapFillIcon }; std::array tool_tips = { _L("Circle"), _L("Sphere"), _L("Triangle"), _L("Height Range"), _L("Fill"), _L("Gap Fill") }; - for (int i = 0; i < tool_icons.size(); i++) { + for (int i = 0; i < tool_ids.size(); i++) { std::string str_label = std::string(""); - std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label); + std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.5f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - if (m_current_tool == tool_icons[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + if (m_current_tool == tool_ids[i]) { + ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); } bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_icons[i]) + if (m_current_tool == tool_ids[i]) { ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); } ImGui::PopStyleVar(1); - if (btn_clicked && m_current_tool != tool_icons[i]) { - m_current_tool = tool_icons[i]; + if (btn_clicked && m_current_tool != tool_ids[i]) { + m_current_tool = tool_ids[i]; for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -518,9 +531,17 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f"); ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(circle_max_width); @@ -536,8 +557,17 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_cursor_type = TriangleSelector::CursorType::POINTER; m_tool_type = ToolType::BRUSH; - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(clipping_slider_left); @@ -574,9 +604,17 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_smart_fill_angle = -1.f; } ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(sliders_left_width); @@ -602,9 +640,17 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::BBLDragFloat("##cursor_height_input", &m_cursor_height, 0.05f, 0.0f, 0.0f, "%.2f"); ImGui::Separator(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(height_max_width); @@ -692,7 +738,9 @@ void GLGizmoMmuSegmentation::update_model_object() if (updated) { const ModelObjectPtrs &mos = wxGetApp().model().objects; - wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin()); + size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin(); + wxGetApp().obj_list()->update_info_items(obj_idx); + wxGetApp().plater()->get_partplate_list().notify_instance_update(obj_idx, 0); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } } @@ -727,6 +775,7 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() EnforcerBlockerType max_ebt = (EnforcerBlockerType)std::min(m_extruders_colors.size(), (size_t)EnforcerBlockerType::ExtruderMax); m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), false, max_ebt); m_triangle_selectors.back()->request_update_render_data(); + m_triangle_selectors.back()->set_wireframe_needed(true); m_volumes_extruder_idxs.push_back(mv->extruder_id()); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index de032fc84f..da9c5d9c64 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -100,9 +100,9 @@ protected: wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; - std::string get_gizmo_entering_text() const override { return _u8L("Entering color painting"); } - std::string get_gizmo_leaving_text() const override { return _u8L("Leaving color painting"); } - std::string get_action_snapshot_name() override { return _u8L("Color painting editing"); } + std::string get_gizmo_entering_text() const override { return "Entering color painting"; } + std::string get_gizmo_leaving_text() const override { return "Leaving color painting"; } + std::string get_action_snapshot_name() override { return "Color painting editing"; } // BBS size_t m_selected_extruder_idx = 0; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 549972119c..b4a9fbee26 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -877,12 +877,12 @@ void GLGizmoPainterBase::on_set_state() on_opening(); const Selection& selection = m_parent.get_selection(); - Camera& camera = wxGetApp().plater()->get_camera(); - Vec3d rotate_target = selection.get_bounding_box().center(); - rotate_target(2) = 0.f; - Vec3d position = camera.get_position(); + //Camera& camera = wxGetApp().plater()->get_camera(); + //Vec3d rotate_target = selection.get_bounding_box().center(); + //rotate_target(2) = 0.f; + //Vec3d position = camera.get_position(); //camera.set_target(rotate_target); - camera.look_at(position, rotate_target, Vec3d::UnitZ()); + //camera.look_at(position, rotate_target, Vec3d::UnitZ()); } if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off // we are actually shutting down @@ -1076,6 +1076,20 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) if (!shader) return; assert(shader->get_name() == "mm_gouraud"); + GLint position_id = -1; + GLint barycentric_id = -1; + if (wxGetApp().plater()->is_wireframe_enabled()) { + position_id = shader->get_attrib_location("v_position"); + barycentric_id = shader->get_attrib_location("v_barycentric"); + if (m_need_wireframe && wxGetApp().plater()->is_show_wireframe()) { + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe on"); + shader->set_uniform("show_wireframe", true); + } + else { + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", show_wireframe off"); + shader->set_uniform("show_wireframe", false); + } + } for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { if (this->has_VBOs(buffer_idx)) { @@ -1094,11 +1108,13 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) std::array new_color = adjust_color_for_rendering(color); shader->set_uniform("uniform_color", new_color); //shader->set_uniform("uniform_color", color); - this->render(buffer_idx); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", buffer_idx %1%: new_color[%2%, %3%, %4%, %5%]")%buffer_idx%new_color[0]%new_color[1]%new_color[2]%new_color[3]; + this->render(buffer_idx, (int)position_id, (int)barycentric_id); } } - if (m_paint_contour.has_VBO()) { + if (m_paint_contour.has_VBO()) + { ScopeGuard guard_mm_gouraud([shader]() { shader->start_using(); }); shader->stop_using(); @@ -1117,6 +1133,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui) void TriangleSelectorPatch::update_triangles_per_type() { + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", enter"); m_triangle_patches.resize((int)EnforcerBlockerType::ExtruderMax + 1); for (int i = 0; i < m_triangle_patches.size(); i++) { auto& patch = m_triangle_patches[i]; @@ -1124,14 +1141,44 @@ void TriangleSelectorPatch::update_triangles_per_type() patch.triangle_indices.reserve(m_triangles.size() / 3); } + bool using_wireframe = (wxGetApp().plater()->is_wireframe_enabled())?true:false; + for (auto& triangle : m_triangles) { if (!triangle.valid() || triangle.is_split()) continue; int state = (int)triangle.get_state(); auto& patch = m_triangle_patches[state]; - patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end()); + //patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end()); + for (int i = 0; i < 3; ++i) { + int j = triangle.verts_idxs[i]; + int index = using_wireframe?int(patch.patch_vertices.size()/6) : int(patch.patch_vertices.size()/3); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: i=%2%, j=%3%, index=%4%, v[%5%,%6%,%7%]")%__LINE__%i%j%index%m_vertices[j].v(0)%m_vertices[j].v(1)%m_vertices[j].v(2); + patch.patch_vertices.emplace_back(m_vertices[j].v(0)); + patch.patch_vertices.emplace_back(m_vertices[j].v(1)); + patch.patch_vertices.emplace_back(m_vertices[j].v(2)); + if (using_wireframe) { + if (i == 0) { + patch.patch_vertices.emplace_back(1.0); + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(0.0); + } + else if (i == 1) { + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(1.0); + patch.patch_vertices.emplace_back(0.0); + } + else { + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(1.0); + } + } + patch.triangle_indices.emplace_back( index); + } + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: state=%2%, vertice size=%3%, triangle size %4%")%__LINE__%state%patch.patch_vertices.size()%patch.triangle_indices.size(); } + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("exit"); } void TriangleSelectorPatch::update_selector_triangles() @@ -1152,6 +1199,8 @@ void TriangleSelectorPatch::update_triangles_per_patch() auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors(); std::vector visited(m_triangles.size(), false); + bool using_wireframe = (wxGetApp().plater()->is_wireframe_enabled())?true:false; + auto get_all_touching_triangles = [this](int facet_idx, const Vec3i& neighbors, const Vec3i& neighbors_propagated) -> std::vector { assert(facet_idx != -1 && facet_idx < int(m_triangles.size())); assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); @@ -1202,7 +1251,32 @@ void TriangleSelectorPatch::update_triangles_per_patch() if (!visited[current_facet]) { Triangle& triangle = m_triangles[current_facet]; - patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end()); + for (int i = 0; i < 3; ++i) { + int j = triangle.verts_idxs[i]; + int index = using_wireframe?int(patch.patch_vertices.size()/6) : int(patch.patch_vertices.size()/3); + patch.patch_vertices.emplace_back(m_vertices[j].v(0)); + patch.patch_vertices.emplace_back(m_vertices[j].v(1)); + patch.patch_vertices.emplace_back(m_vertices[j].v(2)); + if (using_wireframe) { + if (i == 0) { + patch.patch_vertices.emplace_back(1.0); + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(0.0); + } + else if (i == 1) { + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(1.0); + patch.patch_vertices.emplace_back(0.0); + } + else { + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(0.0); + patch.patch_vertices.emplace_back(1.0); + } + } + patch.triangle_indices.emplace_back( index); + } + //patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end()); patch.facet_indices.push_back(current_facet); std::vector touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]); @@ -1246,16 +1320,17 @@ void TriangleSelectorPatch::set_filter_state(bool is_filter_state) void TriangleSelectorPatch::update_render_data() { - if (m_paint_changed || m_vertices_VBO_id == 0) { + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", m_paint_changed=%1%, m_triangle_patches.size %2%")%m_paint_changed%m_triangle_patches.size(); + if (m_paint_changed || (m_triangle_patches.size() == 0)) { this->release_geometry(); - m_patch_vertices.reserve(m_vertices.size() * 3); + /*m_patch_vertices.reserve(m_vertices.size() * 3); for (const Vertex& vr : m_vertices) { m_patch_vertices.emplace_back(vr.v.x()); m_patch_vertices.emplace_back(vr.v.y()); m_patch_vertices.emplace_back(vr.v.z()); } - this->finalize_vertices(); + this->finalize_vertices();*/ if (m_filter_state) update_triangles_per_patch(); @@ -1266,6 +1341,8 @@ void TriangleSelectorPatch::update_render_data() m_paint_changed = false; } + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", before paint_contour"); + m_paint_contour.release_geometry(); std::vector contour_edges = this->get_seed_fill_contour(); m_paint_contour.contour_vertices.reserve(contour_edges.size() * 6); @@ -1284,17 +1361,37 @@ void TriangleSelectorPatch::update_render_data() m_paint_contour.contour_indices_size = m_paint_contour.contour_indices.size(); m_paint_contour.finalize_geometry(); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", exit"); } -void TriangleSelectorPatch::render(int triangle_indices_idx) +void TriangleSelectorPatch::render(int triangle_indices_idx, int position_id, int barycentric_id) { assert(triangle_indices_idx < this->m_triangle_indices_VBO_ids.size()); assert(this->m_triangle_patches.size() == this->m_triangle_indices_VBO_ids.size()); - assert(this->m_vertices_VBO_id != 0); + //assert(this->m_vertices_VBO_id != 0); + assert(this->m_triangle_patches.size() == this->m_vertices_VBO_ids.size()); + assert(this->m_vertices_VBO_ids[triangle_indices_idx] != 0); assert(this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float)))); + //glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_id)); + //glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float)))); + if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) { + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_ids[triangle_indices_idx])); + if (position_id != -1) { + glsafe(::glEnableVertexAttribArray((GLint)position_id)); + glsafe(::glVertexAttribPointer((GLint)position_id, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), nullptr)); + } + else { + glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); + } + + if (barycentric_id != -1) { + glsafe(::glEnableVertexAttribArray((GLint)barycentric_id)); + glsafe(::glVertexAttribPointer((GLint)barycentric_id, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (GLvoid*)(intptr_t)(3 * sizeof(float)))); + } + //glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr)); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: triangle_indices_idx %2%, bind vertex vbo, buffer id %3%")%__LINE__%triangle_indices_idx%this->m_vertices_VBO_ids[triangle_indices_idx]; + } glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); @@ -1303,45 +1400,68 @@ void TriangleSelectorPatch::render(int triangle_indices_idx) glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_triangle_indices_VBO_ids[triangle_indices_idx])); glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->m_triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr)); glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: triangle_indices_idx %2%, bind indices vbo, buffer id %3%")%__LINE__%triangle_indices_idx%this->m_triangle_indices_VBO_ids[triangle_indices_idx]; } glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + if ((this->m_triangle_indices_sizes[triangle_indices_idx] > 0)&&(position_id != -1)) + glsafe(::glDisableVertexAttribArray(position_id)); + if ((this->m_triangle_indices_sizes[triangle_indices_idx] > 0)&&(barycentric_id != -1)) + glsafe(::glDisableVertexAttribArray((GLint)barycentric_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + if (this->m_triangle_indices_sizes[triangle_indices_idx] > 0) + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } void TriangleSelectorPatch::release_geometry() { - if (m_vertices_VBO_id) { + /*if (m_vertices_VBO_id) { glsafe(::glDeleteBuffers(1, &m_vertices_VBO_id)); m_vertices_VBO_id = 0; + }*/ + for (auto& vertice_VBO_id : m_vertices_VBO_ids) { + glsafe(::glDeleteBuffers(1, &vertice_VBO_id)); + vertice_VBO_id = 0; } for (auto& triangle_indices_VBO_id : m_triangle_indices_VBO_ids) { glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); triangle_indices_VBO_id = 0; } this->clear(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: released geometry")%__LINE__; } void TriangleSelectorPatch::finalize_vertices() { - assert(m_vertices_VBO_id == 0); + /*assert(m_vertices_VBO_id == 0); if (!this->m_patch_vertices.empty()) { glsafe(::glGenBuffers(1, &this->m_vertices_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_vertices_VBO_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, this->m_patch_vertices.size() * sizeof(float), this->m_patch_vertices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); this->m_patch_vertices.clear(); - } + }*/ } void TriangleSelectorPatch::finalize_triangle_indices() { + m_vertices_VBO_ids.resize(m_triangle_patches.size()); m_triangle_indices_VBO_ids.resize(m_triangle_patches.size()); m_triangle_indices_sizes.resize(m_triangle_patches.size()); assert(std::all_of(m_triangle_indices_VBO_ids.cbegin(), m_triangle_indices_VBO_ids.cend(), [](const auto& ti_VBO_id) { return ti_VBO_id == 0; })); for (size_t buffer_idx = 0; buffer_idx < m_triangle_patches.size(); ++buffer_idx) { + std::vector& patch_vertices = m_triangle_patches[buffer_idx].patch_vertices; + if (!patch_vertices.empty()) { + glsafe(::glGenBuffers(1, &m_vertices_VBO_ids[buffer_idx])); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vertices_VBO_ids[buffer_idx])); + glsafe(::glBufferData(GL_ARRAY_BUFFER, patch_vertices.size() * sizeof(float), patch_vertices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%patch_vertices.size()%m_vertices_VBO_ids[buffer_idx]; + patch_vertices.clear(); + } + std::vector& triangle_indices = m_triangle_patches[buffer_idx].triangle_indices; m_triangle_indices_sizes[buffer_idx] = triangle_indices.size(); if (!triangle_indices.empty()) { @@ -1349,6 +1469,7 @@ void TriangleSelectorPatch::finalize_triangle_indices() glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangle_indices_VBO_ids[buffer_idx])); glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangle_indices.size() * sizeof(int), triangle_indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: buffer_idx %2%, vertices size %3%, buffer id %4%")%__LINE__%buffer_idx%triangle_indices.size()%m_triangle_indices_VBO_ids[buffer_idx]; triangle_indices.clear(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index a0791bb887..487160aaa2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -73,6 +73,8 @@ public: // to be already set. virtual void render(ImGuiWrapper *imgui); void render() { this->render(nullptr); } + void set_wireframe_needed(bool need_wireframe) { m_need_wireframe = need_wireframe; } + bool get_wireframe_needed() { return m_need_wireframe; } // BBS void request_update_render_data(bool paint_changed = false) @@ -108,10 +110,12 @@ private: protected: GLPaintContour m_paint_contour; + bool m_need_wireframe {false}; }; // BBS struct TrianglePatch { + std::vector patch_vertices; std::vector triangle_indices; std::vector facet_indices; EnforcerBlockerType type = EnforcerBlockerType::NONE; @@ -160,11 +164,15 @@ protected: void clear() { // BBS + this->m_vertices_VBO_ids.clear(); this->m_triangle_indices_VBO_ids.clear(); this->m_triangle_indices_sizes.clear(); for (TrianglePatch& patch : this->m_triangle_patches) + { + patch.patch_vertices.clear(); patch.triangle_indices.clear(); + } this->m_triangle_patches.clear(); } @@ -174,7 +182,7 @@ protected: return this->m_triangle_indices_VBO_ids[triangle_indices_idx] != 0; } - std::vector m_patch_vertices; + //std::vector m_patch_vertices; std::vector m_triangle_patches; // When the triangle indices are loaded into the graphics card as Vertex Buffer Objects, @@ -183,7 +191,8 @@ protected: // IDs of the Vertex Array Objects, into which the geometry has been loaded. // Zero if the VBOs are not sent to GPU yet. - unsigned int m_vertices_VBO_id{ 0 }; + //unsigned int m_vertices_VBO_id{ 0 }; + std::vector m_vertices_VBO_ids; std::vector m_triangle_indices_VBO_ids; std::vector> m_ebt_colors; @@ -192,7 +201,7 @@ protected: private: void update_render_data(); - void render(int buffer_idx); + void render(int buffer_idx, int position_id = -1, int barycentric_id = -1); }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 0e96fec842..11991c2480 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -132,6 +132,7 @@ void GLGizmoSeam::show_tooltip_information(float caption_max, float x, float y) float font_size = ImGui::GetFontSize(); ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, ImGui::GetStyle().FramePadding.y }); ImGui::ImageButton3(normal_id, hover_id, button_size); if (ImGui::IsItemHovered()) { @@ -145,7 +146,7 @@ void GLGizmoSeam::show_tooltip_information(float caption_max, float x, float y) for (const auto &t : std::array{"enforce", "block", "remove", "cursor_size", "clipping_of_view"}) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); ImGui::EndTooltip(); } - ImGui::PopStyleVar(1); + ImGui::PopStyleVar(2); } void GLGizmoSeam::tool_changed(wchar_t old_tool, wchar_t new_tool) @@ -184,7 +185,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: const float space_size = m_imgui->get_style_scaling() * 8; const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, - m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->calc_text_size(m_desc.at("reset_direction")).x + ImGui::GetStyle().FramePadding.x * 2) + m_imgui->scaled(1.5f); const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f); const float empty_button_width = m_imgui->calc_button_size("").x; @@ -206,31 +207,36 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_type")); - std::array tool_icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon}; + std::array tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon }; + std::array icons; + if (m_is_dark_mode) + icons = { ImGui::CircleButtonDarkIcon, ImGui::SphereButtonDarkIcon}; + else + icons = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon }; std::array tool_tips = { _L("Circle"), _L("Sphere")}; - for (int i = 0; i < tool_icons.size(); i++) { + for (int i = 0; i < tool_ids.size(); i++) { std::string str_label = std::string("##"); - std::wstring btn_name = tool_icons[i] + boost::nowide::widen(str_label); + std::wstring btn_name = icons[i] + boost::nowide::widen(str_label); if (i != 0) ImGui::SameLine((empty_button_width + m_imgui->scaled(1.75f)) * i + m_imgui->scaled(1.3f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - if (m_current_tool == tool_icons[i]) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + if (m_current_tool == tool_ids[i]) { + ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0); } bool btn_clicked = ImGui::Button(into_u8(btn_name).c_str()); - if (m_current_tool == tool_icons[i]) + if (m_current_tool == tool_ids[i]) { ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); } ImGui::PopStyleVar(1); - if (btn_clicked && m_current_tool != tool_icons[i]) { - m_current_tool = tool_icons[i]; + if (btn_clicked && m_current_tool != tool_ids[i]) { + m_current_tool = tool_ids[i]; for (auto& triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->request_update_render_data(); @@ -265,8 +271,18 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::PushItemWidth(1.5 * slider_icon_width); ImGui::BBLDragFloat("##cursor_radius_input", &m_cursor_radius, 0.05f, 0.0f, 0.0f, "%.2f"); - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); + ImGui::Separator(); + if (m_c->object_clipper()->get_position() == 0.f) { + ImGui::AlignTextToFramePadding(); + m_imgui->text(m_desc.at("clipping_of_view")); + } + else { + if (m_imgui->button(m_desc.at("reset_direction"))) { + wxGetApp().CallAfter([this]() { + m_c->object_clipper()->set_position(-1., false); + }); + } + } auto clp_dist = float(m_c->object_clipper()->get_position()); ImGui::SameLine(sliders_left_width); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index 952c1b18b1..128a87cc56 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -29,9 +29,9 @@ protected: wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; - std::string get_gizmo_entering_text() const override { return _u8L("Entering Seam painting"); } - std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Seam painting"); } - std::string get_action_snapshot_name() override { return _u8L("Paint-on seam editing"); } + std::string get_gizmo_entering_text() const override { return "Entering Seam painting"; } + std::string get_gizmo_leaving_text() const override { return "Leaving Seam painting"; } + std::string get_action_snapshot_name() override { return "Paint-on seam editing"; } private: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 83a832ca8b..3ef8ccd3e1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -236,7 +236,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi ImGuiWindowFlags_NoCollapse; m_imgui->begin(on_get_name(), flag); - m_imgui->text_colored(ImVec4(0.15f, 0.18f, 0.19f, 1.00f), tr_mesh_name + ":"); + m_imgui->text(tr_mesh_name + ":"); // BBS: somehow the calculated utf8 width is too narrow, have to add 35 here ImGui::SameLine(text_left_width + space_size); std::string name = m_volume->name; @@ -244,7 +244,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi name = name.substr(0, m_gui_cfg->max_char_in_name - 3) + "..."; m_imgui->text_colored(ImVec4(0.42f, 0.42f, 0.42f, 1.00f), name); - m_imgui->text_colored(ImVec4(0.15f, 0.18f, 0.19f, 1.00f), tr_triangles + ":"); + m_imgui->text(tr_triangles + ":"); ImGui::SameLine(text_left_width + space_size); size_t orig_triangle_count = m_volume->mesh().its.indices.size(); @@ -361,22 +361,26 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.15f, 0.18f, 0.19f, 1.00f)); m_imgui->disabled_begin(is_worker_running || ! is_result_ready); + m_imgui->push_confirm_button_style(); if (m_imgui->bbl_button(_L("Apply"))) { apply_simplify(); } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_worker_running) { ImGui::SetTooltip("%s", _u8L("Can't apply when proccess preview.").c_str()); } + m_imgui->pop_confirm_button_style(); m_imgui->disabled_end(); // state !settings ImGui::SameLine(); m_imgui->disabled_begin(is_cancelling); + m_imgui->push_cancel_button_style(); if (m_imgui->bbl_button(_L("Cancel"))) { close(); } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_cancelling) ImGui::SetTooltip("%s", _u8L("Operation already cancelling. Please wait few seconds.").c_str()); + m_imgui->pop_cancel_button_style(); m_imgui->disabled_end(); // state cancelling ImGui::PopStyleVar(3); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 35e6a73089..8dd76336a3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -68,8 +68,8 @@ public: void reslice_SLA_supports(bool postpone_error_messages = false) const; bool wants_enter_leave_snapshots() const override { return true; } - std::string get_gizmo_entering_text() const override { return _u8L("Entering SLA support points"); } - std::string get_gizmo_leaving_text() const override { return _u8L("Leaving SLA support points"); } + std::string get_gizmo_entering_text() const override { return "Entering SLA support points"; } + std::string get_gizmo_leaving_text() const override { return "Leaving SLA support points"; } private: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp index 61763b1970..f5e54ce569 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp @@ -23,20 +23,66 @@ namespace Slic3r { namespace GUI { -static double g_normal_precise = 0.0015; +static const wxColour FONT_TEXTURE_BG = wxColour(0, 0, 0, 0); +static const wxColour FONT_TEXTURE_FG = *wxWHITE; +static const int FONT_SIZE = 12; + GLGizmoText::GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id) { } +GLGizmoText::~GLGizmoText() +{ + for (int i = 0; i < m_textures.size(); i++) { + if (m_textures[i].texture != nullptr) + delete m_textures[i].texture; + } +} + bool GLGizmoText::on_init() { m_avail_font_names = init_occt_fonts(); + update_font_texture(); + m_scale = m_imgui->get_font_size(); m_shortcut_key = WXK_CONTROL_T; return true; } +void GLGizmoText::update_font_texture() +{ + for (int i = 0; i < m_textures.size(); i++) { + if (m_textures[i].texture != nullptr) + delete m_textures[i].texture; + } + m_combo_width = 0.0f; + m_combo_height = 0.0f; + m_textures.clear(); + m_textures.reserve(m_avail_font_names.size()); + for (int i = 0; i < m_avail_font_names.size(); i++) + { + GLTexture* texture = new GLTexture(); + auto face = wxString::FromUTF8(m_avail_font_names[i]); + auto retina_scale = m_parent.get_scale(); + wxFont font { (int)round(retina_scale * FONT_SIZE), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, face }; + int w, h, hl; + if (texture->generate_texture_from_text(m_avail_font_names[i], font, w, h, hl, FONT_TEXTURE_BG, FONT_TEXTURE_FG)) { + //if (h < m_imgui->scaled(2.f)) { + TextureInfo info; + info.texture = texture; + info.w = w; + info.h = h; + info.hl = hl; + info.font_name = m_avail_font_names[i]; + m_textures.push_back(info); + m_combo_width = std::max(m_combo_width, static_cast(texture->m_original_width)); + //} + } + } + m_combo_height = m_imgui->scaled(32.f / 15.f); +} + void GLGizmoText::on_set_state() { } @@ -68,28 +114,89 @@ void GLGizmoText::on_render_for_picking() // TODO: } -void GLGizmoText::push_combo_style(const float scale) -{ - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG); - ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG); - ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); +void GLGizmoText::push_button_style(bool pressed) { + if (m_is_dark_mode) { + if (pressed) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f)); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(45.f / 255.f, 45.f / 255.f, 49.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(45.f / 255.f, 45.f / 255.f, 49.f / 255.f, 1.f)); + } + } + else { + if (pressed) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f)); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(238 / 255.f, 238 / 255.f, 238 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(238 / 255.f, 238 / 255.f, 238 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.f, 1.f, 1.f, 1.f)); + } + + } +} + +void GLGizmoText::pop_button_style() { + ImGui::PopStyleColor(4); +} + +void GLGizmoText::push_combo_style(const float scale) { + if (m_is_dark_mode) { + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); + } + else { + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); + } } void GLGizmoText::pop_combo_style() { ImGui::PopStyleVar(2); - ImGui::PopStyleColor(7); + ImGui::PopStyleColor(9); } // BBS void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) { + if (m_imgui->get_font_size() != m_scale) { + m_scale = m_imgui->get_font_size(); + update_font_texture(); + } + if (m_textures.size() == 0) { + BOOST_LOG_TRIVIAL(info) << "GLGizmoText has no texture"; + return; + } + const float win_h = ImGui::GetWindowHeight(); y = std::min(y, bottom_limit - win_h); GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); @@ -114,12 +221,9 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) float input_size = input_text_size - button_size * 2 - ImGui::GetStyle().ItemSpacing.x * 4; ImTextureID normal_B = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B); - ImTextureID press_B_hover = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B_HOVER); - ImTextureID press_B_press = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B_PRESS); - ImTextureID normal_T = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T); - ImTextureID press_T_hover = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T_HOVER); - ImTextureID press_T_press = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T_PRESS); + ImTextureID normal_B_dark = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B_DARK); + ImTextureID normal_T_dark = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T_DARK); // adjust window position to avoid overlap the view toolbar if (last_h != win_h || last_y != y) { @@ -133,28 +237,29 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::AlignTextToFramePadding(); - const char** cstr_font_names = (const char**)calloc(m_avail_font_names.size(), sizeof(const char*)); - for (int i = 0; i < m_avail_font_names.size(); i++) - cstr_font_names[i] = m_avail_font_names[i].c_str(); - m_imgui->text(_L("Font")); ImGui::SameLine(caption_size); ImGui::PushItemWidth(input_text_size + ImGui::GetFrameHeight() * 2); push_combo_style(currt_scale); - if (ImGui::BBLBeginCombo("##Font", cstr_font_names[m_curr_font_idx], 0)) { + int font_index = m_curr_font_idx; + if (ImGui::BBLBeginCombo("##Font", m_textures[m_curr_font_idx].font_name.c_str(), 0)) { ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f, 0.0f) * currt_scale); - for (int i = 0; i < m_avail_font_names.size(); i++) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 4)); + for (int i = 0; i < m_textures.size(); i++) { const bool is_selected = (m_curr_font_idx == i); - if (ImGui::BBLSelectable(cstr_font_names[i], is_selected)) { + ImTextureID icon_id = (ImTextureID)(intptr_t)(m_textures[i].texture->get_id()); + ImVec4 tint_color = ImGui::GetStyleColorVec4(ImGuiCol_Text); + ImVec2 selectable_size(std::max((input_text_size + ImGui::GetFrameHeight() * 2), m_combo_width), m_combo_height); + if (ImGui::BBLImageSelectable(icon_id, selectable_size, { (float)m_textures[i].w, (float)m_textures[i].h }, m_textures[i].hl, tint_color, { 0, 0 }, {1, 1}, is_selected)) { m_curr_font_idx = i; - m_font_name = cstr_font_names[m_curr_font_idx]; + m_font_name = m_textures[m_curr_font_idx].font_name; } if (is_selected) { ImGui::SetItemDefaultFocus(); } } - ImGui::PopStyleVar(2); + ImGui::PopStyleVar(3); ImGui::EndCombo(); } @@ -167,12 +272,19 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) if (m_font_size < 3.0f)m_font_size = 3.0f; ImGui::SameLine(); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0.0,0.0}); - ImGui::BBLImageButton(normal_B,press_B_hover,press_B_press,{button_size,button_size},m_bold); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * currt_scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {1.0f * currt_scale, 1.0f * currt_scale }); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f * currt_scale); + push_button_style(m_bold); + if (ImGui::ImageButton(m_is_dark_mode ? normal_B_dark : normal_B, { button_size - 2 * ImGui::GetStyle().FramePadding.x, button_size - 2 * ImGui::GetStyle().FramePadding.y })) + m_bold = !m_bold; + pop_button_style(); ImGui::SameLine(); - ImGui::BBLImageButton(normal_T,press_T_hover,press_T_press,{button_size,button_size},m_italic); - ImGui::PopStyleVar(2); + push_button_style(m_italic); + if (ImGui::ImageButton(m_is_dark_mode ? normal_T_dark : normal_T, { button_size - 2 * ImGui::GetStyle().FramePadding.x, button_size - 2 * ImGui::GetStyle().FramePadding.y })) + m_italic = !m_italic; + pop_button_style(); + ImGui::PopStyleVar(3); ImGui::AlignTextToFramePadding(); m_imgui->text(_L("Thickness")); @@ -185,6 +297,7 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(_L("Input text")); ImGui::SameLine(caption_size); ImGui::PushItemWidth(input_text_size); + ImGui::InputText("", m_text, sizeof(m_text)); ImGui::Separator(); @@ -194,13 +307,29 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(offset); bool add_clicked = m_imgui->button(_L("Add")); if (add_clicked) { + m_imgui->disabled_end(); + GizmoImguiEnd(); + ImGui::PopStyleVar(); + ImGuiWrapper::pop_toolbar_style(); + TriangleMesh mesh; load_text_shape(m_text, m_font_name.c_str(), m_font_size, m_thickness, m_bold, m_italic, mesh); ObjectList* obj_list = wxGetApp().obj_list(); obj_list->load_mesh_part(mesh, "text_shape"); + + return; } m_imgui->disabled_end(); +#if 0 + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + ImVec4 tint_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); + ImVec4 border_col = ImVec4(0.0f, 0.0f, 0.0f, 0.8f); + m_imgui->text(wxString("") << atlas->TexWidth << " * " << atlas->TexHeight); + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); +#endif + GizmoImguiEnd(); ImGui::PopStyleVar(); ImGuiWrapper::pop_toolbar_style(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp index 121263741b..668e6bf0fd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp @@ -3,7 +3,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/3DScene.hpp" - +#include "../GLTexture.hpp" namespace Slic3r { @@ -15,16 +15,34 @@ class GLGizmoText : public GLGizmoBase { private: std::vector m_avail_font_names; - char m_text[256] = { 0 }; + char m_text[1024] = { 0 }; std::string m_font_name; float m_font_size = 16.f; int m_curr_font_idx = 0; bool m_bold = true; bool m_italic = false; float m_thickness = 2.f; + float m_combo_height = 0.0f; + float m_combo_width = 0.0f; + float m_scale; + + class TextureInfo { + public: + GLTexture* texture { nullptr }; + int h; + int w; + int hl; + + std::string font_name; + }; + + std::vector m_textures; public: GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); + ~GLGizmoText(); + + void update_font_texture(); protected: virtual bool on_init() override; @@ -34,6 +52,8 @@ protected: virtual void on_render_for_picking() override; void push_combo_style(const float scale); void pop_combo_style(); + void push_button_style(bool pressed); + void pop_button_style(); virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; virtual void on_render_input_window(float x, float y, float bottom_limit); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index a8ef43c85b..d52969ba5b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -433,11 +433,11 @@ void ObjectClipper::set_position(double pos, bool keep_normal) int active_inst = get_pool()->selection_info()->get_active_instance(); double z_shift = get_pool()->selection_info()->get_sla_shift(); - Vec3d camera_dir = wxGetApp().plater()->get_camera().get_dir_forward(); - if (abs(camera_dir(0)) > EPSILON || abs(camera_dir(1)) > EPSILON) - camera_dir(2) = 0; + //Vec3d camera_dir = wxGetApp().plater()->get_camera().get_dir_forward(); + //if (abs(camera_dir(0)) > EPSILON || abs(camera_dir(1)) > EPSILON) + // camera_dir(2) = 0; - Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : -camera_dir; + Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : /*-camera_dir;*/ -wxGetApp().plater()->get_camera().get_dir_forward(); const Vec3d& center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift); float dist = normal.dot(center); @@ -697,8 +697,7 @@ void ModelObjectsClipper::render_cut() const void ModelObjectsClipper::set_position(double pos, bool keep_normal) { - Vec3d camera_dir = wxGetApp().plater()->get_camera().get_dir_forward(); - Vec3d normal = -camera_dir; + Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward(); const Vec3d& center = get_pool()->get_canvas()->volumes_bounding_box().center(); float dist = normal.dot(center); @@ -708,6 +707,7 @@ void ModelObjectsClipper::set_position(double pos, bool keep_normal) m_clp_ratio = pos; m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius * GLVolume::explosion_ratio) - m_clp_ratio * 2 * m_active_inst_bb_radius * GLVolume::explosion_ratio))); get_pool()->get_canvas()->set_as_dirty(); + } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index df59dff67f..855fee0557 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -120,12 +120,57 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const return Undefined; } +void GLGizmosManager::switch_gizmos_icon_filename() +{ + m_background_texture.metadata.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; + m_background_texture.metadata.left = 16; + m_background_texture.metadata.top = 16; + m_background_texture.metadata.right = 16; + m_background_texture.metadata.bottom = 16; + if (!m_background_texture.metadata.filename.empty()) + m_background_texture.texture.load_from_file(resources_dir() + "/images/" + m_background_texture.metadata.filename, false, GLTexture::SingleThreaded, false); + + for (auto& gizmo : m_gizmos) { + gizmo->on_change_color_mode(m_is_dark); + switch (gizmo->get_sprite_id()) + { + case(EType::Move): + gizmo->set_icon_filename(m_is_dark ? "toolbar_move_dark.svg" : "toolbar_move.svg"); + break; + case(EType::Rotate): + gizmo->set_icon_filename(m_is_dark ? "toolbar_rotate_dark.svg" : "toolbar_rotate.svg"); + break; + case(EType::Scale): + gizmo->set_icon_filename(m_is_dark ? "toolbar_scale_dark.svg" : "toolbar_scale.svg"); + break; + case(EType::Flatten): + gizmo->set_icon_filename(m_is_dark ? "toolbar_flatten_dark.svg" : "toolbar_flatten.svg"); + break; + case(EType::Cut): + gizmo->set_icon_filename(m_is_dark ? "toolbar_cut_dark.svg" : "toolbar_cut.svg"); + break; + case(EType::FdmSupports): + gizmo->set_icon_filename(m_is_dark ? "toolbar_support_dark.svg" : "toolbar_support.svg"); + break; + case(EType::Seam): + gizmo->set_icon_filename(m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg"); + break; + case(EType::Text): + gizmo->set_icon_filename(m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg"); + break; + case(EType::MmuSegmentation): + gizmo->set_icon_filename(m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg"); + break; + } + } +} + bool GLGizmosManager::init() { bool result = init_icon_textures(); if (!result) return result; - m_background_texture.metadata.filename = "toolbar_background.png"; + m_background_texture.metadata.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png"; m_background_texture.metadata.left = 16; m_background_texture.metadata.top = 16; m_background_texture.metadata.right = 16; @@ -139,23 +184,25 @@ bool GLGizmosManager::init() // Order of gizmos in the vector must match order in EType! //BBS: GUI refactor: add obj manipulation + m_gizmos.clear(); unsigned int sprite_id = 0; - m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "toolbar_move.svg", EType::Move, &m_object_manipulation)); - m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "toolbar_rotate.svg", EType::Rotate, &m_object_manipulation)); - m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "toolbar_scale.svg", EType::Scale, &m_object_manipulation)); - m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "toolbar_flatten.svg", EType::Flatten)); - m_gizmos.emplace_back(new GLGizmoAdvancedCut(m_parent, "toolbar_cut.svg", EType::Cut)); - m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "toolbar_support.svg", EType::FdmSupports)); - m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "toolbar_seam.svg", EType::Seam)); - m_gizmos.emplace_back(new GLGizmoText(m_parent, "toolbar_text.svg", EType::Text)); - m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", EType::MmuSegmentation)); + m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, m_is_dark ? "toolbar_move_dark.svg" : "toolbar_move.svg", EType::Move, &m_object_manipulation)); + m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, m_is_dark ? "toolbar_rotate_dark.svg" : "toolbar_rotate.svg", EType::Rotate, &m_object_manipulation)); + m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, m_is_dark ? "toolbar_scale_dark.svg" : "toolbar_scale.svg", EType::Scale, &m_object_manipulation)); + m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, m_is_dark ? "toolbar_flatten_dark.svg" : "toolbar_flatten.svg", EType::Flatten)); + m_gizmos.emplace_back(new GLGizmoAdvancedCut(m_parent, m_is_dark ? "toolbar_cut_dark.svg" : "toolbar_cut.svg", EType::Cut)); + m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, m_is_dark ? "toolbar_support_dark.svg" : "toolbar_support.svg", EType::FdmSupports)); + m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam)); + m_gizmos.emplace_back(new GLGizmoText(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Text)); + m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg", EType::MmuSegmentation)); m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "reduce_triangles.svg", EType::Simplify)); //m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", sprite_id++)); //m_gizmos.emplace_back(new GLGizmoFaceDetector(m_parent, "face recognition.svg", sprite_id++)); //m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", sprite_id++)); m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent)); - m_assemble_view_data.reset(new AssembleViewDataPool(&m_parent)); + if(!m_assemble_view_data) + m_assemble_view_data.reset(new AssembleViewDataPool(&m_parent)); for (auto& gizmo : m_gizmos) { if (! gizmo->init()) { @@ -163,6 +210,7 @@ bool GLGizmosManager::init() return false; } gizmo->set_common_data_pool(m_common_gizmos_data.get()); + gizmo->on_change_color_mode(m_is_dark); } m_current = Undefined; @@ -203,30 +251,20 @@ bool GLGizmosManager::init_icon_textures() else return false; - if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_B_hover.svg", 20, 20, texture_id)) - icon_list.insert(std::make_pair((int)IC_TEXT_B_HOVER, texture_id)); - else - return false; - - if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_B_press.svg", 20, 20, texture_id)) - icon_list.insert(std::make_pair((int)IC_TEXT_B_PRESS, texture_id)); - else - return false; + if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_B_dark.svg", 20, 20, texture_id)) + icon_list.insert(std::make_pair((int)IC_TEXT_B_DARK, texture_id)); + else + return false; if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_T.svg", 20, 20, texture_id)) icon_list.insert(std::make_pair((int)IC_TEXT_T, texture_id)); else return false; - if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_T_hover.svg", 20, 20, texture_id)) - icon_list.insert(std::make_pair((int)IC_TEXT_T_HOVER, texture_id)); - else - return false; - - if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_T_press.svg", 20, 20, texture_id)) - icon_list.insert(std::make_pair((int)IC_TEXT_T_PRESS, texture_id)); - else - return false; + if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/text_T_dark.svg", 20, 20, texture_id)) + icon_list.insert(std::make_pair((int)IC_TEXT_T_DARK, texture_id)); + else + return false; return true; } @@ -617,6 +655,10 @@ bool GLGizmosManager::wants_reslice_supports_on_undo() const && dynamic_cast(m_gizmos.at(SlaSupports).get())->has_backend_supports()); } +void GLGizmosManager::on_change_color_mode(bool is_dark) { + m_is_dark = is_dark; +} + void GLGizmosManager::render_current_gizmo() const { if (!m_enabled || m_current == Undefined) @@ -640,7 +682,7 @@ void GLGizmosManager::render_painter_gizmo() const void GLGizmosManager::render_painter_assemble_view() const { - if (m_assemble_view_data) + if (m_assemble_view_data && m_assemble_view_data->model_objects_clipper()) m_assemble_view_data->model_objects_clipper()->render_cut(); } @@ -653,7 +695,7 @@ void GLGizmosManager::render_current_gizmo_for_picking_pass() const m_gizmos[m_current]->render_for_picking(); } -void GLGizmosManager::render_overlay() const +void GLGizmosManager::render_overlay() { if (!m_enabled) return; @@ -1037,6 +1079,14 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt) //break; //} + // BBS: Skip all keys when in gizmo. This is necessary for 3D text tool. + default: + { + if (is_running() && m_current == EType::Text) { + processed = true; + } + break; + } } } @@ -1484,6 +1534,9 @@ bool GLGizmosManager::activate_gizmo(EType type) GLGizmoBase* new_gizmo = type == Undefined ? nullptr : m_gizmos[type].get(); if (old_gizmo) { + //if (m_current == Text) { + // wxGetApp().imgui()->destroy_fonts_texture(); + //} old_gizmo->set_state(GLGizmoBase::Off); if (old_gizmo->get_state() != GLGizmoBase::Off) return false; // gizmo refused to be turned off, do nothing. @@ -1503,8 +1556,12 @@ bool GLGizmosManager::activate_gizmo(EType type) m_current = type; - if (new_gizmo) + if (new_gizmo) { + //if (m_current == Text) { + // wxGetApp().imgui()->load_fonts_texture(); + //} new_gizmo->set_state(GLGizmoBase::On); + } return true; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index c47aed6ba4..c943bc3888 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -144,6 +144,8 @@ private: // key MENU_ICON_NAME, value = ImtextureID std::map icon_list; + + bool m_is_dark = false; public: std::unique_ptr m_assemble_view_data; @@ -153,16 +155,16 @@ public: IC_TOOLBAR_TOOLTIP, IC_TOOLBAR_TOOLTIP_HOVER, IC_TEXT_B, - IC_TEXT_B_HOVER, - IC_TEXT_B_PRESS, + IC_TEXT_B_DARK, IC_TEXT_T, - IC_TEXT_T_HOVER, - IC_TEXT_T_PRESS, + IC_TEXT_T_DARK, IC_NAME_COUNT, }; explicit GLGizmosManager(GLCanvas3D& parent); + void switch_gizmos_icon_filename(); + bool init(); bool init_icon_textures(); @@ -209,6 +211,7 @@ public: bool is_enabled() const { return m_enabled; } void set_enabled(bool enable) { m_enabled = enable; } + void set_icon_dirty() { m_icons_texture_dirty = true; } void set_overlay_icon_size(float size); void set_overlay_scale(float scale); @@ -256,6 +259,12 @@ public: else return nullptr; } + void* get_icon_texture_id(MENU_ICON_NAME icon) const{ + if (icon_list.find((int)icon) != icon_list.end()) + return icon_list.at(icon); + else + return nullptr; + } Vec3d get_flattening_normal() const; @@ -273,12 +282,13 @@ public: bool is_in_editing_mode(bool error_notification = false) const; bool is_hiding_instances() const; + void on_change_color_mode(bool is_dark); void render_current_gizmo() const; void render_current_gizmo_for_picking_pass() const; void render_painter_gizmo() const; void render_painter_assemble_view() const; - void render_overlay() const; + void render_overlay(); void render_arrow(const GLCanvas3D& parent, EType highlighted_type) const; diff --git a/src/slic3r/GUI/HMS.cpp b/src/slic3r/GUI/HMS.cpp index e5fc020a3f..2bb7a78b37 100644 --- a/src/slic3r/GUI/HMS.cpp +++ b/src/slic3r/GUI/HMS.cpp @@ -44,9 +44,11 @@ int HMSQuery::download_hms_info() if (!config) return -1; std::string hms_host = wxGetApp().app_config->get_hms_host(); - std::string lang_code = wxGetApp().app_config->get_language_code(); + std::string lang_code = HMSQuery::hms_language_code(); std::string url = (boost::format("https://%1%/query.php?lang=%2%") % hms_host % lang_code).str(); + BOOST_LOG_TRIVIAL(info) << "hms: download url = " << url; + Slic3r::Http http = Slic3r::Http::get(url); http.on_complete([this](std::string body, unsigned status) { @@ -102,6 +104,7 @@ int HMSQuery::load_from_local(std::string &version_info) } } catch(...) { version_info = ""; + BOOST_LOG_TRIVIAL(error) << "HMS: load_from_local failed"; return -1; } version_info = ""; @@ -125,27 +128,42 @@ int HMSQuery::save_to_local() json_file.close(); return 0; } + BOOST_LOG_TRIVIAL(error) << "HMS: save_to_local failed"; return -1; } +std::string HMSQuery::hms_language_code() +{ + AppConfig* config = wxGetApp().app_config; + if (!config) + // set language code to en by default + return "en"; + std::string lang_code = wxGetApp().app_config->get_language_code(); + if (lang_code.empty()) { + // set language code to en by default + return "en"; + } + return lang_code; +} + std::string HMSQuery::get_hms_file() { - AppConfig* config = wxGetApp().app_config; - if (!config) - return HMS_INFO_FILE; - std::string lang_code = wxGetApp().app_config->get_language_code(); + std::string lang_code = HMSQuery::hms_language_code(); return (boost::format("hms_%1%.json") % lang_code).str(); } wxString HMSQuery::query_hms_msg(std::string long_error_code) { - if (long_error_code.empty()) - return wxEmptyString; AppConfig* config = wxGetApp().app_config; if (!config) return wxEmptyString; + std::string lang_code = HMSQuery::hms_language_code(); + return _query_hms_msg(long_error_code, lang_code); +} - std::string hms_host = wxGetApp().app_config->get_hms_host(); - std::string lang_code = wxGetApp().app_config->get_language_code(); +wxString HMSQuery::_query_hms_msg(std::string long_error_code, std::string lang_code) +{ + if (long_error_code.empty()) + return wxEmptyString; if (m_hms_json.contains("device_hms")) { if (m_hms_json["device_hms"].contains(lang_code)) { @@ -160,34 +178,61 @@ wxString HMSQuery::query_hms_msg(std::string long_error_code) } } BOOST_LOG_TRIVIAL(info) << "hms: query_hms_msg, not found error_code = " << long_error_code; + } else { + BOOST_LOG_TRIVIAL(error) << "hms: query_hms_msg, do not contains lang_code = " << lang_code; + // return first language + if (!m_hms_json["device_hms"].empty()) { + for (auto lang : m_hms_json["device_hms"]) { + for (auto item = lang.begin(); item != lang.end(); item++) { + if (item->contains("ecode")) { + std::string temp_string = (*item)["ecode"].get(); + if (boost::to_upper_copy(temp_string) == long_error_code) { + if (item->contains("intro")) { + return wxString::FromUTF8((*item)["intro"].get()); + } + } + } + } + } + } } } else { + BOOST_LOG_TRIVIAL(info) << "device_hms is not exists"; return wxEmptyString; } return wxEmptyString; } -wxString HMSQuery::query_error_msg(std::string error_code) +wxString HMSQuery::_query_error_msg(std::string error_code, std::string lang_code) { - AppConfig* config = wxGetApp().app_config; - if (!config) return wxEmptyString; - - std::string hms_host = wxGetApp().app_config->get_hms_host(); - std::string lang_code = wxGetApp().app_config->get_language_code(); - if (m_hms_json.contains("device_error")) { if (m_hms_json["device_error"].contains(lang_code)) { for (auto item = m_hms_json["device_error"][lang_code].begin(); item != m_hms_json["device_error"][lang_code].end(); item++) { - if (item->contains("ecode") && (*item)["ecode"].get() == error_code) { + if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get()) == error_code) { if (item->contains("intro")) { return wxString::FromUTF8((*item)["intro"].get()); } } } BOOST_LOG_TRIVIAL(info) << "hms: query_error_msg, not found error_code = " << error_code; + } else { + BOOST_LOG_TRIVIAL(error) << "hms: query_error_msg, do not contains lang_code = " << lang_code; + // return first language + if (!m_hms_json["device_error"].empty()) { + for (auto lang : m_hms_json["device_error"]) { + for (auto item = lang.begin(); item != lang.end(); item++) { + if (item->contains("ecode") && boost::to_upper_copy((*item)["ecode"].get()) == error_code) { + if (item->contains("intro")) { + return wxString::FromUTF8((*item)["intro"].get()); + } + } + } + } + } } } else { + BOOST_LOG_TRIVIAL(info) << "device_error is not exists"; return wxEmptyString; } return wxEmptyString; @@ -197,7 +242,8 @@ wxString HMSQuery::query_print_error_msg(int print_error) { char buf[32]; ::sprintf(buf, "%08X", print_error); - return query_error_msg(std::string(buf)); + std::string lang_code = HMSQuery::hms_language_code(); + return _query_error_msg(std::string(buf), lang_code); } int HMSQuery::check_hms_info() @@ -230,7 +276,7 @@ std::string get_hms_wiki_url(std::string error_code) if (!config) return ""; std::string hms_host = wxGetApp().app_config->get_hms_host(); - std::string lang_code = wxGetApp().app_config->get_language_code(); + std::string lang_code = HMSQuery::hms_language_code(); std::string url = (boost::format("https://%1%/index.php?e=%2%&s=device_hms&lang=%3%") % hms_host % error_code diff --git a/src/slic3r/GUI/HMS.hpp b/src/slic3r/GUI/HMS.hpp index fd45a2c3a8..e76a5938ce 100644 --- a/src/slic3r/GUI/HMS.hpp +++ b/src/slic3r/GUI/HMS.hpp @@ -24,12 +24,14 @@ protected: int load_from_local(std::string& version_info); int save_to_local(); std::string get_hms_file(); + wxString _query_hms_msg(std::string long_error_code, std::string lang_code = "en"); + wxString _query_error_msg(std::string long_error_code, std::string lang_code = "en"); public: HMSQuery() {} int check_hms_info(); wxString query_hms_msg(std::string long_error_code); - wxString query_error_msg(std::string error_code); wxString query_print_error_msg(int print_error); + static std::string hms_language_code(); }; int get_hms_info_version(std::string &version); diff --git a/src/slic3r/GUI/HMSPanel.cpp b/src/slic3r/GUI/HMSPanel.cpp index ab5ea78a67..f4946fd889 100644 --- a/src/slic3r/GUI/HMSPanel.cpp +++ b/src/slic3r/GUI/HMSPanel.cpp @@ -62,7 +62,8 @@ HMSNotifyItem::HMSNotifyItem(wxWindow *parent, HMSItem& item) this->SetSizer(main_sizer); this->Layout(); - m_hms_content->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent &e) { +#ifdef __linux__ + m_panel_hms->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& e) { e.Skip(); if (!m_url.empty()) { auto font = m_hms_content->GetFont(); @@ -72,7 +73,7 @@ HMSNotifyItem::HMSNotifyItem(wxWindow *parent, HMSItem& item) SetCursor(wxCURSOR_HAND); } }); - m_hms_content->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &e) { + m_panel_hms->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { e.Skip(); if (!m_url.empty()) { auto font = m_hms_content->GetFont(); @@ -82,9 +83,37 @@ HMSNotifyItem::HMSNotifyItem(wxWindow *parent, HMSItem& item) SetCursor(wxCURSOR_ARROW); } }); - m_hms_content->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &e) { + m_panel_hms->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { if (!m_url.empty()) wxLaunchDefaultBrowser(m_url); - }); + }); + m_hms_content->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { + if (!m_url.empty()) wxLaunchDefaultBrowser(m_url); + }); +#else + m_hms_content->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& e) { + e.Skip(); + if (!m_url.empty()) { + auto font = m_hms_content->GetFont(); + font.SetUnderlined(true); + m_hms_content->SetFont(font); + Layout(); + SetCursor(wxCURSOR_HAND); + } + }); + m_hms_content->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { + e.Skip(); + if (!m_url.empty()) { + auto font = m_hms_content->GetFont(); + font.SetUnderlined(false); + m_hms_content->SetFont(font); + Layout(); + SetCursor(wxCURSOR_ARROW); + } + }); + m_hms_content->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) { + if (!m_url.empty()) wxLaunchDefaultBrowser(m_url); + }); +#endif } HMSNotifyItem ::~HMSNotifyItem() { ; @@ -153,7 +182,8 @@ void HMSPanel::append_hms_panel(HMSItem& item) { m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL); else { // debug for hms display error info - m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL); + // m_top_sizer->Add(m_notify_item, 0, wxALIGN_CENTER_HORIZONTAL); + BOOST_LOG_TRIVIAL(info) << "hms: do not display empty_item"; } } @@ -180,6 +210,21 @@ void HMSPanel::update(MachineObject *obj) } } +void HMSPanel::show_status(int status) +{ + if (last_status == status) return; + last_status = status; + + if (((status & (int)MonitorStatus::MONITOR_DISCONNECTED) != 0) + || ((status & (int)MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0) + || ((status & (int)MonitorStatus::MONITOR_CONNECTING) != 0) + || ((status & (int)MonitorStatus::MONITOR_NO_PRINTER) != 0) + ) { + delete_hms_panels(); + Layout(); + } +} + bool HMSPanel::Show(bool show) { return wxPanel::Show(show); diff --git a/src/slic3r/GUI/HMSPanel.hpp b/src/slic3r/GUI/HMSPanel.hpp index e50e22cbed..f6fe003382 100644 --- a/src/slic3r/GUI/HMSPanel.hpp +++ b/src/slic3r/GUI/HMSPanel.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include namespace Slic3r { @@ -44,6 +45,7 @@ protected: wxScrolledWindow *m_scrolledWindow; wxBoxSizer * m_top_sizer; HMSNotifyItem * m_notify_item; + int last_status; void append_hms_panel(HMSItem &item); void delete_hms_panels(); @@ -58,6 +60,8 @@ public: void update(MachineObject *obj_); + void show_status(int status); + MachineObject *obj { nullptr }; }; diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 1a289c611f..e64c66caf1 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -839,7 +839,7 @@ void NotificationManager::HintNotification::render_text(ImGuiWrapper& imgui, con float x_offset = m_left_indentation; int last_end = 0; - float starting_y = (m_lines_count < 4 ? m_line_height / 2 * (4 - m_lines_count + 1) : m_line_height / 2); + float starting_y = (/*m_lines_count < 4 ? m_line_height / 2 * (4 - m_lines_count + 1) :*/ m_line_height / 2); float shift_y = m_line_height; std::string line; @@ -929,44 +929,32 @@ void NotificationManager::HintNotification::render_close_button(ImGuiWrapper& im ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); - std::string button_text; - button_text = ImGui::CloseNotifButton; + std::wstring button_text; + button_text = m_is_dark ? ImGui::CloseNotifDarkButton : ImGui::CloseNotifButton; - 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 - 2 * m_line_height), - true)) - { - button_text = ImGui::CloseNotifHoverButton; - } - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str()); ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); m_close_b_w = button_size.y; - if (m_lines_count <= 3) { - m_close_b_y = win_size.y / 2 - button_size.y * 1.25f; - ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); - ImGui::SetCursorPosY(m_close_b_y); - } - else { - ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); - ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y + win_size.y / 2 - button_pic_size.y), + ImVec2(win_pos.x, win_pos.y + win_size.y / 2 + button_pic_size.y), + true)) + { + button_text = m_is_dark ? ImGui::CloseNotifHoverDarkButton : ImGui::CloseNotifHoverButton; + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + close(); } + 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)) { close(); } - //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 - 2 * m_line_height)) - { - close(); - } ImGui::PopStyleColor(5); - //render_right_arrow_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + render_right_arrow_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); //render_logo(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); render_preferences_button(imgui, win_pos_x, win_pos_y); if (!m_documentation_link.empty() && wxGetApp().app_config->get("suppress_hyperlinks") != "1") @@ -978,47 +966,38 @@ void NotificationManager::HintNotification::render_close_button(ImGuiWrapper& im void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) { - + auto scale = wxGetApp().plater()->get_current_canvas3D()->get_scale(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); 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); - std::string button_text; - button_text = ImGui::PreferencesButton; + std::wstring button_text; + button_text = m_is_dark ? ImGui::PreferencesDarkButton : ImGui::PreferencesButton; //hover - if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 15.f, win_pos_y + m_window_height - 1.75f * m_line_height), + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 15.f, win_pos_y + m_window_height - 1.5f * m_line_height), ImVec2(win_pos_x, win_pos_y + m_window_height), true)) { - button_text = ImGui::PreferencesHoverButton; + button_text = m_is_dark ? ImGui::PreferencesHoverDarkButton : ImGui::PreferencesHoverButton; // tooltip - long time_now = wxGetLocalTime(); - if (m_prefe_hover_time > 0 && m_prefe_hover_time < time_now) { - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - ImGui::BeginTooltip(); - imgui.text(_u8L("Open Preferences.")); - ImGui::EndTooltip(); - ImGui::PopStyleColor(); - } - if (m_prefe_hover_time == 0) - m_prefe_hover_time = time_now; + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::PushStyleColor(ImGuiCol_Border, { 0,0,0,0 }); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 8 * scale, 1 * scale }); + ImGui::BeginTooltip(); + imgui.text(_u8L("Open Preferences.")); + ImGui::EndTooltip(); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); } - else - m_prefe_hover_time = 0; - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str()); ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); ImGui::SetCursorPosX(m_window_width - m_line_height * 1.75f); - if (m_lines_count <= 3) { - ImGui::SetCursorPosY(m_close_b_y + m_close_b_w / 4.f * 7.f); - } - else { - ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); - } + ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) { - wxGetApp().open_preferences(1, "GUI");// 1 is to modify + wxGetApp().open_preferences(); } ImGui::PopStyleColor(5); @@ -1028,7 +1007,7 @@ void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapp void NotificationManager::HintNotification::render_right_arrow_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { // Used for debuging - + auto scale = wxGetApp().plater()->get_current_canvas3D()->get_scale(); 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)); @@ -1037,17 +1016,28 @@ void NotificationManager::HintNotification::render_right_arrow_button(ImGuiWrapp 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::RightArrowButton; + std::wstring button_text; + button_text = m_is_dark ? ImGui::RightArrowDarkButton : ImGui::RightArrowButton; - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str()); ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); - + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 7.5f, win_pos_y + m_window_height - 1.5f * m_line_height), + ImVec2(win_pos_x - m_window_width / 15.f, win_pos_y + m_window_height), + true)) + { + button_text = m_is_dark ? ImGui::RightArrowHoverDarkButton : ImGui::RightArrowHoverButton; + // tooltip + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::PushStyleColor(ImGuiCol_Border, { 0,0,0,0 }); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 8 * scale, 1 * scale }); + ImGui::BeginTooltip(); + imgui.text(_u8L("Open next tip.")); + ImGui::EndTooltip(); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); + } ImGui::SetCursorPosX(m_window_width - m_line_height * 3.f); - if (m_lines_count <= 3) - ImGui::SetCursorPosY(m_close_b_y + m_close_b_w / 4.f * 7.f); - else - ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); + ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); if (imgui.button(button_text.c_str(), button_size.x * 0.8f, button_size.y * 1.f)) { retrieve_data(); @@ -1068,6 +1058,7 @@ void NotificationManager::HintNotification::render_logo(ImGuiWrapper& imgui, con } void NotificationManager::HintNotification::render_documentation_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { + auto scale = wxGetApp().plater()->get_current_canvas3D()->get_scale(); 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)); @@ -1077,32 +1068,29 @@ void NotificationManager::HintNotification::render_documentation_button(ImGuiWra ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); std::wstring button_text; - button_text = ImGui::DocumentationButton; + button_text = m_is_dark ? ImGui::DocumentationDarkButton : ImGui::DocumentationButton; std::string placeholder_text; placeholder_text = ImGui::EjectButton; - if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y), - ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y - 2 * m_line_height), - true)) - { - button_text = ImGui::DocumentationHoverButton; - // tooltip - long time_now = wxGetLocalTime(); - if (m_docu_hover_time > 0 && m_docu_hover_time < time_now) { - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - ImGui::BeginTooltip(); - imgui.text(_u8L("Open Documentation in web browser.")); - ImGui::EndTooltip(); - ImGui::PopStyleColor(); - } - if (m_docu_hover_time == 0) - m_docu_hover_time = time_now; - } - else - m_docu_hover_time = 0; - ImVec2 button_pic_size = ImGui::CalcTextSize(placeholder_text.c_str()); ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y + win_size.y / 2 - button_pic_size.y), + ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y / 2 + button_pic_size.y), + true)) + { + button_text = m_is_dark ? ImGui::DocumentationHoverDarkButton : ImGui::DocumentationHoverButton; + // tooltip + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::PushStyleColor(ImGuiCol_Border, { 0,0,0,0 }); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 8 * scale, 1 * scale }); + ImGui::BeginTooltip(); + imgui.text(_u8L("Open Documentation in web browser.")); + ImGui::EndTooltip(); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + open_documentation(); + } ImGui::SetCursorPosX(win_size.x - m_line_height * 5.0f); ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) @@ -1110,14 +1098,6 @@ void NotificationManager::HintNotification::render_documentation_button(ImGuiWra open_documentation(); } - //invisible large button - ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f); - ImGui::SetCursorPosY(0); - if (imgui.button(" ", m_line_height * 2.f, win_size.y - 2 * m_line_height)) - { - open_documentation(); - } - ImGui::PopStyleColor(5); } diff --git a/src/slic3r/GUI/HintNotification.hpp b/src/slic3r/GUI/HintNotification.hpp index b345c9f248..d0444cd8fe 100644 --- a/src/slic3r/GUI/HintNotification.hpp +++ b/src/slic3r/GUI/HintNotification.hpp @@ -88,6 +88,7 @@ protected: const float win_pos_x, const float win_pos_y) override; virtual void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override {} + void render_preferences_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y); void render_right_arrow_button(ImGuiWrapper& imgui, diff --git a/src/slic3r/GUI/IMSlider.cpp b/src/slic3r/GUI/IMSlider.cpp index 12a1ee18d5..63f270e026 100644 --- a/src/slic3r/GUI/IMSlider.cpp +++ b/src/slic3r/GUI/IMSlider.cpp @@ -12,16 +12,6 @@ #include "Tab.hpp" #include "GUI_ObjectList.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -49,6 +39,7 @@ constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 static const float LEFT_MARGIN = 13.0f + 100.0f; // avoid thumbnail toolbar static const float SLIDER_LENGTH = 680.0f; static const float TEXT_WIDTH_DUMMY = 63.0f; +static const float ONE_LAYER_MARGIN = 10.0f; static const ImVec2 ONE_LAYER_OFFSET = ImVec2(41.0f, 44.0f); static const ImVec2 HORIZONTAL_SLIDER_SIZE = ImVec2(764.0f, 90.0f);//764 = 680 + handle_dummy_width * 2 + text_right_dummy static const ImVec2 VERTICAL_SLIDER_SIZE = ImVec2(105.0f, 748.0f);//748 = 680 + text_dummy_height * 2 @@ -440,7 +431,7 @@ IMSlider::IMSlider(int lowerValue, int higherValue, int minValue, int maxValue, m_style = style == wxSL_HORIZONTAL || style == wxSL_VERTICAL ? style : wxSL_HORIZONTAL; // BBS set to none style by default m_extra_style = style == wxSL_VERTICAL ? 0 : 0; - m_selection = ssUndef; + m_selection = ssHigher; m_is_need_post_tick_changed_event = false; m_tick_change_event_type = Type::Unknown; @@ -452,13 +443,14 @@ bool IMSlider::init_texture() bool result = true; if (!is_horizontal()) { // BBS init image texture id - result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/reset_normal.svg", 20, 20, m_reset_normal_id); - result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/reset_hover.svg", 20, 20, m_reset_hover_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_on.svg", 24, 24, m_one_layer_on_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_on_hover.svg", 28, 28, m_one_layer_on_hover_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off.svg", 28, 28, m_one_layer_off_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off_hover.svg", 28, 28, m_one_layer_off_hover_id); - result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_arrow.svg", 28, 28, m_one_layer_arrow_id); + result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_on_dark.svg", 24, 24, m_one_layer_on_dark_id); + result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_on_hover_dark.svg", 28, 28, m_one_layer_on_hover_dark_id); + result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off_dark.svg", 28, 28, m_one_layer_off_dark_id); + result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/one_layer_off_hover_dark.svg", 28, 28, m_one_layer_off_hover_dark_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_gcode_pause.svg", 14, 14, m_pause_icon_id); result &= IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/im_slider_delete.svg", 14, 14, m_delete_icon_id); } @@ -722,8 +714,8 @@ bool IMSlider::switch_one_layer_mode() } void IMSlider::draw_background(const ImRect& groove) { - const ImU32 bg_rect_col = IM_COL32(255, 255, 255, 255); - const ImU32 groove_col = IM_COL32(206, 206, 206, 255); + const ImU32 bg_rect_col = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(255, 255, 255, 255); + const ImU32 groove_col = m_is_dark ? IM_COL32(45, 45, 49, 255) : IM_COL32(206, 206, 206, 255); if (is_horizontal() || m_ticks.empty()) { ImVec2 groove_padding = ImVec2(2.0f, 2.0f) * m_scale; @@ -772,9 +764,9 @@ bool IMSlider::horizontal_slider(const char* str_id, int* value, int v_min, int float triangle_offsets[3] = {-3.5f * m_scale, 3.5f * m_scale, -6.06f * m_scale}; - const ImU32 white_bg = IM_COL32(255, 255, 255, 255); + const ImU32 white_bg = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(255, 255, 255, 255); const ImU32 handle_clr = IM_COL32(0, 174, 66, 255); - const ImU32 handle_border_clr = IM_COL32(248, 248, 248, 255); + const ImU32 handle_border_clr = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(248, 248, 248, 255); // calc groove size ImVec2 groove_start = ImVec2(pos.x + handle_dummy_width, pos.y + size.y - groove_y - bottom_dummy); @@ -835,7 +827,7 @@ void IMSlider::draw_colored_band(const ImRect& groove, const ImRect& slideable_r if (m_ticks.empty()) return; - const ImU32 blank_col = IM_COL32(255, 255, 255, 255); + const ImU32 blank_col = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(255, 255, 255, 255); ImVec2 blank_padding = ImVec2(6.0f, 5.0f) * m_scale; float blank_width = 1.0f * m_scale; @@ -908,8 +900,7 @@ void IMSlider::draw_ticks(const ImRect& slideable_region) { ImVec2 icon_size = ImVec2(14.0f, 14.0f) * m_scale; const ImU32 tick_clr = IM_COL32(144, 144, 144, 255); - const ImU32 tick_hover_box_clr = IM_COL32(219, 253, 231, 255); - const ImU32 delete_btn_clr = IM_COL32(144, 144, 144, 255); + const ImU32 tick_hover_box_clr = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(219, 253, 231, 255); auto get_tick_pos = [this, slideable_region](int tick) { @@ -1010,10 +1001,9 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower ImVec2 text_content_size; ImVec2 text_size; - const ImU32 white_bg = IM_COL32(255, 255, 255, 255); + const ImU32 white_bg = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(255, 255, 255, 255); const ImU32 handle_clr = IM_COL32(0, 174, 66, 255); - const ImU32 handle_border_clr = IM_COL32(248, 248, 248, 255); - const ImU32 delete_btn_clr = IM_COL32(144, 144, 144, 255); + const ImU32 handle_border_clr = m_is_dark ? IM_COL32(65, 65, 71, 255) : IM_COL32(248, 248, 248, 255); // calc slider groove size ImVec2 groove_start = ImVec2(pos.x + size.x - groove_x - right_dummy, pos.y + text_dummy_height); @@ -1055,7 +1045,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower if (!one_layer_flag) { // select higher handle by default - static bool h_selected = true; + bool h_selected = (selection == ssHigher); if (ImGui::ItemHoverable(higher_handle, id) && context.IO.MouseClicked[0]) { selection = ssHigher; h_selected = true; @@ -1223,6 +1213,8 @@ bool IMSlider::render(int canvas_width, int canvas_height) render_input_custom_gcode(); + render_go_to_layer_dialog(); + if (is_horizontal()) { float pos_x = std::max(LEFT_MARGIN, 0.2f * canvas_width); float pos_y = (canvas_height - HORIZONTAL_SLIDER_SIZE.y * m_scale); @@ -1236,9 +1228,9 @@ bool IMSlider::render(int canvas_width, int canvas_height) } imgui.end(); } else { - float pos_x = canvas_width - (VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY) * m_scale; + float pos_x = canvas_width - (VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY + ONE_LAYER_MARGIN) * m_scale; float pos_y = std::max(ONE_LAYER_OFFSET.y, 0.15f * canvas_height - (VERTICAL_SLIDER_SIZE.y - SLIDER_LENGTH) * scale); - ImVec2 size = ImVec2((VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY) * m_scale, canvas_height - 2 * pos_y); + ImVec2 size = ImVec2((VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY + ONE_LAYER_MARGIN) * m_scale, canvas_height - 2 * pos_y); imgui.set_next_window_pos(pos_x, pos_y, ImGuiCond_Always); imgui.begin(std::string("laysers_slider"), windows_flag); @@ -1261,8 +1253,12 @@ bool IMSlider::render(int canvas_width, int canvas_height) ImGui::Spacing(); ImGui::SameLine((VERTICAL_SLIDER_SIZE.x - ONE_LAYER_OFFSET.x) * scale * m_scale); - ImTextureID normal_id = is_one_layer() ? m_one_layer_on_id : m_one_layer_off_id; - ImTextureID hover_id = is_one_layer() ? m_one_layer_on_hover_id : m_one_layer_off_hover_id; + ImTextureID normal_id = m_is_dark ? + is_one_layer() ? m_one_layer_on_dark_id : m_one_layer_off_dark_id : + is_one_layer() ? m_one_layer_on_id : m_one_layer_off_id; + ImTextureID hover_id = m_is_dark ? + is_one_layer() ? m_one_layer_on_hover_dark_id : m_one_layer_off_hover_dark_id : + is_one_layer() ? m_one_layer_on_hover_id : m_one_layer_off_hover_id; if (ImGui::ImageButton3(normal_id, hover_id, ImVec2(28 * m_scale, 28 * m_scale))) { switch_one_layer_mode(); } @@ -1282,11 +1278,12 @@ void IMSlider::render_input_custom_gcode() return; ImGuiWrapper& imgui = *wxGetApp().imgui(); static bool move_to_center = true; + static bool set_focus = true; if (move_to_center) { - move_to_center = false; auto pos_x = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_width() / 2; auto pos_y = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_height() / 2; imgui.set_next_window_pos(pos_x, pos_y, ImGuiCond_Always, 0.5f, 0.5f); + move_to_center = false; } imgui.push_common_window_style(m_scale); @@ -1301,6 +1298,12 @@ void IMSlider::render_input_custom_gcode() | ImGuiWindowFlags_NoScrollWithMouse; imgui.begin(_u8L("Custom G-code"), windows_flag); imgui.text(_u8L("Enter Custom G-code used on current layer:")); + if (ImGui::IsMouseClicked(0)) { + set_focus = false; + } + if (set_focus && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)) { + ImGui::SetKeyboardFocusHere(0); + } int text_height = 6; ImGui::InputTextMultiline("##text", m_custom_gcode, sizeof(m_custom_gcode), ImVec2(-1, ImGui::GetTextLineHeight() * text_height)); //text_height = 5; @@ -1311,29 +1314,104 @@ void IMSlider::render_input_custom_gcode() ImGui::NewLine(); ImGui::SameLine(ImGui::GetStyle().WindowPadding.x * 14); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f / 255.f, 174.f / 255.f, 66.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(61.f / 255.f, 203.f / 255.f, 115.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(27.f / 255.f, 136.f / 255.f, 68.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.f, 1.f, 1.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); - if (imgui.bbl_button(_L("OK"))) { + imgui.push_confirm_button_style(); + if (imgui.bbl_button(_L("OK")) || ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Enter))) { m_show_custom_gcode_window = false; add_custom_gcode(m_custom_gcode); move_to_center = true; + set_focus = true; } - ImGui::PopStyleColor(5); + imgui.pop_confirm_button_style(); ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(255.f / 255.f, 255.f / 255.f, 255.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(238.f / 255.f, 238.f / 255.f, 238.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(206.f / 255.f, 206.f / 255.f, 206.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 0.f, 0.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(38.f / 255.0f, 46.f / 255.0f, 48.f / 255.0f, 1.00f)); - if (imgui.bbl_button(_L("Cancel"))) { + imgui.push_cancel_button_style(); + if (imgui.bbl_button(_L("Cancel")) || ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) { m_show_custom_gcode_window = false; move_to_center = true; + set_focus = true; } - ImGui::PopStyleColor(5); + imgui.pop_cancel_button_style(); + + imgui.end(); + ImGui::PopStyleVar(3); + imgui.pop_common_window_style(); +} + +void IMSlider::do_go_to_layer(size_t layer_number) { + clamp((int)layer_number, m_min_value, m_max_value); + GetSelection() == ssLower ? SetLowerValue(layer_number) : SetHigherValue(layer_number); +} + +void IMSlider::render_go_to_layer_dialog(){ + if (!m_show_go_to_layer_dialog) + return; + ImGuiWrapper& imgui = *wxGetApp().imgui(); + static bool move_to_center = true; + static bool set_focus = true; + if (move_to_center) { + auto pos_x = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_width() / 2; + auto pos_y = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_height() / 2; + imgui.set_next_window_pos(pos_x, pos_y, ImGuiCond_Always, 0.5f, 0.5f); + move_to_center = false; + } + + imgui.push_common_window_style(m_scale); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.f * m_scale); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 3) * m_scale); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 7) * m_scale); + int windows_flag = + ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_AlwaysAutoResize + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoScrollWithMouse; + imgui.begin(_u8L("Jump to layer"), windows_flag); + imgui.text(_u8L("Please enter the layer number") + " (" + std::to_string(m_min_value + 1) + " - " + std::to_string(m_max_value + 1) + "):"); + if (ImGui::IsMouseClicked(0)) { + set_focus = false; + } + if (set_focus && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)) { + ImGui::SetKeyboardFocusHere(0); + } + ImGui::InputText("##input_layer_number", m_layer_number, sizeof(m_layer_number)); + + ImGui::NewLine(); + ImGui::SameLine(GImGui->Style.WindowPadding.x * 8); + imgui.push_confirm_button_style(); + bool disable_button = false; + if (strlen(m_layer_number) == 0) + disable_button = true; + else { + for (size_t i = 0; i< strlen(m_layer_number); i++) + if (!isdigit(m_layer_number[i])) + disable_button = true; + if (!disable_button && (m_min_value > atoi(m_layer_number) - 1 || atoi(m_layer_number) - 1 > m_max_value)) + disable_button = true; + } + if (disable_button) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + imgui.push_button_disable_style(); + } + if (imgui.bbl_button(_L("OK")) || (!disable_button && ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Enter)))) { + do_go_to_layer(atoi(m_layer_number) - 1); + m_show_go_to_layer_dialog = false; + move_to_center = true; + set_focus = true; + } + if (disable_button) { + ImGui::PopItemFlag(); + imgui.pop_button_disable_style(); + } + imgui.pop_confirm_button_style(); + + ImGui::SameLine(); + imgui.push_cancel_button_style(); + if (imgui.bbl_button(_L("Cancel")) || ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) { + m_show_go_to_layer_dialog = false; + move_to_center = true; + set_focus = true; + } + imgui.pop_cancel_button_style(); imgui.end(); ImGui::PopStyleVar(3); @@ -1354,8 +1432,11 @@ void IMSlider::render_menu() if (ImGui::BeginPopup("slider_menu_popup")) { if ((m_selection == ssLower && GetLowerValueD() == m_zero_layer_height) || (m_selection == ssHigher && GetHigherValueD() == m_zero_layer_height)) { - menu_item_with_icon(_u8L("Add Pause").c_str(), "", ImVec2(0, 0), 0, false, false); - }else + if (menu_item_with_icon(_u8L("Jump to Layer").c_str(), "")) { + m_show_go_to_layer_dialog = true; + } + } + else { if (menu_item_with_icon(_u8L("Add Pause").c_str(), "")) { add_code_as_tick(PausePrint); @@ -1368,6 +1449,9 @@ void IMSlider::render_menu() add_code_as_tick(Template); } } + if (menu_item_with_icon(_u8L("Jump to Layer").c_str(), "")) { + m_show_go_to_layer_dialog = true; + } } //BBS render this menu item only when extruder_num > 1 @@ -1391,11 +1475,67 @@ void IMSlider::render_menu() ImGuiWrapper::pop_menu_style(); } +void IMSlider::on_change_color_mode(bool is_dark) { + m_is_dark = is_dark; +} + void IMSlider::set_scale(float scale) { if(m_scale != scale) m_scale = scale; } +void IMSlider::on_mouse_wheel(wxMouseEvent& evt) { + auto moves_slider_window = ImGui::FindWindowByName("moves_slider"); + auto layers_slider_window = ImGui::FindWindowByName("laysers_slider"); + if (!moves_slider_window || !layers_slider_window) { + BOOST_LOG_TRIVIAL(info) << "Couldn't find slider window"; + return; + } + + float wheel = 0.0f; + wheel = evt.GetWheelRotation() > 0 ? 1.0f : -1.0f; + if (wheel == 0.0f) + return; + +#ifdef __WXOSX__ + if (wxGetKeyState(WXK_SHIFT)) { + wheel *= -5; + } + else if (wxGetKeyState(WXK_RAW_CONTROL)) { + wheel *= 5; + } +#else + if (wxGetKeyState(WXK_COMMAND) || wxGetKeyState(WXK_SHIFT)) + wheel *= 5; +#endif + if (is_horizontal()) { + if( evt.GetPosition().x > moves_slider_window->Pos.x && + evt.GetPosition().x < moves_slider_window->Pos.x + moves_slider_window->Size.x && + evt.GetPosition().y > moves_slider_window->Pos.y && + evt.GetPosition().y < moves_slider_window->Pos.y + moves_slider_window->Size.y){ + const int new_pos = GetHigherValue() + wheel; + SetHigherValue(new_pos); + set_as_dirty(); + } + } + else { + if (evt.GetPosition().x > layers_slider_window->Pos.x && + evt.GetPosition().x < layers_slider_window->Pos.x + layers_slider_window->Size.x && + evt.GetPosition().y > layers_slider_window->Pos.y && + evt.GetPosition().y < layers_slider_window->Pos.y + layers_slider_window->Size.y) { + if (is_one_layer()) { + const int new_pos = GetHigherValue() + wheel; + SetHigherValue(new_pos); + } + else { + const int new_pos = m_selection == ssLower ? GetLowerValue() + wheel : GetHigherValue() + wheel; + m_selection == ssLower ? SetLowerValue(new_pos) : SetHigherValue(new_pos); + } + set_as_dirty(); + } + } +} + void IMSlider::correct_lower_value() { if (m_lower_value < m_min_value) diff --git a/src/slic3r/GUI/IMSlider.hpp b/src/slic3r/GUI/IMSlider.hpp index 5b6e7ce983..73b36c43cb 100644 --- a/src/slic3r/GUI/IMSlider.hpp +++ b/src/slic3r/GUI/IMSlider.hpp @@ -261,18 +261,14 @@ public: void UseDefaultColors(bool def_colors_on) { m_ticks.set_default_colors(def_colors_on); } - void add_custom_gcode(std::string custom_gcode); - void add_code_as_tick(Type type, int selected_extruder = -1); + void on_mouse_wheel(wxMouseEvent& evt); void post_ticks_changed_event(Type type = Custom); bool check_ticks_changed_event(Type type); bool switch_one_layer_mode(); + void show_go_to_layer(bool show) { m_show_go_to_layer_dialog = show; } bool render(int canvas_width, int canvas_height); - void render_menu(); - - void render_input_custom_gcode(); - //BBS update scroll value changed bool is_dirty() { return m_dirty; } void set_as_dirty(bool dirty = true) { m_dirty = dirty; } @@ -286,10 +282,18 @@ public: ExtrudersSequence m_extruders_sequence; float m_scale = 1.0; void set_scale(float scale = 1.0); + void on_change_color_mode(bool is_dark); + protected: + void add_custom_gcode(std::string custom_gcode); + void add_code_as_tick(Type type, int selected_extruder = -1); + void do_go_to_layer(size_t layer_number); void correct_lower_value(); void correct_higher_value(); bool horizontal_slider(const char* str_id, int* v, int v_min, int v_max, const ImVec2& pos, const ImVec2& size, float scale = 1.0); + void render_go_to_layer_dialog(); + void render_input_custom_gcode(); + void render_menu(); void draw_background(const ImRect& groove); void draw_colored_band(const ImRect& groove, const ImRect& slideable_region); void draw_ticks(const ImRect& slideable_region); @@ -305,8 +309,6 @@ private: int get_tick_from_value(double value, bool force_lower_bound = false); float get_pos_from_value(int v_min, int v_max, int value, const ImRect& rect); - - std::string get_color_for_tool_change_tick(std::set::const_iterator it) const; // Get active extruders for tick. // Means one current extruder for not existing tick OR @@ -315,6 +317,8 @@ private: std::array get_active_extruders_for_tick(int tick) const; // Use those values to disable selection of active extruders + bool m_is_dark = false; + bool is_osx{false}; int m_min_value; int m_max_value; @@ -331,6 +335,7 @@ private: bool m_is_focused = false; bool m_show_menu = false; bool m_show_custom_gcode_window = false; + bool m_show_go_to_layer_dialog = false; bool m_force_mode_apply = true; bool m_enable_action_icon = true; bool m_enable_cog_icon = false; @@ -340,13 +345,18 @@ private: int m_selected_tick_value = -1; /* BBS slider images */ - void *m_reset_normal_id; - void *m_reset_hover_id; void *m_one_layer_on_id; void *m_one_layer_on_hover_id; - void *m_one_layer_arrow_id; void *m_one_layer_off_id; void *m_one_layer_off_hover_id; + void* m_one_layer_on_light_id; + void* m_one_layer_on_hover_light_id; + void* m_one_layer_off_light_id; + void* m_one_layer_off_hover_light_id; + void* m_one_layer_on_dark_id; + void* m_one_layer_on_hover_dark_id; + void* m_one_layer_off_dark_id; + void* m_one_layer_off_hover_dark_id; void *m_pause_icon_id; void *m_delete_icon_id; @@ -373,6 +383,7 @@ private: std::vector m_alternate_values; char m_custom_gcode[1024] = { 0 }; + char m_layer_number[64] = { 0 }; }; } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 77503e14ed..fe4d57fcec 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -27,6 +27,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" +#include "libslic3r/Shape/TextShape.hpp" #include "3DScene.hpp" #include "GUI.hpp" #include "I18N.hpp" @@ -37,6 +38,7 @@ #include "nanosvg/nanosvg.h" #include "nanosvg/nanosvgrast.h" #include "OpenGLManager.hpp" +#include "GUI_App.hpp" namespace Slic3r { namespace GUI { @@ -65,6 +67,20 @@ static const std::map font_icons = { {ImGui::FoldButtonIcon , "im_fold" }, {ImGui::UnfoldButtonIcon , "im_unfold" }, {ImGui::SphereButtonIcon , "toolbar_modifier_sphere" }, + // dark mode icon + {ImGui::MinimalizeDarkButton , "notification_minimalize_dark" }, + {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::CircleButtonDarkIcon , "circle_paint_dark" }, + {ImGui::TriangleButtonDarkIcon , "triangle_paint_dark" }, + {ImGui::FillButtonDarkIcon , "fill_paint_dark" }, + {ImGui::HeightRangeDarkIcon , "height_range_dark" }, + {ImGui::GapFillDarkIcon , "gap_fill_dark" }, + {ImGui::SphereButtonDarkIcon , "toolbar_modifier_sphere_dark" }, }; static const std::map font_icons_large = { @@ -86,6 +102,11 @@ static const std::map font_icons_large = { {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"}, }; static const std::map font_icons_extra_large = { @@ -108,9 +129,11 @@ const ImVec4 ImGuiWrapper::COL_BLUE_LIGHT = ImVec4(0.122f, 0.557f, 0.918f const ImVec4 ImGuiWrapper::COL_GREEN_LIGHT = ImVec4(0.86f, 0.99f, 0.91f, 1.0f); const ImVec4 ImGuiWrapper::COL_HOVER = { 0.933f, 0.933f, 0.933f, 1.0f }; const ImVec4 ImGuiWrapper::COL_ACTIVE = { 0.675f, 0.675f, 0.675f, 1.0f }; -const ImVec4 ImGuiWrapper::COL_SEPARATOR = { 0.93f, 0.93f, 0.93f,1.0f }; +const ImVec4 ImGuiWrapper::COL_SEPARATOR = { 0.93f, 0.93f, 0.93f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_SEPARATOR_DARK = { 0.24f, 0.24f, 0.27f, 1.0f }; const ImVec4 ImGuiWrapper::COL_TITLE_BG = { 0.745f, 0.745f, 0.745f, 1.0f }; -const ImVec4 ImGuiWrapper::COL_WINDOW_BG = { 1.000f, 1.000f, 1.000f, 0.95f }; +const ImVec4 ImGuiWrapper::COL_WINDOW_BG = { 1.000f, 1.000f, 1.000f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_WINDOW_BG_DARK = { 45 / 255.f, 45 / 255.f, 49 / 255.f, 1.f }; int ImGuiWrapper::TOOLBAR_WINDOW_FLAGS = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove @@ -118,7 +141,6 @@ int ImGuiWrapper::TOOLBAR_WINDOW_FLAGS = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar; -static float accer = 1.f; bool get_data_from_svg(const std::string &filename, unsigned int max_size_px, ThumbnailData &thumbnail_data) { @@ -189,15 +211,7 @@ bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const // Process interacting with the slider ImS32 v_new = *out_value; bool value_changed = false; - // wheel behavior - ImRect mouse_wheel_responsive_region; - if (axis == ImGuiAxis_X) - mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(handle_sz.x / 2, 0), region.Max + ImVec2(handle_sz.x / 2, 0)); - if (axis == ImGuiAxis_Y) - mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(0, handle_sz.y), region.Max + ImVec2(0, handle_sz.y)); - if (ImGui::ItemHoverable(mouse_wheel_responsive_region, id)) { - v_new = ImClamp(*out_value + (ImS32)(context.IO.MouseWheel * accer), v_min, v_max); - } + // drag behavior if (context.ActiveId == id) { @@ -290,6 +304,7 @@ ImGuiWrapper::ImGuiWrapper() ImGuiWrapper::~ImGuiWrapper() { + //destroy_fonts_texture(); destroy_font(); ImGui::DestroyContext(); } @@ -353,18 +368,25 @@ void ImGuiWrapper::set_language(const std::string &language) ImGui::GetIO().Fonts->GetGlyphRangesChineseFull() : // Simplified Chinese // Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese - ImGui::GetIO().Fonts->GetGlyphRangesChineseFull(); + ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon(); m_font_cjk = true; } else if (lang == "th") { ranges = ImGui::GetIO().Fonts->GetGlyphRangesThai(); // Default + Thai characters - } else { - ranges = ImGui::GetIO().Fonts->GetGlyphRangesDefault(); // Basic Latin, Extended Latin + } + else if (lang == "en") { + ranges = ImGui::GetIO().Fonts->GetGlyphRangesEnglish(); // Basic Latin + } + else{ + ranges = ImGui::GetIO().Fonts->GetGlyphRangesOthers(); } if (ranges != m_glyph_ranges) { m_glyph_ranges = ranges; + //destroy_fonts_texture(); destroy_font(); } + + m_glyph_basic_ranges = ImGui::GetIO().Fonts->GetGlyphRangesBasic(); } void ImGuiWrapper::set_display_size(float w, float h) @@ -388,6 +410,7 @@ void ImGuiWrapper::set_scaling(float font_size, float scale_style, float scale_b ImGui::GetStyle().ScaleAllSizes(scale_style / m_style_scaling); m_style_scaling = scale_style; + //destroy_fonts_texture(); destroy_font(); } @@ -422,19 +445,6 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) ImGuiIO& io = ImGui::GetIO(); - if (evt.CmdDown()) { - accer = 5.f; - } - else if (evt.ShiftDown()) { -#ifdef __APPLE__ - accer = -5.f; -#else - accer = 5.f; -#endif - } - else - accer = 1.f; - if (evt.GetEventType() == wxEVT_CHAR) { // Char event const auto key = evt.GetUnicodeKey(); @@ -1537,6 +1547,31 @@ void ImGuiWrapper::bold_text(const std::string& str) } } +bool ImGuiWrapper::push_font_by_name(std::string font_name) +{ + auto sys_font = im_fonts_map.find(font_name); + if (sys_font != im_fonts_map.end()) { + ImFont* font = sys_font->second; + if (font && font->ContainerAtlas && font->Glyphs.Size > 4) + ImGui::PushFont(font); + else { + ImGui::PushFont(default_font); + } + return true; + } + return false; +} + +bool ImGuiWrapper::pop_font_by_name(std::string font_name) +{ + auto sys_font = im_fonts_map.find(font_name); + if (sys_font != im_fonts_map.end()) { + ImGui::PopFont(); + return true; + } + return false; +} + void ImGuiWrapper::title(const std::string& str) { if (bold_font){ @@ -1635,50 +1670,95 @@ std::vector ImGuiWrapper::load_svg(const std::string& bitmap_name return data; } - //BBS +static bool m_is_dark_mode = false; + +void ImGuiWrapper::on_change_color_mode(bool is_dark) +{ + m_is_dark_mode = is_dark; +} + void ImGuiWrapper::push_toolbar_style(const float scale) { - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f) * scale); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(50/255.0f, 58/255.0f, 61/255.0f, 1.00f)); // 1 - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGuiWrapper::COL_WINDOW_BG); // 2 - ImGui::PushStyleColor(ImGuiCol_TitleBg, ImGuiWrapper::COL_TITLE_BG); // 3 - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImGuiWrapper::COL_TITLE_BG); // 4 - ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR); // 5 - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 6 - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiWrapper::COL_HOVER); // 7 - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 8 - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238/255.0f, 238/255.0f, 238/255.0f, 1.00f)); // 9 - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238/255.0f, 238/255.0f, 238/255.0f, 0.00f)); // 10 - ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 11 - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//12 - 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)); + if (m_is_dark_mode) { + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f) * scale); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 0.88f)); // 1 + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGuiWrapper::COL_WINDOW_BG_DARK); // 2 + ImGui::PushStyleColor(ImGuiCol_TitleBg, ImGuiWrapper::COL_TITLE_BG); // 3 + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImGuiWrapper::COL_TITLE_BG); // 4 + ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR_DARK); // 5 + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(62 / 255.0f, 62 / 255.0f, 69 / 255.0f, 1.00f)); // 6 + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(73 / 255.0f, 73 / 255.0f, 78 / 255.0f, 1.00f)); // 7 + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(73 / 255.0f, 73 / 255.0f, 78 / 255.0f, 1.00f)); // 8 + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(84 / 255.0f, 84 / 255.0f, 90 / 255.0f, 1.00f)); // 9 + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(62 / 255.0f, 62 / 255.0f, 69 / 255.0f, 1.00f)); // 10 + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f)); // 12 + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 13 + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f)); // 14 + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); // 15 + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); // 16 + } + else { + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f) * scale); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(50 / 255.0f, 58 / 255.0f, 61 / 255.0f, 1.00f)); // 1 + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGuiWrapper::COL_WINDOW_BG); // 2 + ImGui::PushStyleColor(ImGuiCol_TitleBg, ImGuiWrapper::COL_TITLE_BG); // 3 + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImGuiWrapper::COL_TITLE_BG); // 4 + ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR); // 5 + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 6 + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGuiWrapper::COL_HOVER); // 7 + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 8 + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(172 / 255.0f, 172 / 255.0f, 172 / 255.0f, 1.00f)); // 9 + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10 + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 12 + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//13 + 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 ImGuiWrapper::pop_toolbar_style() { // size in push toolbar style - ImGui::PopStyleColor(15); + ImGui::PopStyleColor(16); ImGui::PopStyleVar(6); } void ImGuiWrapper::push_menu_style(const float scale) { - ImGuiWrapper::push_toolbar_style(scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * scale); - ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f); - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG); - ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + if (m_is_dark_mode) { + ImGuiWrapper::push_toolbar_style(scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG_DARK); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + } + else { + ImGuiWrapper::push_toolbar_style(scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + } } void ImGuiWrapper::pop_menu_style() { @@ -1688,25 +1768,48 @@ void ImGuiWrapper::pop_menu_style() } void ImGuiWrapper::push_common_window_style(const float scale) { - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowTitleAlign, ImVec2(0.05f, 0.50f) * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(38 / 255.0f, 46 / 255.0f, 48 / 255.0f, 1.00f)); // 1 - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGuiWrapper::COL_WINDOW_BG); // 2 - ImGui::PushStyleColor(ImGuiCol_TitleBg, ImGuiWrapper::COL_TITLE_BG); // 3 - ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImGuiWrapper::COL_TITLE_BG); // 4 - ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR); // 5 - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 6 - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 7 - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 8 - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 9 - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10 - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 12 - ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, ImGuiWrapper::COL_GREEN_LIGHT); // 13 - ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 14 + if (m_is_dark_mode) { + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowTitleAlign, ImVec2(0.05f, 0.50f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 0.88f)); // 1 + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGuiWrapper::COL_WINDOW_BG_DARK); // 2 + ImGui::PushStyleColor(ImGuiCol_TitleBg, ImVec4(54 / 255.0f, 54 / 255.0f, 60 / 255.0f, 1.00f)); // 3 + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImVec4(54 / 255.0f, 54 / 255.0f, 60 / 255.0f, 1.00f)); // 4 + ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR_DARK); // 5 + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 6 + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 7 + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 8 + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(84 / 255.0f, 84 / 255.0f, 90 / 255.0f, 1.00f)); // 9 + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(62 / 255.0f, 62 / 255.0f, 69 / 255.0f, 1.00f)); // 10 + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 12 + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f)); // 13 + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 14 + } + else { + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0f, 10.0f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowTitleAlign, ImVec2(0.05f, 0.50f) * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f * scale); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(38 / 255.0f, 46 / 255.0f, 48 / 255.0f, 1.00f)); // 1 + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 2 + ImGui::PushStyleColor(ImGuiCol_TitleBg, ImVec4(245 / 255.0f, 245 / 255.0f, 245 / 255.0f, 1.00f)); // 3 + ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImVec4(245 / 255.0f, 245 / 255.0f, 245 / 255.0f, 1.00f)); // 4 + ImGui::PushStyleColor(ImGuiCol_Separator, ImGuiWrapper::COL_SEPARATOR); // 5 + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 6 + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 7 + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 8 + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 9 + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10 + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11 + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f)); // 12 + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, ImGuiWrapper::COL_GREEN_LIGHT); // 13 + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); // 14 + } } void ImGuiWrapper::pop_common_window_style() { @@ -1714,6 +1817,69 @@ void ImGuiWrapper::pop_common_window_style() { ImGui::PopStyleVar(5); } +void ImGuiWrapper::push_confirm_button_style() { + if (m_is_dark_mode) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f / 255.f, 174.f / 255.f, 66.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f / 255.f, 174.f / 255.f, 66.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(61.f / 255.f, 203.f / 255.f, 115.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(27.f / 255.f, 136.f / 255.f, 68.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.f, 1.f, 1.f, 0.88f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 0.88f)); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f / 255.f, 174.f / 255.f, 66.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f / 255.f, 174.f / 255.f, 66.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(61.f / 255.f, 203.f / 255.f, 115.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(27.f / 255.f, 136.f / 255.f, 68.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.f, 1.f, 1.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); + } +} + +void ImGuiWrapper::pop_confirm_button_style() { + ImGui::PopStyleColor(6); +} + +void ImGuiWrapper::push_cancel_button_style() { + if (m_is_dark_mode) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.f, 0.f, 0.f, 0.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.f, 1.f, 1.f, 0.64f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(73 / 255.f, 73 / 255.f, 78 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(129 / 255.f, 129 / 255.f, 131 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.f, 1.f, 1.f, 0.64f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 0.64f)); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(38 / 255.f, 46 / 255.f, 48 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(238.f / 255.f, 238.f / 255.f, 238.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(206.f / 255.f, 206.f / 255.f, 206.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 0.f, 0.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(38.f / 255.0f, 46.f / 255.0f, 48.f / 255.0f, 1.00f)); + } +} + +void ImGuiWrapper::pop_cancel_button_style() { + ImGui::PopStyleColor(6); +} + +void ImGuiWrapper::push_button_disable_style() { + if (m_is_dark_mode) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(54 / 255.f, 54 / 255.f, 60 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(54 / 255.f, 54 / 255.f, 60 / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 0.4f)); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(206.f / 255.f, 206.f / 255.f, 206.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(206.f / 255.f, 206.f / 255.f, 206.f / 255.f, 1.f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f)); + } +} + +void ImGuiWrapper::pop_button_disable_style() { + ImGui::PopStyleColor(3); +} + void ImGuiWrapper::init_font(bool compress) { destroy_font(); @@ -1723,6 +1889,7 @@ void ImGuiWrapper::init_font(bool compress) // Create ranges of characters from m_glyph_ranges, possibly adding some OS specific special characters. ImVector ranges; + ImVector basic_ranges; ImFontAtlas::GlyphRangesBuilder builder; builder.AddRanges(m_glyph_ranges); #ifdef __APPLE__ @@ -1737,15 +1904,15 @@ void ImGuiWrapper::init_font(bool compress) cfg.OversampleH = cfg.OversampleV = 1; //FIXME replace with io.Fonts->AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, m_font_size, nullptr, ranges.Data); //https://github.com/ocornut/imgui/issues/220 - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf").c_str(), m_font_size, &cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - if (font == nullptr) { - font = io.Fonts->AddFontDefault(); - if (font == nullptr) { + default_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Regular.ttf").c_str(), m_font_size, &cfg, ImGui::GetIO().Fonts->GetGlyphRangesChineseFull()); + if (default_font == nullptr) { + default_font = io.Fonts->AddFontDefault(); + if (default_font == nullptr) { throw Slic3r::RuntimeError("ImGui: Could not load deafult font"); } } - bold_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Bold.ttf").c_str(), m_font_size, &cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + bold_font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/" + "HarmonyOS_Sans_SC_Bold.ttf").c_str(), m_font_size, &cfg, ranges.Data); if (bold_font == nullptr) { bold_font = io.Fonts->AddFontDefault(); if (bold_font == nullptr) { throw Slic3r::RuntimeError("ImGui: Could not load deafult font"); } @@ -1767,16 +1934,17 @@ void ImGuiWrapper::init_font(bool compress) int rect_id = io.Fonts->CustomRects.Size; // id of the rectangle added next // add rectangles for the icons to the font atlas for (auto& icon : font_icons) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); for (auto& icon : font_icons_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); for (auto& icon : font_icons_extra_large) - io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); + io.Fonts->AddCustomRectFontGlyph(default_font, icon.first, icon_sz * 4, icon_sz * 4, 3.0 * font_scale + icon_sz * 4); // Build texture atlas unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. + BOOST_LOG_TRIVIAL(trace) << "Build default font texture done. width: " << width << ", height: " << height; // Fill rectangles from the SVG-icons for (auto icon : font_icons) { @@ -1846,6 +2014,66 @@ void ImGuiWrapper::init_font(bool compress) glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture)); } +void ImGuiWrapper::load_fonts_texture() +{ + //if (m_font_another_texture == 0) { + // ImGuiIO& io = ImGui::GetIO(); + // io.Fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; + // ImFontConfig cfg = ImFontConfig(); + // cfg.OversampleH = cfg.OversampleV = 1; + // std::map sys_fonts_map = get_occt_fonts_maps(); // map + // im_fonts_map.clear(); // map + // BOOST_LOG_TRIVIAL(info) << "init_im_font start"; + // for (auto sys_font : sys_fonts_map) { + // boost::filesystem::path font_path(sys_font.second); + // if (!boost::filesystem::exists(font_path)) { + // BOOST_LOG_TRIVIAL(trace) << "load font = " << sys_font.first << ", path = " << font_path << " is not exists"; + // continue; + // } + // ImFont* im_font = io.Fonts->AddFontFromFileTTF(sys_font.second.c_str(), m_font_size, &cfg, ImGui::GetIO().Fonts->GetGlyphRangesBasic()); + // if (im_font == nullptr) { + // BOOST_LOG_TRIVIAL(trace) << "load font = " << sys_font.first << " failed, path = " << font_path << " is not exists"; + // continue; + // } + // im_fonts_map.insert({ sys_font.first, im_font }); + // } + // BOOST_LOG_TRIVIAL(info) << "init_im_font end"; + + // unsigned char* pixels; + // int width, height; + // io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + // BOOST_LOG_TRIVIAL(trace) << "Build system fonts texture done. width: " << width << ", height: " << height; + + // if (m_fonts_names.size() == 0) { + // std::vector to_delete_fonts; + // for (auto im_font : im_fonts_map) { + // if (im_font.second->Glyphs.Size < 4) { to_delete_fonts.push_back(im_font.first); } + // } + // for (auto to_delete_font : to_delete_fonts) { + // sys_fonts_map.erase(to_delete_font); + // im_fonts_map.erase(to_delete_font); + // } + // for (auto im_font : im_fonts_map) m_fonts_names.push_back(im_font.first); + // } + + // GLint last_texture; + // glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + // glsafe(::glGenTextures(1, &(m_font_another_texture))); + // glsafe(::glBindTexture(GL_TEXTURE_2D, m_font_another_texture)); + // glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + // glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + // glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + + // glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); + + // // Store our identifier + // io.Fonts->TexID = (ImTextureID)(intptr_t)m_font_another_texture; + + // // Restore state + // glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture)); + //} +} + void ImGuiWrapper::init_input() { ImGuiIO& io = ImGui::GetIO(); @@ -2052,6 +2280,20 @@ void ImGuiWrapper::destroy_font() } } +void ImGuiWrapper::destroy_fonts_texture() { + //if (m_font_another_texture != 0) { + // if (m_new_frame_open) { + // render(); + // } + // init_font(true); + // glsafe(::glDeleteTextures(1, &m_font_another_texture)); + // m_font_another_texture = 0; + // if (!m_new_frame_open) { + // new_frame(); + // } + //} +} + const char* ImGuiWrapper::clipboard_get(void* user_data) { ImGuiWrapper *self = reinterpret_cast(user_data); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index e0efa6b06e..6b584a60c0 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -45,10 +45,12 @@ bool menu_item_with_icon(const char *label, const char *shortcut, ImVec2 icon_si class ImGuiWrapper { const ImWchar* m_glyph_ranges{ nullptr }; + const ImWchar* m_glyph_basic_ranges { nullptr }; // Chinese, Japanese, Korean bool m_font_cjk{ false }; float m_font_size{ 18.0 }; unsigned m_font_texture{ 0 }; + unsigned m_font_another_texture{ 0 }; float m_style_scaling{ 1.0 }; unsigned m_mouse_buttons{ 0 }; bool m_disabled{ false }; @@ -155,6 +157,13 @@ public: void bold_text(const std::string &str); void title(const std::string& str); + // set font + const std::vector get_fonts_names() const { return m_fonts_names; } + bool push_font_by_name(std::string font_name); + bool pop_font_by_name(std::string font_name); + void load_fonts_texture(); + void destroy_fonts_texture(); + void disabled_begin(bool disabled); void disabled_end(); @@ -185,15 +194,24 @@ public: static const ImVec4 COL_ACTIVE; static const ImVec4 COL_TITLE_BG; static const ImVec4 COL_WINDOW_BG; + static const ImVec4 COL_WINDOW_BG_DARK; static const ImVec4 COL_SEPARATOR; + static const ImVec4 COL_SEPARATOR_DARK; //BBS + static void on_change_color_mode(bool is_dark); static void push_toolbar_style(const float scale); static void pop_toolbar_style(); static void push_menu_style(const float scale); static void pop_menu_style(); static void push_common_window_style(const float scale); static void pop_common_window_style(); + static void push_confirm_button_style(); + static void pop_confirm_button_style(); + static void push_cancel_button_style(); + static void pop_cancel_button_style(); + static void push_button_disable_style(); + static void pop_button_disable_style(); //BBS static int TOOLBAR_WINDOW_FLAGS; @@ -211,7 +229,10 @@ private: static void clipboard_set(void* user_data, const char* text); LastSliderStatus m_last_slider_status; + ImFont* default_font = nullptr; ImFont* bold_font = nullptr; + std::map im_fonts_map; + std::vector m_fonts_names; }; class IMTexture diff --git a/src/slic3r/GUI/ImageGrid.cpp b/src/slic3r/GUI/ImageGrid.cpp index 67f436229d..eff08335d7 100644 --- a/src/slic3r/GUI/ImageGrid.cpp +++ b/src/slic3r/GUI/ImageGrid.cpp @@ -44,7 +44,6 @@ ImageGrid::ImageGrid(wxWindow * parent) { SetBackgroundStyle(wxBG_STYLE_PAINT); SetBackgroundColour(0xEEEEEE); - SetForegroundColour(*wxWHITE); // time text color SetFont(Label::Head_20); m_timer.Bind(wxEVT_TIMER, [this](auto & e) { Refresh(); }); @@ -72,7 +71,7 @@ void ImageGrid::SetFileSystem(boost::shared_ptr file_sys) UpdateFileSystem(); } -void ImageGrid::SetStatus(wxBitmap const & icon, wxString const &msg) +void ImageGrid::SetStatus(ScalableBitmap const & icon, wxString const &msg) { int code = m_file_sys ? m_file_sys->GetLastError() : 1; m_status_icon = icon; @@ -187,8 +186,6 @@ void Slic3r::GUI::ImageGrid::DoAction(size_t index, int action) openFolderForFile(from_u8(file.path)); #else #endif - } else { - m_file_sys->DownloadCancel(index); } return; } @@ -288,7 +285,7 @@ std::pair Slic3r::GUI::ImageGrid::HitTest(wxPoint const &pt) if (!m_selecting) { wxRect hover_rect{0, m_image_size.y - 40, m_image_size.GetWidth(), 40}; auto & file = m_file_sys->GetFile(index); - int btn = file.IsDownload() && file.progress >= 100 ? 3 : 2; + int btn = file.IsDownload() && file.progress >= 0 ? 3 : 2; 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}; @@ -338,6 +335,7 @@ void ImageGrid::mouseDown(wxMouseEvent& event) m_hit_item = hit.second; if (m_hit_type >= HIT_ACTION) Refresh(); + SetFocus(); } } @@ -370,14 +368,17 @@ void ImageGrid::resize(wxSizeEvent& event) void ImageGrid::mouseWheelMoved(wxMouseEvent &event) { - auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? -1 : 1; - int off = m_row_offset + delta; - if (off >= 0 && off < m_row_count) { - m_row_offset = off; - m_timer.StartOnce(4000); // Show position bar - UpdateFocusRange(); - Refresh(); - } + auto delta = -event.GetWheelRotation(); + m_scroll_offset += delta; + int max = m_row_count * m_cell_size.GetHeight() / 4; + if (m_scroll_offset < 0) + m_scroll_offset = 0; + else if (m_scroll_offset >= max) + m_scroll_offset = max - 1; + m_row_offset = m_scroll_offset * 4 / m_cell_size.GetHeight(); + m_timer.StartOnce(4000); // Show position bar + UpdateFocusRange(); + Refresh(); } void Slic3r::GUI::ImageGrid::changedEvent(wxCommandEvent& evt) @@ -477,10 +478,10 @@ void ImageGrid::render(wxDC& dc) if (!m_file_sys || m_file_sys->GetCount() == 0) { dc.DrawRectangle({ 0, 0, size.x, size.y }); if (!m_status_msg.IsEmpty()) { - auto si = m_status_icon.GetSize(); + auto si = m_status_icon.GetBmpSize(); auto st = dc.GetTextExtent(m_status_msg); auto rect = wxRect{0, 0, max(st.x, si.x), si.y + 26 + st.y}.CenterIn(wxRect({0, 0}, size)); - dc.DrawBitmap(m_status_icon, rect.x + (rect.width - si.x) / 2, rect.y); + dc.DrawBitmap(m_status_icon.bmp(), rect.x + (rect.width - si.x) / 2, rect.y); dc.SetTextForeground(wxColor(0x909090)); dc.DrawText(m_status_msg, rect.x + (rect.width - st.x) / 2, rect.GetBottom() - st.y); } @@ -545,6 +546,7 @@ void ImageGrid::render(wxDC& dc) } else { secondAction = _L("Cancel"); nonHoverText = wxString::Format(_L("Downloading %d%%..."), file.progress); + thirdAction = wxString::Format(L"%d%%...", file.progress); } } // Draw buttons on hovered item @@ -559,6 +561,7 @@ void ImageGrid::render(wxDC& dc) dc.DrawBitmap(file.IsSelect() ? m_checked_icon.bmp() : m_unchecked_icon.bmp(), pt + wxPoint{10, m_image_size.GetHeight() - m_checked_icon.GetBmpHeight() - 10}); } else { + dc.SetTextForeground(*wxWHITE); // time text color auto date = wxDateTime((time_t) file.time).Format(_L(formats[m_file_sys->GetGroupMode()])); dc.DrawText(date, pt + wxPoint{24, 16}); } @@ -583,7 +586,7 @@ void ImageGrid::render(wxDC& dc) auto date1 = wxDateTime((time_t) file1.time).Format(_L(formats[m_file_sys->GetGroupMode()])); auto date2 = wxDateTime((time_t) file2.time).Format(_L(formats[m_file_sys->GetGroupMode()])); dc.SetFont(Label::Head_16); - dc.SetTextForeground(wxColor("#262E30")); + dc.SetTextForeground(StateColor::darkModeColorFor("#262E30")); dc.DrawText(date1 + " - " + date2, wxPoint{off.x, 2}); } // Draw bottom background @@ -620,21 +623,23 @@ void Slic3r::GUI::ImageGrid::renderButtons(wxDC &dc, wxStringList const &texts, // Draw button background //dc.Blit(rect.GetTopLeft(), rect.GetSize(), &mdc, {m_buttonBackgroundColor.colorIndexForStates(states) * 128, 0}); //dc.DrawBitmap(m_button_background, rect2.GetTopLeft()); - // Draw button splitter - if (i > 0) dc.DrawLine(rect.GetLeftTop(), rect.GetLeftBottom()); - // Draw button text rect.Deflate(10, 5); + // Draw button splitter + auto pen = dc.GetPen(); + dc.SetPen(wxPen("#616161")); + if (i > 0) dc.DrawLine(rect.GetLeftTop(), rect.GetLeftBottom()); + dc.SetPen(pen); + // Draw button text renderText(dc, texts[i], rect, states | states2); rect.Inflate(10, 5); rect.Offset(rect.GetWidth(), 0); } - dc.SetTextForeground(*wxWHITE); // time text color dc.SetFont(GetFont()); } void Slic3r::GUI::ImageGrid::renderText(wxDC &dc, wxString const &text, wxRect const &rect, int states) { - dc.SetTextForeground(m_buttonTextColor.colorForStates(states)); + dc.SetTextForeground(m_buttonTextColor.colorForStatesNoDark(states)); wxRect rc({0, 0}, dc.GetTextExtent(text)); rc = rc.CenterIn(rect); dc.DrawText(text, rc.GetTopLeft()); diff --git a/src/slic3r/GUI/ImageGrid.h b/src/slic3r/GUI/ImageGrid.h index 516bd3f6b6..8aef8a5e9d 100644 --- a/src/slic3r/GUI/ImageGrid.h +++ b/src/slic3r/GUI/ImageGrid.h @@ -32,7 +32,7 @@ public: void SetFileSystem(boost::shared_ptr file_sys); - void SetStatus(wxBitmap const & icon, wxString const &msg); + void SetStatus(ScalableBitmap const & icon, wxString const &msg); boost::shared_ptr GetFileSystem() { return m_file_sys; } @@ -93,7 +93,7 @@ protected: private: boost::shared_ptr m_file_sys; - wxBitmap m_status_icon; + ScalableBitmap m_status_icon; wxString m_status_msg; ScalableBitmap m_checked_icon; @@ -122,6 +122,7 @@ private: int m_hit_type = HIT_NONE; size_t m_hit_item = size_t(-1); + int m_scroll_offset = 0; int m_row_offset = 0; // 1/4 row height int m_row_count = 0; // 1/4 row height int m_col_count = 1; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index f8a3874ecc..fc7b6025af 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -157,7 +157,7 @@ void ArrangeJob::prepare_selected() { m_locked.emplace_back(std::move(ap)); if (inst_sel[i]) selected_is_locked = true; - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % i; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%, name %3%") % oidx % i % mo->name; } } } @@ -235,37 +235,53 @@ void ArrangeJob::prepare_all() { } prepare_wipe_tower(); + + // add the virtual object into unselect list if has + plate_list.preprocess_exclude_areas(m_unselected, MAX_NUM_PLATES); } +// 准备料塔。逻辑如下: +// 1. 如果料塔被禁用,或是逐件打印,则不需要料塔 +// 2. 以下两种情况需要料塔:1)某对象是多色对象;2)打开了支撑,且支撑体与接触面使用的是不同材料 +// 3. 如果允许不同材料落在相同盘,则以下情况也需要料塔:1)所有选定对象中使用了多种热床温度相同的材料(比如颜色不同的PLA) 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"); + if (op && op->getBool() == false || params.is_seq_print) return; + // 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) { + std::set obj_extruders; + for (int id : item.extrude_ids) obj_extruders.insert(id); + if (obj_extruders.size() > 1) { + need_wipe_tower = true; + BOOST_LOG_TRIVIAL(info) << "arrange: need wipe tower because object " << item.name << " has multiple extruders (has paint-on colors)"; + break; + } + } + // if multile extruders have same bed temp, we need wipe tower - if (!params.is_seq_print) { - // need wipe tower if some object has multiple extruders (has paint-on colors) - if (!params.allow_multi_materials_on_same_plate) { - for (const auto &item : m_selected) - if (item.extrude_ids.size() > 1) { - need_wipe_tower = true; - break; - } - } else { - std::map> bedTemp2extruderIds; - for (const auto &item : m_selected) - for (auto id : item.extrude_ids) { bedTemp2extruderIds[item.bed_temp].insert(id); } - for (const auto &be : bedTemp2extruderIds) { - if (be.second.size() > 1) { - need_wipe_tower = true; - break; - } + if (params.allow_multi_materials_on_same_plate) { + std::map> bedTemp2extruderIds; + for (const auto &item : m_selected) + for (auto id : item.extrude_ids) { bedTemp2extruderIds[item.bed_temp].insert(id); } + 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"; + break; } } } + BOOST_LOG_TRIVIAL(info) << "arrange: need_wipe_tower=" << need_wipe_tower; if (need_wipe_tower) { - // BBS: prepare wipe tower for all possible plates + // check all plates to see if wipe tower is already there ArrangePolygon wipe_tower_ap; std::vector plates_have_wipe_tower(MAX_NUM_PLATES, false); for (int bedid = 0; bedid < MAX_NUM_PLATES; bedid++) @@ -296,20 +312,6 @@ void ArrangeJob::prepare_wipe_tower() } -arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi) -{ - arrangement::ArrangePolygon ap = get_arrange_poly(mi); - - auto setter = ap.setter; - ap.setter = [this, setter, mi](const arrangement::ArrangePolygon &set_ap) { - setter(set_ap); - if (!set_ap.is_arranged()) - m_unarranged.emplace_back(mi); - }; - - return ap; -} - //BBS: prepare current part plate for arranging void ArrangeJob::prepare_partplate() { clear_input(); @@ -347,17 +349,18 @@ void ArrangeJob::prepare_partplate() { ArrangePolygons& cont = mo->instances[inst_idx]->printable ? (in_plate ? m_selected : m_unselected) : m_unprintable; - ap.itemid = cont.size(); bool locked = plate_list.preprocess_arrange_polygon_other_locked(oidx, inst_idx, ap, in_plate); 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 = m_locked.size(); m_locked.emplace_back(std::move(ap)); - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, instance_id %2%") % oidx % inst_idx; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": skip locked instance, obj_id %1%, name %2%") % oidx % mo->name; } } } @@ -368,11 +371,8 @@ void ArrangeJob::prepare_partplate() { m_unselected.emplace_back(std::move(ap)); } - // The strides have to be removed from the fixed items. For the - // arrangeable (selected) items bed_idx is ignored and the - // translation is irrelevant. - //BBS: remove logic for unselected object - //for (auto& p : m_unselected) p.translation(X) -= p.bed_idx * stride; + // add the virtual object into unselect list if has + plate_list.preprocess_exclude_areas(m_unselected, current_plate_index + 1); } //BBS: add partplate logic @@ -389,6 +389,7 @@ void ArrangeJob::prepare() 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.allow_multi_materials_on_same_plate = settings.allow_multi_materials_on_same_plate; params.avoid_extrusion_cali_region = settings.avoid_extrusion_cali_region; @@ -410,8 +411,6 @@ void ArrangeJob::prepare() prepare_partplate(); } - //add the virtual object into unselect list if has - m_plater->get_partplate_list().preprocess_exclude_areas(m_unselected, MAX_NUM_PLATES); #if SAVE_ARRANGE_POLY if (1) @@ -498,13 +497,14 @@ void ArrangeJob::process() { const GLCanvas3D::ArrangeSettings &settings = static_cast(m_plater->canvas3D())->get_arrange_settings(); + auto & partplate_list = m_plater->get_partplate_list(); auto& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print(); if (params.is_seq_print) params.min_obj_distance = std::max(params.min_obj_distance, scaled(params.cleareance_radius)); if (params.avoid_extrusion_cali_region && print.full_print_config().opt_bool("scan_first_layer")) - m_plater->get_partplate_list().preprocess_nonprefered_areas(m_unselected, MAX_NUM_PLATES); + partplate_list.preprocess_nonprefered_areas(m_unselected, MAX_NUM_PLATES); double skirt_distance = print.has_skirt() ? print.config().skirt_distance.value : 0; double brim_max = 0; @@ -527,21 +527,41 @@ void ArrangeJob::process() } } + if (print.full_print_config().opt_bool("enable_support")) { + params.bed_shrink_x = std::max(5.f, params.bed_shrink_x); + params.bed_shrink_y = std::max(5.f, params.bed_shrink_y); + params.min_obj_distance = std::max(scaled(10.0), params.min_obj_distance); + } + // do not inflate brim_width. Objects are allowed to have overlapped brim. - std::for_each(m_selected.begin(), m_selected.end(), [&](auto& ap) {ap.inflation = params.min_obj_distance / 2; }); + Points bedpts = get_bed_shape(*m_plater->config()); + BoundingBox bedbb = Polygon(bedpts).bounding_box(); + std::for_each(m_selected.begin(), m_selected.end(), [&](ArrangePolygon &ap) { + ap.inflation = params.min_obj_distance / 2; + BoundingBox apbb = ap.poly.contour.bounding_box(); + auto diffx = bedbb.size().x() - apbb.size().x() - 5; + auto diffy = bedbb.size().y() - apbb.size().y() - 5; + if (diffx > 0 && diffy > 0) { + auto min_diff = std::min(diffx, diffy); + ap.inflation = std::min(min_diff / 2, ap.inflation); + } + }); // For occulusion regions, inflation should be larger to prevent genrating brim on them. // However, extrusion cali regions are exceptional, since we can allow brim overlaps them. + // 屏蔽区域只需要膨胀brim宽度,防止brim长过去;挤出标定区域不需要膨胀,brim可以长过去。 + // 以前我们认为还需要膨胀clearance_radius/2,这其实是不需要的,因为这些区域并不会真的摆放物体, + // 其他物体的膨胀轮廓是可以跟它们重叠的。 + double scaled_exclusion_gap = scale_(1); std::for_each(m_unselected.begin(), m_unselected.end(), [&](auto &ap) { ap.inflation = !ap.is_virt_object ? params.min_obj_distance / 2 : - (ap.is_extrusion_cali_object ? scaled(params.cleareance_radius / 2) : scaled(params.brim_skirt_distance + params.cleareance_radius / 2)); + (ap.is_extrusion_cali_object ? 0 : scaled_exclusion_gap); }); - m_plater->get_partplate_list().preprocess_exclude_areas(params.excluded_regions, 1); + partplate_list.preprocess_exclude_areas(params.excluded_regions, 1, scaled_exclusion_gap); // shrink bed by moving to center by dist - Points bedpts = get_bed_shape(*m_plater->config()); auto shrinkFun = [](Points& bedpts, double dist, int direction) { #define SGN(x) ((x)>=0?1:-1) Point center = Polygon(bedpts).bounding_box().center(); @@ -561,13 +581,6 @@ void ArrangeJob::process() update_status(num_finished, _L("Arranging") + " " + str); }; - if(!params.is_seq_print) - { - // force all heights be the same, so items are sorted by area - for (auto& ap : m_selected) ap.height = 1; - for (auto& ap : m_unselected) ap.height = 1; - } - { BOOST_LOG_TRIVIAL(debug) << "items selected before arrange: "; for (auto selected : m_selected) @@ -587,7 +600,8 @@ void ArrangeJob::process() BOOST_LOG_TRIVIAL(debug) << "items selected after arrange: "; for (auto selected : m_selected) BOOST_LOG_TRIVIAL(debug) << selected.name << ", extruder: " << selected.extrude_ids.back() << ", bed: " << selected.bed_idx - << ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp; + << ", bed_temp: " << selected.first_bed_temp << ", print_temp: " << selected.print_temp + << ", trans: " << unscale(selected.translation(X)) << ","<< unscale(selected.translation(Y)); BOOST_LOG_TRIVIAL(debug) << "items unselected after arrange: "; for (auto item : m_unselected) if (!item.is_virt_object) diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.hpp b/src/slic3r/GUI/Jobs/ArrangeJob.hpp index 340d867a90..6e8ebe028b 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.hpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.hpp @@ -38,8 +38,6 @@ class ArrangeJob : public PlaterJob void prepare_partplate(); void prepare_wipe_tower(); - ArrangePolygon get_arrange_poly_(ModelInstance* mi); - ArrangePolygon prepare_arrange_polygon(void* instance); protected: diff --git a/src/slic3r/GUI/Jobs/Job.cpp b/src/slic3r/GUI/Jobs/Job.cpp index 7dca5aa9f3..8224285cf3 100644 --- a/src/slic3r/GUI/Jobs/Job.cpp +++ b/src/slic3r/GUI/Jobs/Job.cpp @@ -30,6 +30,11 @@ void GUI::Job::update_status(int st, const wxString &msg) wxQueueEvent(this, evt); } +void GUI::Job::update_percent_finish() +{ + m_progress->clear_percent(); +} + GUI::Job::Job(std::shared_ptr pri) : m_progress(std::move(pri)) { diff --git a/src/slic3r/GUI/Jobs/Job.hpp b/src/slic3r/GUI/Jobs/Job.hpp index 41d12fb368..4041e498f2 100644 --- a/src/slic3r/GUI/Jobs/Job.hpp +++ b/src/slic3r/GUI/Jobs/Job.hpp @@ -45,6 +45,8 @@ protected: // status update, to be used from the work thread (process() method) void update_status(int st, const wxString &msg = ""); + void update_percent_finish(); + bool was_canceled() const { return m_canceled.load(); } // Launched just before start(), a job can use it to prepare internals diff --git a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp index cb71705687..e9f957e4f3 100644 --- a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp +++ b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.cpp @@ -5,6 +5,11 @@ namespace Slic3r { namespace GUI { NotificationProgressIndicator::NotificationProgressIndicator(NotificationManager *nm): m_nm{nm} {} +void NotificationProgressIndicator::clear_percent() +{ + +} + void NotificationProgressIndicator::set_range(int range) { m_nm->progress_indicator_set_range(range); diff --git a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp index 6b03af69df..388bfea935 100644 --- a/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp +++ b/src/slic3r/GUI/Jobs/NotificationProgressIndicator.hpp @@ -14,6 +14,7 @@ public: explicit NotificationProgressIndicator(NotificationManager *nm); + void clear_percent() override; void set_range(int range) override; void set_cancel_callback(CancelFn = CancelFn()) override; void set_progress(int pr) override; diff --git a/src/slic3r/GUI/Jobs/PrintJob.cpp b/src/slic3r/GUI/Jobs/PrintJob.cpp index 7db397c196..eceb338e3f 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.cpp +++ b/src/slic3r/GUI/Jobs/PrintJob.cpp @@ -132,16 +132,22 @@ void PrintJob::process() return; } + // task name std::string project_name = wxGetApp().plater()->get_project_name().ToUTF8().data(); int curr_plate_idx = 0; if (job_data.plate_idx >= 0) curr_plate_idx = job_data.plate_idx + 1; else if (job_data.plate_idx == PLATE_CURRENT_IDX) curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; + else if (job_data.plate_idx == PLATE_ALL_IDX) + curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; + else + curr_plate_idx = m_plater->get_partplate_list().get_curr_plate_index() + 1; BBL::PrintParams params; params.dev_id = m_dev_id; - params.project_name = wxGetApp().plater()->get_project_name().ToUTF8().data(); + //params.project_name = project_name; + params.project_name = m_project_name; params.preset_name = wxGetApp().preset_bundle->prints.get_selected_preset_name(); params.filename = job_data._3mf_path.string(); params.config_filename = job_data._3mf_config_path.string(); @@ -163,18 +169,26 @@ void PrintJob::process() wxString error_text; wxString msg_text; - auto update_fn = [this, &msg, &curr_percent, &error_text](int stage, int code, std::string info) { + + const int StagePercentPoint[(int)PrintingStageFinished + 1] = { + 20, // PrintingStageCreate + 30, // PrintingStageUpload + 70, // PrintingStageWaiting + 75, // PrintingStageRecord + 99, // PrintingStageSending + 100 // PrintingStageFinished + }; + + auto update_fn = [this, &msg, &curr_percent, &error_text, StagePercentPoint](int stage, int code, std::string info) { if (stage == BBL::SendingPrintJobStage::PrintingStageCreate) { if (this->connection_type == "lan") { msg = _L("Sending print job over LAN"); } else { msg = _L("Sending print job through cloud service"); } - curr_percent = 25; } else if (stage == BBL::SendingPrintJobStage::PrintingStageUpload) { - curr_percent = 30; - if (code == 0 && !info.empty()) { + if (code >= 0 && code <= 100 && !info.empty()) { if (this->connection_type == "lan") { msg = _L("Sending print job over LAN"); } else { @@ -189,10 +203,8 @@ void PrintJob::process() } else { msg = _L("Sending print job through cloud service"); } - curr_percent = 50; } else if (stage == BBL::SendingPrintJobStage::PrintingStageRecord) { - curr_percent = 70; msg = _L("Sending print configuration"); } else if (stage == BBL::SendingPrintJobStage::PrintingStageSending) { @@ -201,11 +213,10 @@ void PrintJob::process() } else { msg = _L("Sending print job through cloud service"); } - curr_percent = 90; } else if (stage == BBL::SendingPrintJobStage::PrintingStageFinished) { - curr_percent = 100; - msg = wxString::Format(_L("Successfully sent. Will automatically jump to the device page in %s s"), info); + msg = wxString::Format(_L("Successfully sent. Will automatically jump to the device page in %ss"), info); + this->update_percent_finish(); } else { if (this->connection_type == "lan") { msg = _L("Sending print job over LAN"); @@ -213,7 +224,18 @@ void PrintJob::process() msg = _L("Sending print job through cloud service"); } } - if (code != 0) { + + // update current percnet + if (stage >= 0 && stage <= (int) PrintingStageFinished) { + curr_percent = StagePercentPoint[stage]; + if ((stage == BBL::SendingPrintJobStage::PrintingStageUpload + || stage == BBL::SendingPrintJobStage::PrintingStageRecord) + && (code > 0 && code <= 100)) { + curr_percent = (StagePercentPoint[stage + 1] - StagePercentPoint[stage]) * code / 100 + StagePercentPoint[stage]; + } + } + + if (code > 100 || code < 0) { error_text = this->get_http_error_msg(code, info); msg += wxString::Format("[%s]", error_text); } @@ -273,14 +295,9 @@ void PrintJob::process() } } - if (was_canceled()) { - update_status(curr_percent, printjob_cancel_str); - return; - } - if (result < 0) { if (result == BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED) { - msg_text = upload_failed_str; + msg_text = _L("Failed to send the print job. Please try again."); } if (result == BAMBU_NETWORK_ERR_FILE_NOT_EXIST) { msg_text = file_is_not_exists_str; } else if (result == BAMBU_NETWORK_ERR_FILE_OVER_SIZE) { @@ -288,20 +305,22 @@ void PrintJob::process() } else if (result == BAMBU_NETWORK_ERR_CHECK_MD5_FAILED) { msg_text = failed_in_cloud_service_str; } else if (result == BAMBU_NETWORK_ERR_INVALID_PARAMS) { - msg_text = upload_failed_str; + msg_text = _L("Failed to send the print job. Please try again."); } else if (result == BAMBU_NETWORK_ERR_CANCELED) { msg_text = print_canceled_str; } else if (result == BAMBU_NETWORK_ERR_TIMEOUT) { msg_text = timeout_to_upload_str; } else if (result == BAMBU_NETWORK_ERR_INVALID_RESULT) { - msg_text = upload_failed_str; + msg_text = _L("Failed to send the print job. Please try again."); } else if (result == BAMBU_NETWORK_ERR_FTP_UPLOAD_FAILED) { - msg_text = upload_failed_str; + msg_text = _L("Failed to send the print job. Please try again."); } else { update_status(curr_percent, failed_in_cloud_service_str); } - if (!error_text.IsEmpty()) - msg_text += wxString::Format("[%s]", error_text); + if (!error_text.IsEmpty()) { + curr_percent = 0; + msg_text += wxString::Format("[%d][%s]", result, error_text); + } update_status(curr_percent, msg_text); BOOST_LOG_TRIVIAL(error) << "print_job: failed, result = " << result; } else { @@ -319,4 +338,9 @@ void PrintJob::finalize() { Job::finalize(); } +void PrintJob::set_project_name(std::string name) +{ + m_project_name = name; +} + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/PrintJob.hpp b/src/slic3r/GUI/Jobs/PrintJob.hpp index 449dba499a..13c8d749a8 100644 --- a/src/slic3r/GUI/Jobs/PrintJob.hpp +++ b/src/slic3r/GUI/Jobs/PrintJob.hpp @@ -37,7 +37,7 @@ protected: public: PrintJob(std::shared_ptr pri, Plater *plater, std::string dev_id = ""); - + std::string m_project_name; std::string m_dev_ip; std::string m_access_code; std::string task_bed_type; @@ -75,6 +75,7 @@ public: wxString get_http_error_msg(unsigned int status, std::string body); void process() override; void finalize() override; + void set_project_name(std::string name); }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/ProgressIndicator.hpp b/src/slic3r/GUI/Jobs/ProgressIndicator.hpp index 674a81ba26..b029fa762a 100644 --- a/src/slic3r/GUI/Jobs/ProgressIndicator.hpp +++ b/src/slic3r/GUI/Jobs/ProgressIndicator.hpp @@ -17,6 +17,7 @@ public: virtual ~ProgressIndicator() = default; + virtual void clear_percent() = 0; virtual void set_range(int range) = 0; virtual void set_cancel_callback(CancelFn = CancelFn()) = 0; virtual void set_progress(int pr) = 0; diff --git a/src/slic3r/GUI/Jobs/SendJob.cpp b/src/slic3r/GUI/Jobs/SendJob.cpp index 5d4cbc040b..c15b9995e0 100644 --- a/src/slic3r/GUI/Jobs/SendJob.cpp +++ b/src/slic3r/GUI/Jobs/SendJob.cpp @@ -12,7 +12,7 @@ namespace GUI { static wxString check_gcode_failed_str = _L("Abnormal print file data. Please slice again"); static wxString printjob_cancel_str = _L("Task canceled"); static wxString timeout_to_upload_str = _L("Upload task timed out. Please check the network problem and try again"); -static wxString failed_in_cloud_service_str = _L("Cloud service connection failed. Please try again."); +static wxString failed_in_cloud_service_str = _L("Send to Printer failed. Please try again."); static wxString file_is_not_exists_str = _L("Print file not found, please slice again"); static wxString file_over_size_str = _L("The print file exceeds the maximum allowable size (1GB). Please simplify the model and slice again"); static wxString print_canceled_str = _L("Task canceled"); @@ -150,9 +150,7 @@ void SendJob::process() BBL::PrintParams params; params.dev_id = m_dev_id; - //params.project_name = wxGetApp().plater()->get_project_name().ToUTF8().data(); - params.project_name = wxGetApp().plater()->get_project_name().utf8_string(); - + params.project_name = m_project_name + ".gcode.3mf"; params.preset_name = wxGetApp().preset_bundle->prints.get_selected_preset_name(); params.filename = job_data._3mf_path.string(); params.config_filename = job_data._3mf_config_path.string(); @@ -168,30 +166,37 @@ void SendJob::process() wxString error_text; wxString msg_text; - auto update_fn = [this, &msg, &curr_percent, &error_text](int stage, int code, std::string info) { + const int StagePercentPoint[(int)PrintingStageFinished + 1] = { + 20, // PrintingStageCreate + 30, // PrintingStageUpload + 99, // PrintingStageWaiting + 99, // PrintingStageRecord + 99, // PrintingStageSending + 100 // PrintingStageFinished + }; + + auto update_fn = [this, &msg, &curr_percent, &error_text, StagePercentPoint](int stage, int code, std::string info) { if (stage == SendingPrintJobStage::PrintingStageCreate) { if (this->connection_type == "lan") { msg = _L("Sending gcode file over LAN"); } else { msg = _L("Sending gcode file to sdcard"); } - curr_percent = 25; } else if (stage == SendingPrintJobStage::PrintingStageUpload) { - if (code == 0 && !info.empty()) { - if (this->connection_type == "lan") { - msg = _L("Sending gcode file over LAN"); - } - else { - msg = _L("Sending gcode file to sdcard"); - } - msg += wxString::Format("(%s)", info); - curr_percent = 40; - this->update_status(curr_percent, msg); - } + if (code >= 0 && code <= 100 && !info.empty()) { + if (this->connection_type == "lan") { + msg = _L("Sending gcode file over LAN"); + } + else { + msg = _L("Sending gcode file to sdcard"); + } + if (!info.empty()) { + msg += wxString::Format("(%s)", info); + } + } } else if (stage == SendingPrintJobStage::PrintingStageFinished) { - curr_percent = 100; msg = wxString::Format(_L("Successfully sent. Close current page in %s s"), info); } else { @@ -200,10 +205,19 @@ void SendJob::process() } else { msg = _L("Sending gcode file over LAN"); - //msg = _L("Sending gcode file through cloud service"); } } - if (code != 0) { + + // update current percnet + if (stage >= 0 && stage <= (int) PrintingStageFinished) { + curr_percent = StagePercentPoint[stage]; + if ((stage == BBL::SendingPrintJobStage::PrintingStageUpload) && + (code > 0 && code <= 100)) { + curr_percent = (StagePercentPoint[stage + 1] - StagePercentPoint[stage]) * code / 100 + StagePercentPoint[stage]; + } + } + + if (code < 0 || code > 100) { error_text = this->get_http_error_msg(code, info); msg += wxString::Format("[%s]", error_text); } @@ -253,7 +267,7 @@ void SendJob::process() this->update_status(curr_percent, _L("Sending gcode file over LAN")); result = m_agent->start_send_gcode_to_sdcard(params, update_fn, cancel_fn); } else { - this->update_status(curr_percent, _L("An SD card needs to be inserted before printing via LAN.")); + this->update_status(curr_percent, _L("An SD card needs to be inserted before sending to printer.")); return; } } @@ -265,7 +279,7 @@ void SendJob::process() if (result < 0) { if (result == BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED) { - msg_text = upload_failed_str; + msg_text = upload_login_failed_str; } if (result == BAMBU_NETWORK_ERR_FILE_NOT_EXIST) { msg_text = file_is_not_exists_str; } else if (result == BAMBU_NETWORK_ERR_FILE_OVER_SIZE) { @@ -285,15 +299,24 @@ void SendJob::process() } else { update_status(curr_percent, failed_in_cloud_service_str); } - if (!error_text.IsEmpty()) - msg_text += wxString::Format("[%s]", error_text); + + if (!error_text.IsEmpty()) { + if (result == BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED) { + msg_text += ". "; + msg_text += _L("Please log out and login to the printer again."); + } + else { + msg_text += wxString::Format("[%s]", error_text); + } + } + update_status(curr_percent, msg_text); BOOST_LOG_TRIVIAL(error) << "send_job: failed, result = " << result; } else { BOOST_LOG_TRIVIAL(error) << "send_job: send ok."; //m_success_fun(); wxCommandEvent* evt = new wxCommandEvent(m_print_job_completed_id); - evt->SetString(m_dev_id); + evt->SetString(from_u8(params.project_name)); wxQueueEvent(m_plater, evt); m_job_finished = true; } @@ -311,4 +334,9 @@ void SendJob::finalize() { Job::finalize(); } +void SendJob::set_project_name(std::string name) +{ + m_project_name = name; +} + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/SendJob.hpp b/src/slic3r/GUI/Jobs/SendJob.hpp index 7411b2b1ad..53f9203250 100644 --- a/src/slic3r/GUI/Jobs/SendJob.hpp +++ b/src/slic3r/GUI/Jobs/SendJob.hpp @@ -30,7 +30,7 @@ protected: public: SendJob(std::shared_ptr pri, Plater *plater, std::string dev_id = ""); - + std::string m_project_name; std::string m_dev_ip; std::string m_access_code; std::string task_bed_type; @@ -53,6 +53,7 @@ public: void process() override; void on_success(std::function success); void finalize() override; + void set_project_name(std::string name); }; }} diff --git a/src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp b/src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp index 827cd88434..000edf8542 100644 --- a/src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp +++ b/src/slic3r/GUI/Jobs/UpgradeNetworkJob.cpp @@ -16,7 +16,8 @@ wxDEFINE_EVENT(EVT_INSTALL_NETWORK_FAILED, wxCommandEvent); UpgradeNetworkJob::UpgradeNetworkJob(std::shared_ptr pri) : Job{std::move(pri)} { - ; + name = "plugins"; + package_name = "networking_plugins.zip"; } void UpgradeNetworkJob::on_exception(const std::exception_ptr &eptr) @@ -56,7 +57,7 @@ void UpgradeNetworkJob::process() BOOST_LOG_TRIVIAL(info) << "[UpgradeNetworkJob process]: enter"; // get temp path - fs::path target_file_path = (fs::temp_directory_path() / "network_plugin.zip"); + fs::path target_file_path = (fs::temp_directory_path() / package_name); fs::path tmp_path = target_file_path; auto path_str = tmp_path.string() + wxString::Format(".%d%s", get_current_pid(), ".tmp").ToStdString(); tmp_path = fs::path(path_str); @@ -67,7 +68,7 @@ void UpgradeNetworkJob::process() return was_canceled(); }; int curr_percent = 0; - result = wxGetApp().download_plugin( + result = wxGetApp().download_plugin(name, package_name, [this, &curr_percent](int state, int percent, bool &cancel) { if (state == InstallStatusNormal) { update_status(percent, _L("Downloading")); @@ -95,9 +96,11 @@ void UpgradeNetworkJob::process() return; } - result = wxGetApp().install_plugin([this](int state, int percent, bool&cancel) { + result = wxGetApp().install_plugin( + name, package_name, + [this](int state, int percent, bool &cancel) { if (state == InstallStatusInstallCompleted) { - update_status(percent, _L("Finish")); + update_status(percent, _L("Install successfully.")); } else { update_status(percent, _L("Installing")); } diff --git a/src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp b/src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp index f26dcba37f..20bbf2b4f3 100644 --- a/src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp +++ b/src/slic3r/GUI/Jobs/UpgradeNetworkJob.hpp @@ -29,6 +29,9 @@ class UpgradeNetworkJob : public Job InstallProgressFn pro_fn { nullptr }; protected: + std::string name; + std::string package_name; + void on_exception(const std::exception_ptr &) override; public: UpgradeNetworkJob(std::shared_ptr pri); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index c7abcd233d..0d002c174c 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -85,37 +85,38 @@ KBShortcutsDialog::KBShortcutsDialog() event.SetInt(0); event.SetEventObject(this); wxPostEvent(this, event); + wxGetApp().UpdateDlgDarkUI(this); } void KBShortcutsDialog::OnSelectTabel(wxCommandEvent &event) { - auto id = event.GetInt(); + auto id = event.GetInt(); SelectHash::iterator i = m_hash_selector.begin(); while (i != m_hash_selector.end()) { Select *sel = i->second; if (id == sel->m_index) { - sel->m_tab_button->SetBackgroundColour(wxColour(255, 255, 255)); - sel->m_tab_text->SetBackgroundColour(wxColour(255, 255, 255)); + sel->m_tab_button->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#FFFFFF"))); + sel->m_tab_text->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#FFFFFF"))); sel->m_tab_text->SetFont(::Label::Head_13); sel->m_tab_button->Refresh(); sel->m_tab_text->Refresh(); m_simplebook->SetSelection(id); } else { - sel->m_tab_button->SetBackgroundColour(wxColour(248, 248, 248)); - sel->m_tab_text->SetBackgroundColour(wxColour(248, 248, 248)); + sel->m_tab_button->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F8F8F8"))); + sel->m_tab_text->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F8F8F8"))); sel->m_tab_text->SetFont(::Label::Body_13); sel->m_tab_button->Refresh(); sel->m_tab_text->Refresh(); } i++; } + wxGetApp().UpdateDlgDarkUI(this); } wxWindow *KBShortcutsDialog::create_button(int id, wxString text) { auto tab_button = new wxWindow(m_panel_selects, wxID_ANY, wxDefaultPosition, wxSize( FromDIP(150), FromDIP(28)), wxTAB_TRAVERSAL); - tab_button->SetBackgroundColour(wxColour(248, 248, 248)); wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL); @@ -302,7 +303,6 @@ void KBShortcutsDialog::fill_shortcuts() wxPanel* KBShortcutsDialog::create_page(wxWindow* parent, const ShortcutsItem& shortcuts, const wxFont& font, const wxFont& bold_font) { wxPanel* main_page = new wxPanel(parent); - wxGetApp().UpdateDarkUI(main_page); wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); if (!shortcuts.first.second.empty()) { @@ -327,11 +327,13 @@ wxPanel* KBShortcutsDialog::create_page(wxWindow* parent, const ShortcutsItem& s for (int i = 0; i < items_count; ++i) { const auto &[shortcut, description] = shortcuts.second[i]; auto key = new wxStaticText(scrollable_panel, wxID_ANY, _(shortcut)); + key->SetForegroundColour(wxColour(50, 58, 61)); key->SetFont(bold_font); grid_sizer->Add(key, 0, wxALIGN_CENTRE_VERTICAL); auto desc = new wxStaticText(scrollable_panel, wxID_ANY, _(description)); desc->SetFont(font); + desc->SetForegroundColour(wxColour(50, 58, 61)); desc->Wrap(FromDIP(600)); grid_sizer->Add(desc, 0, wxALIGN_CENTRE_VERTICAL); } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 3e9c777d64..cc601257f3 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -56,6 +56,8 @@ #include "NotificationManager.hpp" #include "MarkdownTip.hpp" #include "NetworkTestDialog.hpp" +#include "ConfigWizard.hpp" +#include "Widgets/WebView.hpp" #ifdef _WIN32 #include @@ -69,6 +71,7 @@ namespace GUI { wxDEFINE_EVENT(EVT_SELECT_TAB, wxCommandEvent); wxDEFINE_EVENT(EVT_HTTP_ERROR, wxCommandEvent); wxDEFINE_EVENT(EVT_USER_LOGIN, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPDATE_PRESET_CB, SimpleEvent); // BBS: backup wxDEFINE_EVENT(EVT_BACKUP_POST, wxCommandEvent); @@ -153,7 +156,7 @@ MainFrame::MainFrame() : DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_STYLE, "mainframe") , m_printhost_queue_dlg(new PrintHostQueueDialog(this)) // BBS - , m_recent_projects(9) + , m_recent_projects(18) , m_settings_dialog(this) , diff_dialog(this) { @@ -322,6 +325,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ TabPosition pos = (TabPosition)evt.GetInt(); m_tabpanel->SetSelection(pos); }); + Bind(EVT_SYNC_CLOUD_PRESET, &MainFrame::on_select_default_preset, this); // Bind(wxEVT_MENU, @@ -447,6 +451,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ m_plater->reset(); this->shutdown(); // propagate event + + wxGetApp().remove_mall_system_dialog(); event.Skip(); BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": mainframe finished process close_widow event"; }); @@ -469,10 +475,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); event.Skip(); }); -#endif - - wxGetApp().persist_window_geometry(this, true); - wxGetApp().persist_window_geometry(&m_settings_dialog, true); +#endif update_ui_from_settings(); // FIXME (?) @@ -510,9 +513,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ return; } if (evt.CmdDown() && evt.GetKeyCode() == 'Q') { wxPostEvent(this, wxCloseEvent(wxEVT_CLOSE_WINDOW)); return;} - if (evt.CmdDown() && evt.RawControlDown() && evt.GetKeyCode() == 'F') { + if (evt.CmdDown() && evt.RawControlDown() && evt.GetKeyCode() == 'F') { EnableFullScreenView(true); - if (IsFullScreen()) { + if (IsFullScreen()) { ShowFullScreen(false); } else { ShowFullScreen(true); @@ -522,13 +525,13 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ if (evt.CmdDown() && evt.GetKeyCode() == 'J') { m_printhost_queue_dlg->Show(); return; } if (evt.CmdDown() && evt.GetKeyCode() == 'N') { m_plater->new_project(); return;} if (evt.CmdDown() && evt.GetKeyCode() == 'O') { m_plater->load_project(); return;} - if (evt.CmdDown() && evt.ShiftDown() && evt.GetKeyCode() == 'S') { if (m_plater) m_plater->save_project(true); return;} - else if (evt.CmdDown() && evt.GetKeyCode() == 'S') { if (m_plater) m_plater->save_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;} #ifdef __APPLE__ if (evt.CmdDown() && evt.GetKeyCode() == ',') #else - if (evt.CmdDown() && evt.GetKeyCode() == 'P') + if (evt.CmdDown() && evt.GetKeyCode() == 'P') #endif { PreferencesDialog dlg(this); @@ -549,6 +552,13 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ } evt.Skip(); }); + +#ifdef _MSW_DARK_MODE + wxGetApp().UpdateDarkUIWin(this); +#endif // _MSW_DARK_MODE + + wxGetApp().persist_window_geometry(this, true); + wxGetApp().persist_window_geometry(&m_settings_dialog, true); } #ifdef __WIN32__ @@ -678,6 +688,17 @@ void MainFrame::update_layout() 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_main_sizer->Add(m_tabpanel, 1, wxEXPAND | wxTOP, 0); + + m_tabpanel->Bind(wxCUSTOMEVT_NOTEBOOK_SEL_CHANGED, [this](wxCommandEvent& evt) + { + // jump to 3deditor under preview_only mode + if (evt.GetId() == tp3DEditor){ + if (!preview_only_hint()) + return; + } + evt.Skip(); + }); + m_plater->Show(); m_tabpanel->Show(); @@ -791,10 +812,10 @@ void MainFrame::shutdown() void MainFrame::update_title() { - return; + return; } -void MainFrame::update_title_colour_after_set_title() +void MainFrame::update_title_colour_after_set_title() { #ifdef __APPLE__ set_title_colour_after_set_title(GetHandle()); @@ -808,6 +829,7 @@ void MainFrame::show_option(bool show) if (m_slice_btn->IsShown()) { m_slice_btn->Hide(); m_print_btn->Hide(); + m_slice_option_btn->Hide(); m_print_option_btn->Hide(); Layout(); } @@ -815,6 +837,7 @@ void MainFrame::show_option(bool show) if (!m_slice_btn->IsShown()) { m_slice_btn->Show(); m_print_btn->Show(); + m_slice_option_btn->Show(); m_print_option_btn->Show(); Layout(); } @@ -828,6 +851,7 @@ void MainFrame::init_tabpanel() // BBS wxBoxSizer* side_tools = create_side_tools(); m_tabpanel = new Notebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, side_tools, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); + m_tabpanel->SetBackgroundColour(*wxWHITE); #ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font()); @@ -850,14 +874,6 @@ void MainFrame::init_tabpanel() } } } - else if (new_sel == tp3DEditor) { - if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) { - e.Veto(); - BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2% in preview mode")%old_sel %new_sel; - wxCommandEvent *evt = new wxCommandEvent(EVT_PREVIEW_ONLY_MODE_HINT); - wxQueueEvent(m_plater, evt); - } - } }); #ifdef __WXMSW__ @@ -921,7 +937,6 @@ 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_param_panel = new ParamsPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); } @@ -935,6 +950,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_printer_view = new PrinterWebView(m_tabpanel); @@ -946,6 +962,7 @@ void MainFrame::init_tabpanel() m_printer_view->Hide(); m_auxiliary = new AuxiliaryPanel(m_tabpanel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_auxiliary->SetBackgroundColour(*wxWHITE); m_tabpanel->AddPage(m_auxiliary, _L("Project"), std::string("tab_auxiliary_avtice"), std::string("tab_auxiliary_avtice")); if (m_plater) { @@ -990,6 +1007,33 @@ void MainFrame::show_device(bool bBBLPrinter) { } +bool MainFrame::preview_only_hint() +{ + if (m_plater && (m_plater->only_gcode_mode() || (m_plater->using_exported_file()))) { + BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2% in preview mode")%m_tabpanel->GetSelection() %tp3DEditor; + + ConfirmBeforeSendDialog confirm_dlg(this, wxID_ANY, _L("Warning")); + confirm_dlg.Bind(EVT_SECONDARY_CHECK_CONFIRM, [this](wxCommandEvent& e) { + preview_only_to_editor = true; + }); + confirm_dlg.update_btn_label(_L("Yes"), _L("No")); + auto filename = wxString((m_plater->get_preview_only_filename()).c_str(), wxConvUTF8); + //if size of filename is beyond limit + auto format_filename = confirm_dlg.format_text(filename, FromDIP(240)); + + confirm_dlg.update_text(format_filename + _L(" will be closed before creating a new model. Do you want to continue?")); + confirm_dlg.on_show(); + if (preview_only_to_editor) { + m_plater->new_project(); + preview_only_to_editor = false; + } + + return false; + } + + return true; +} + #ifdef WIN32 void MainFrame::register_win32_callbacks() { @@ -1115,13 +1159,13 @@ bool MainFrame::can_save() const { return (m_plater != nullptr) && !m_plater->get_view3D_canvas3D()->get_gizmos_manager().is_in_editing_mode(false) && - m_plater->is_project_dirty(); + m_plater->is_project_dirty() && !m_plater->using_exported_file() && !m_plater->only_gcode_mode(); } bool MainFrame::can_save_as() const { return (m_plater != nullptr) && - !m_plater->get_view3D_canvas3D()->get_gizmos_manager().is_in_editing_mode(false); + !m_plater->get_view3D_canvas3D()->get_gizmos_manager().is_in_editing_mode(false) && !m_plater->using_exported_file() && !m_plater->only_gcode_mode(); } void MainFrame::save_project() @@ -1192,10 +1236,39 @@ bool MainFrame::can_export_gcode() const return true; } +bool MainFrame::can_export_all_gcode() const +{ + if (m_plater == nullptr) + return false; + + if (m_plater->model().objects.empty()) + return false; + + if (m_plater->is_export_gcode_scheduled()) + return false; + + // TODO:: add other filters + PartPlateList& part_plate_list = m_plater->get_partplate_list(); + return part_plate_list.is_all_slice_results_ready_for_print(); +} + +bool MainFrame::can_print_3mf() const +{ + if (m_plater && !m_plater->model().objects.empty()) { + if (wxGetApp().preset_bundle->printers.get_edited_preset().is_custom_defined()) + return false; + } + return true; +} + bool MainFrame::can_send_gcode() const { if (m_plater && !m_plater->model().objects.empty()) { + // BBL printer presets + if (!wxGetApp().preset_bundle->printers.get_edited_preset().is_custom_defined()) + return false; + auto cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config; if (const auto *print_host_opt = cfg.option("print_host"); print_host_opt) return !print_host_opt->value.empty(); @@ -1264,7 +1337,7 @@ bool MainFrame::can_deselect() const bool MainFrame::can_delete() const { - return (m_plater != nullptr) && (m_tabpanel->GetSelection() == TabPosition::tp3DEditor) && !m_plater->is_selection_empty(); + return (m_plater != nullptr) && (m_tabpanel->GetSelection() == TabPosition::tp3DEditor) && !m_plater->is_selection_empty(); } bool MainFrame::can_delete_all() const @@ -1286,11 +1359,14 @@ wxBoxSizer* MainFrame::create_side_tools() m_print_select = ePrintPlate; m_slice_btn = new SideButton(this, _L("Slice"), ""); + m_slice_option_btn = new SideButton(this, "", "sidebutton_dropdown", 0, FromDIP(14)); m_print_btn = new SideButton(this, _L("Print"), ""); m_print_option_btn = new SideButton(this, "", "sidebutton_dropdown", 0, FromDIP(14)); update_side_button_style(); + m_slice_option_btn->Enable(); m_print_option_btn->Enable(); + sizer->Add(m_slice_option_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(1)); sizer->Add(m_slice_btn, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(1)); sizer->Add(FromDIP(15), 0, 0, 0, 0); sizer->Add(m_print_option_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(1)); @@ -1300,97 +1376,84 @@ wxBoxSizer* MainFrame::create_side_tools() sizer->Layout(); m_slice_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) - { - //this->m_plater->select_view_3D("Preview"); - m_plater->update(); - if (m_slice_select == eSliceAll) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL)); - else - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); + { + //this->m_plater->select_view_3D("Preview"); + m_plater->update(); + if (m_slice_select == eSliceAll) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL)); + else + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE)); this->m_tabpanel->SetSelection(tpPreview); }); m_print_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) - { - //this->m_plater->select_view_3D("Preview"); - if (m_print_select == ePrintAll || m_print_select == ePrintPlate) { - m_plater->apply_background_progress(); - // check valid of print - m_print_enable = get_enable_print_status(); - m_print_btn->Enable(m_print_enable); - if (m_print_enable) { - if (m_print_select == ePrintAll) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_ALL)); - if (m_print_select == ePrintPlate) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE)); + //this->m_plater->select_view_3D("Preview"); + if (m_print_select == ePrintAll || m_print_select == ePrintPlate) + { + m_plater->apply_background_progress(); + // check valid of print + m_print_enable = get_enable_print_status(); + m_print_btn->Enable(m_print_enable); + if (m_print_enable) { + if (m_print_select == ePrintAll) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_ALL)); + if (m_print_select == ePrintPlate) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE)); + } } - } - else if (m_print_select == eExportGcode) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_GCODE)); - else if (m_print_select == eSendGcode) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE)); - else if (m_print_select == eUploadGcode) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_UPLOAD_GCODE)); - else if (m_print_select == eExportSlicedFile) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); - else if (m_print_select == eSendToPrinter) - wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_TO_PRINTER)); - }); + else if (m_print_select == eExportGcode) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_GCODE)); + else if (m_print_select == eSendGcode) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE)); + else if (m_print_select == eUploadGcode) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_UPLOAD_GCODE)); + else if (m_print_select == eExportSlicedFile) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); + else if (m_print_select == eExportAllSlicedFile) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_ALL_SLICED_FILE)); + else if (m_print_select == eSendToPrinter) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_TO_PRINTER)); + else if (m_print_select == eSendToPrinterAll) + wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_TO_PRINTER_ALL)); + }); - // only support single plate currently -#if 0 m_slice_option_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { SidePopup* p = new SidePopup(this); SideButton* slice_all_btn = new SideButton(p, _L("Slice all"), ""); slice_all_btn->SetCornerRadius(0); - SideButton* slice_plate_btn = new SideButton(p, _L("Slice"), ""); + SideButton* slice_plate_btn = new SideButton(p, _L("Slice plate"), ""); slice_plate_btn->SetCornerRadius(0); slice_all_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { - m_slice_btn->SetLabel(_L("Slice all")); - m_slice_select = eSliceAll; - m_slice_enable = get_enable_slice_status(); - m_slice_btn->Enable(m_slice_enable); - this->Layout(); - p->Dismiss(); + m_slice_btn->SetLabel(_L("Slice all")); + m_slice_select = eSliceAll; + m_slice_enable = get_enable_slice_status(); + m_slice_btn->Enable(m_slice_enable); + this->Layout(); + p->Dismiss(); }); slice_plate_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { - m_slice_btn->SetLabel(_L("Slice plate")); - m_slice_select = eSlicePlate; - m_slice_enable = get_enable_slice_status(); - m_slice_btn->Enable(m_slice_enable); - this->Layout(); - p->Dismiss(); + m_slice_btn->SetLabel(_L("Slice plate")); + m_slice_select = eSlicePlate; + m_slice_enable = get_enable_slice_status(); + m_slice_btn->Enable(m_slice_enable); + this->Layout(); + p->Dismiss(); }); p->append_button(slice_all_btn); p->append_button(slice_plate_btn); p->Popup(m_slice_btn); } ); -#endif m_print_option_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { SidePopup* p = new SidePopup(this); -#if ENABEL_PRINT_ALL - SideButton* print_all_btn = new SideButton(p, _L("Print all"), ""); - print_all_btn->SetCornerRadius(0); - print_all_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent &) { - m_print_btn->SetLabel(_L("Print all")); - m_print_select = ePrintAll; - if (m_print_enable) m_print_enable = get_enable_print_status(); - m_print_btn->Enable(m_print_enable); - this->Layout(); - p->Dismiss(); - }); -#endif -#if ENABEL_PRINT_ALL - p->append_button(print_all_btn); -#endif + if (wxGetApp().preset_bundle && !wxGetApp().preset_bundle->printers.get_edited_preset().is_bbl_vendor_preset(wxGetApp().preset_bundle)) { // ThirdParty Buttons @@ -1418,7 +1481,7 @@ wxBoxSizer* MainFrame::create_side_tools() }); // upload only - /*SideButton* upload_gcode_btn = new SideButton(p, _L("Send"), ""); + SideButton* upload_gcode_btn = new SideButton(p, _L("Send"), ""); upload_gcode_btn->SetCornerRadius(0); upload_gcode_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { m_print_btn->SetLabel(_L("Send")); @@ -1427,24 +1490,28 @@ wxBoxSizer* MainFrame::create_side_tools() m_print_btn->Enable(m_print_enable); this->Layout(); p->Dismiss(); - });*/ + }); p->append_button(send_gcode_btn); - //p->append_button(upload_gcode_btn); + p->append_button(upload_gcode_btn); p->append_button(export_gcode_btn); - } else { + } + else { //Bambu Studio Buttons - SideButton* print_plate_btn = new SideButton(p, _L("Print"), ""); + SideButton* print_plate_btn = new SideButton(p, _L("Print plate"), ""); print_plate_btn->SetCornerRadius(0); - /*SideButton* send_to_printer_btn = new SideButton(p, _L("Send"), ""); - send_to_printer_btn->SetCornerRadius(0);*/ + SideButton* send_to_printer_btn = new SideButton(p, _L("Send"), ""); + send_to_printer_btn->SetCornerRadius(0); - SideButton* export_sliced_file_btn = new SideButton(p, _L("Export sliced file"), ""); + SideButton* export_sliced_file_btn = new SideButton(p, _L("Export plate sliced file"), ""); export_sliced_file_btn->SetCornerRadius(0); + SideButton* export_all_sliced_file_btn = new SideButton(p, _L("Export all sliced file"), ""); + export_all_sliced_file_btn->SetCornerRadius(0); + print_plate_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { - m_print_btn->SetLabel(_L("Print")); + m_print_btn->SetLabel(_L("Print plate")); m_print_select = ePrintPlate; m_print_enable = get_enable_print_status(); m_print_btn->Enable(m_print_enable); @@ -1452,26 +1519,61 @@ wxBoxSizer* MainFrame::create_side_tools() p->Dismiss(); }); - /*send_to_printer_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { + SideButton* print_all_btn = new SideButton(p, _L("Print all"), ""); + print_all_btn->SetCornerRadius(0); + print_all_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { + m_print_btn->SetLabel(_L("Print all")); + m_print_select = ePrintAll; + m_print_enable = get_enable_print_status(); + m_print_btn->Enable(m_print_enable); + this->Layout(); + p->Dismiss(); + }); + + send_to_printer_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { m_print_btn->SetLabel(_L("Send")); m_print_select = eSendToPrinter; m_print_enable = get_enable_print_status(); m_print_btn->Enable(m_print_enable); this->Layout(); p->Dismiss(); - });*/ + }); + + SideButton* send_to_printer_all_btn = new SideButton(p, _L("Send all"), ""); + send_to_printer_all_btn->SetCornerRadius(0); + send_to_printer_all_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { + m_print_btn->SetLabel(_L("Send all")); + m_print_select = eSendToPrinterAll; + m_print_enable = get_enable_print_status(); + m_print_btn->Enable(m_print_enable); + this->Layout(); + p->Dismiss(); + }); export_sliced_file_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { - m_print_btn->SetLabel(_L("Export Sliced File")); + m_print_btn->SetLabel(_L("Export plate sliced file")); m_print_select = eExportSlicedFile; m_print_enable = get_enable_print_status(); m_print_btn->Enable(m_print_enable); this->Layout(); p->Dismiss(); }); + + export_all_sliced_file_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { + m_print_btn->SetLabel(_L("Export all sliced file")); + m_print_select = eExportAllSlicedFile; + m_print_enable = get_enable_print_status(); + m_print_btn->Enable(m_print_enable); + this->Layout(); + p->Dismiss(); + }); + p->append_button(print_plate_btn); - //p->append_button(send_to_printer_btn); + p->append_button(print_all_btn); + p->append_button(send_to_printer_btn); + p->append_button(send_to_printer_all_btn); p->append_button(export_sliced_file_btn); + p->append_button(export_all_sliced_file_btn); } p->Popup(m_print_btn); @@ -1500,20 +1602,26 @@ bool MainFrame::get_enable_slice_status() BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": on slicing, return false directly!"); return false; } + else if (m_plater->only_gcode_mode() || m_plater->using_exported_file()) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": in gcode/exported 3mf mode, return false directly!"); + return false; + } PartPlateList &part_plate_list = m_plater->get_partplate_list(); PartPlate *current_plate = part_plate_list.get_curr_plate(); if (m_slice_select == eSliceAll) { - if (part_plate_list.is_all_slice_results_valid()) + /*if (part_plate_list.is_all_slice_results_valid()) { enable = false; } else if (!part_plate_list.is_all_plates_ready_for_slice()) { enable = false; - } + }*/ + //always enable slice_all button + enable = true; } else if (m_slice_select == eSlicePlate) { @@ -1587,6 +1695,20 @@ bool MainFrame::get_enable_print_status() enable = false; } } + else if (m_print_select == eSendToPrinterAll) + { + if (!part_plate_list.is_all_slice_results_ready_for_print()) + { + enable = false; + } + } + else if (m_print_select == eExportAllSlicedFile) + { + if (!part_plate_list.is_all_slice_results_ready_for_print()) + { + enable = false; + } + } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": m_print_select %1%, enable= %2% ")%m_print_select %enable; @@ -1598,33 +1720,34 @@ void MainFrame::update_side_button_style() // BBS int em = em_unit(); - m_slice_btn->SetLayoutStyle(1); + /*m_slice_btn->SetLayoutStyle(1); m_slice_btn->SetTextLayout(SideButton::EHorizontalOrientation::HO_Center, FromDIP(15)); m_slice_btn->SetMinSize(wxSize(-1, FromDIP(24))); m_slice_btn->SetCornerRadius(FromDIP(12)); m_slice_btn->SetExtraSize(wxSize(FromDIP(38), FromDIP(10))); - m_slice_btn->SetBottomColour(wxColour(0x3B4446)); + m_slice_btn->SetBottomColour(wxColour(0x3B4446));*/ + m_slice_btn->SetTextLayout(SideButton::EHorizontalOrientation::HO_Left, FromDIP(15)); + m_slice_btn->SetCornerRadius(FromDIP(12)); + m_slice_btn->SetExtraSize(wxSize(FromDIP(38), FromDIP(10))); + m_slice_btn->SetMinSize(wxSize(-1, FromDIP(24))); -#if 0 m_slice_option_btn->SetTextLayout(SideButton::EHorizontalOrientation::HO_Center); - m_slice_option_btn->SetCornerRadius(12 * em / 10); - m_slice_option_btn->SetExtraSize(wxSize(10 * em / 10, 10 * em / 10)); - m_slice_option_btn->SetIconOffset(2 * em / 10); - m_slice_option_btn->SetMinSize(wxSize(24 * em / 10, 24 * em / 10)); - m_slice_option_btn->SetBottomColour(wxColour(0x3B4446)); -#endif + m_slice_option_btn->SetCornerRadius(FromDIP(12)); + m_slice_option_btn->SetExtraSize(wxSize(FromDIP(10), FromDIP(10))); + m_slice_option_btn->SetIconOffset(FromDIP(2)); + m_slice_option_btn->SetMinSize(wxSize(FromDIP(24), FromDIP(24))); + m_print_btn->SetTextLayout(SideButton::EHorizontalOrientation::HO_Left, FromDIP(15)); m_print_btn->SetCornerRadius(FromDIP(12)); m_print_btn->SetExtraSize(wxSize(FromDIP(38), FromDIP(10))); m_print_btn->SetMinSize(wxSize(-1, FromDIP(24))); - m_print_btn->SetBottomColour(wxColour(0x3B4446)); + m_print_option_btn->SetTextLayout(SideButton::EHorizontalOrientation::HO_Center); m_print_option_btn->SetCornerRadius(FromDIP(12)); m_print_option_btn->SetExtraSize(wxSize(FromDIP(10), FromDIP(10))); m_print_option_btn->SetIconOffset(FromDIP(2)); m_print_option_btn->SetMinSize(wxSize(FromDIP(24), FromDIP(24))); - m_print_option_btn->SetBottomColour(wxColour(0x3B4446)); } void MainFrame::update_slice_print_status(SlicePrintEventType event, bool can_slice, bool can_print) @@ -1681,8 +1804,8 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect) update_side_button_style(); m_slice_btn->Rescale(); - //m_slice_option_btn->Rescale(); m_print_btn->Rescale(); + m_slice_option_btn->Rescale(); m_print_option_btn->Rescale(); // update Plater @@ -1729,6 +1852,12 @@ void MainFrame::on_sys_color_changed() // update label colors in respect to the system mode wxGetApp().init_label_colours(); + +#ifdef __APPLE__ + wxGetApp().force_colors_update(); + wxGetApp().update_ui_from_settings(); +#endif //__APPLE__ + #ifdef __WXMSW__ wxGetApp().UpdateDarkUI(m_tabpanel); // m_statusbar->update_dark_ui(); @@ -1741,9 +1870,11 @@ void MainFrame::on_sys_color_changed() // BBS m_tabpanel->Rescale(); + m_param_panel->msw_rescale(); // update Plater wxGetApp().plater()->sys_color_changed(); + m_monitor->on_sys_color_changed(); // update Tabs for (auto tab : wxGetApp().tabs_list) @@ -1753,6 +1884,8 @@ void MainFrame::on_sys_color_changed() MenuFactory::sys_color_changed(m_menubar); + WebView::RecreateAll(); + this->Refresh(); } @@ -1781,6 +1914,11 @@ static wxMenu* generate_help_menu() append_menu_item(helpMenu, wxID_ANY, _L("Show Configuration Folder"), _L("Show Configuration Folder"), [](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_current_canvas3D()->set_as_dirty(); + }); + // Report a bug //append_menu_item(helpMenu, wxID_ANY, _L("Report Bug(TODO)"), _L("Report a bug of BambuStudio"), // [](wxCommandEvent&) { @@ -1793,25 +1931,58 @@ static wxMenu* generate_help_menu() }, "", nullptr, []() { return true; }); - // About -#ifndef __APPLE__ - wxString about_title = wxString::Format(_L("&About %s"), SLIC3R_APP_FULL_NAME); - append_menu_item(helpMenu, wxID_ANY, about_title, about_title, - [](wxCommandEvent&) { Slic3r::GUI::about(); }); -#endif - 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_current_canvas3D()->set_as_dirty(); - }); append_menu_item(helpMenu, wxID_ANY, _L("Open Network Test"), _L("Open Network Test"), [](wxCommandEvent&) { NetworkTestDialog dlg(wxGetApp().mainframe); dlg.ShowModal(); }); + // About +#ifndef __APPLE__ + wxString about_title = wxString::Format(_L("&About %s"), SLIC3R_APP_FULL_NAME); + append_menu_item(helpMenu, wxID_ANY, about_title, about_title, + [](wxCommandEvent&) { Slic3r::GUI::about(); }); +#endif + return helpMenu; } + +static void add_common_publish_menu_items(wxMenu* publish_menu, MainFrame* mainFrame) +{ +#ifndef __WINDOWS__ + append_menu_item(publish_menu, wxID_ANY, _L("Upload Models"), _L("Upload Models"), + [](wxCommandEvent&) { + if (!wxGetApp().getAgent()) { + BOOST_LOG_TRIVIAL(info) << "publish: no agent"; + return; + } + + //if (GUI::wxGetApp().plater()->model().objects.empty()) return; + + if (!wxGetApp().check_login()) + return; + + wxGetApp().open_publish_page_dialog(); + }); + + append_menu_item(publish_menu, wxID_ANY, _L("Download Models"), _L("Download Models"), + [](wxCommandEvent&) { + if (!wxGetApp().getAgent()) { + BOOST_LOG_TRIVIAL(info) << "publish: no agent"; + return; +} + + //if (GUI::wxGetApp().plater()->model().objects.empty()) return; + + if (!wxGetApp().check_login()) + return; + + wxGetApp().open_mall_page_dialog(); + }); +#endif +} + static void add_common_view_menu_items(wxMenu* view_menu, MainFrame* mainFrame, std::function can_change_view) { // The camera control accelerators are captured by GLCanvas3D::on_char(). @@ -1917,13 +2088,13 @@ void MainFrame::init_menubar_as_editor() // BBS wxMenu *import_menu = new wxMenu(); #ifndef __APPLE__ - append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/OBJ/AMF") + dots + "\tCtrl+I", _L("Load a model"), + append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots + "\tCtrl+I", _L("Load a model"), [this](wxCommandEvent&) { if (m_plater) { - m_plater->add_model(); + m_plater->add_file(); } }, "menu_import", nullptr, [this](){return can_add_models(); }, this); #else - append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/OBJ/AMF") + dots + "\tCtrl+I", _L("Load a model"), + append_menu_item(import_menu, wxID_ANY, _L("Import 3MF/STL/STEP/SVG/OBJ/AMF") + dots + "\tCtrl+I", _L("Load a model"), [this](wxCommandEvent&) { if (m_plater) { m_plater->add_model(); } }, "", nullptr, [this](){return can_add_models(); }, this); #endif @@ -1943,16 +2114,21 @@ void MainFrame::init_menubar_as_editor() [this](wxCommandEvent&) { if (m_plater) m_plater->export_core_3mf(); }, "menu_export_sliced_file", nullptr, [this](){return can_export_model(); }, this); // BBS export .gcode.3mf - append_menu_item(export_menu, wxID_ANY, _L("Export Sliced File") + dots/* + "\tCtrl+G"*/, _L("Export current Sliced file"), + append_menu_item(export_menu, wxID_ANY, _L("Export plate sliced file") + dots/* + "\tCtrl+G"*/, _L("Export current sliced file"), [this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); }, "menu_export_sliced_file", nullptr, [this](){return can_export_gcode(); }, this); + + append_menu_item(export_menu, wxID_ANY, _L("Export all plate sliced file") + dots/* + "\tCtrl+G"*/, _L("Export all plate sliced file"), + [this](wxCommandEvent&) { if (m_plater) wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_EXPORT_SLICED_FILE)); }, "menu_export_sliced_file", nullptr, + [this]() {return can_export_all_gcode(); }, this); + append_menu_item(export_menu, wxID_ANY, _L("Export G-code") + dots/* + "\tCtrl+G"*/, _L("Export current plate as G-code"), [this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(false); }, "menu_export_gcode", nullptr, [this]() {return can_export_gcode(); }, this); append_menu_item( - export_menu, wxID_ANY, _L("Export &Configs") + dots /* + "\tCtrl+E"*/, _L("Export current configuration to files"), + export_menu, wxID_ANY, _L("Export &Configs") + dots /* + "\tCtrl+E"*/, _L("Export current configuration to files"), [this](wxCommandEvent &) { export_config(); }, - "menu_export_config", nullptr, + "menu_export_config", nullptr, []() { return true; }, this); append_submenu(fileMenu, export_menu, wxID_ANY, _L("Export"), ""); @@ -2040,10 +2216,12 @@ void MainFrame::init_menubar_as_editor() append_menu_item(editMenu, wxID_ANY, _L("Paste") + "\tCtrl+V", _L("Paste clipboard"), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this); +#if 0 // BBS Delete selected - append_menu_item(editMenu, wxID_ANY, _L("Delete selected") + "\tDel", + append_menu_item(editMenu, wxID_ANY, _L("Delete selected") + "\tBackSpace", _L("Deletes the current selection"),[this](wxCommandEvent&) { m_plater->remove_selected(); }, "", nullptr, [this](){return can_delete(); }, this); +#endif //BBS: delete all append_menu_item(editMenu, wxID_ANY, _L("Delete all") + "\tCtrl+D", _L("Deletes all objects"),[this](wxCommandEvent&) { m_plater->delete_all_objects_from_model(); }, @@ -2084,6 +2262,14 @@ void MainFrame::init_menubar_as_editor() // BBS + //publish menu + + if (m_plater) { + publishMenu = new wxMenu(); + add_common_publish_menu_items(publishMenu, this); + publishMenu->AppendSeparator(); + } + // View menu wxMenu* viewMenu = nullptr; if (m_plater) { @@ -2110,10 +2296,15 @@ void MainFrame::init_menubar_as_editor() viewMenu->Check(wxID_CAMERA_ORTHOGONAL + camera_id_base, true); viewMenu->AppendSeparator(); - append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Labels"), _L("Show object labels in 3D scene"), - [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, + append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Labels") + "\tCtrl+E", _L("Show object labels in 3D scene"), + [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); + /*viewMenu->AppendSeparator(); + append_menu_check_item(viewMenu, wxID_ANY, _L("Show &Wireframe") + "\tCtrl+Shift+Enter", _L("Show wireframes in 3D scene"), + [this](wxCommandEvent&) { m_plater->toggle_show_wireframe(); m_plater->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT)); }, this, + [this]() { return m_plater->is_wireframe_enabled(); }, [this]() { return m_plater->is_show_wireframe(); }, this);*/ + //viewMenu->AppendSeparator(); ////BBS orthogonal view //append_menu_check_item(viewMenu, wxID_ANY, _L("Show Edges(TODO)"), _L("Show Edges"), @@ -2232,11 +2423,11 @@ void MainFrame::init_menubar_as_editor() //}); //parent_menu->Insert(0, about_item); append_menu_item( - parent_menu, wxID_ANY, _L(about_title), _L(""), + parent_menu, wxID_ANY, _L(about_title), "", [this](wxCommandEvent &) { Slic3r::GUI::about();}, "", nullptr, []() { return true; }, this, 0); append_menu_item( - parent_menu, wxID_ANY, _L("Preferences") + "\tCtrl+,", _L(""), + parent_menu, wxID_ANY, _L("Preferences") + "\tCtrl+,", "", [this](wxCommandEvent &) { PreferencesDialog dlg(this); dlg.ShowModal(); @@ -2253,7 +2444,7 @@ void MainFrame::init_menubar_as_editor() // Help menu auto helpMenu = generate_help_menu(); - + #ifndef __APPLE__ m_topbar->SetFileMenu(fileMenu); if (editMenu) @@ -2261,9 +2452,9 @@ void MainFrame::init_menubar_as_editor() if (viewMenu) m_topbar->AddDropDownSubMenu(viewMenu, _L("View")); //BBS add Preference - + append_menu_item( - m_topbar->GetTopMenu(), wxID_ANY, _L("Preferences") + "\tCtrl+P", _L(""), + m_topbar->GetTopMenu(), wxID_ANY, _L("Preferences") + "\tCtrl+P", "", [this](wxCommandEvent &) { PreferencesDialog dlg(this); dlg.ShowModal(); @@ -2286,9 +2477,12 @@ void MainFrame::init_menubar_as_editor() m_menubar->Append(editMenu, wxString::Format("&%s", _L("Edit"))); if (viewMenu) m_menubar->Append(viewMenu, wxString::Format("&%s", _L("View"))); + /*if (publishMenu) + m_menubar->Append(publishMenu, wxString::Format("&%s", _L("3D Models")));*/ if (helpMenu) m_menubar->Append(helpMenu, wxString::Format("&%s", _L("Help"))); SetMenuBar(m_menubar); + #endif #ifdef _MSW_DARK_MODE @@ -2308,6 +2502,18 @@ void MainFrame::init_menubar_as_editor() #endif // __APPLE__ } +void MainFrame::show_publish_button(bool show) +{ + if (!m_menubar) return; + + if (show){ + m_menubar->Insert(4, publishMenu, wxString::Format("&%s", _L("3D Models"))); + } + else { + m_menubar->Remove(4); + } +} + void MainFrame::open_menubar_item(const wxString& menu_name,const wxString& item_name) { if (m_menubar == nullptr) @@ -2357,7 +2563,7 @@ void MainFrame::init_menubar_as_gcodeviewer() append_menu_item(fileMenu, wxID_ANY, _L("Export &Toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"), [this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr, [this]() {return can_export_toolpaths(); }, this); - append_menu_item(fileMenu, wxID_ANY, _L("Open &PrusaSlicer") + dots, _L("Open PrusaSlicer"), + append_menu_item(fileMenu, wxID_ANY, _L("Open &Studio") + dots, _L("Open Studio"), [](wxCommandEvent&) { start_new_slicer(); }, "", nullptr, []() {return true; }, this); fileMenu->AppendSeparator(); @@ -2445,7 +2651,7 @@ void MainFrame::export_config() }, false); if (!files.empty()) m_last_config = from_u8(files.back()); - MessageDialog dlg(this, wxString::Format(_L_PLURAL("There is %d config exported. (Only non-system configs)", + MessageDialog dlg(this, wxString::Format(_L_PLURAL("There is %d config exported. (Only non-system configs)", "There are %d configs exported. (Only non-system configs)", files.size()), files.size()), _L("Export result"), wxOK); dlg.ShowModal(); @@ -2485,7 +2691,7 @@ void MainFrame::load_config_file() wxGetApp().app_config->update_config_dir(get_dir_name(cfiles.back())); wxGetApp().load_current_presets(); } - MessageDialog dlg2(this, wxString::Format(_L_PLURAL("There is %d config imported. (Only non-system and compatible configs)", + 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); dlg2.ShowModal(); @@ -2653,12 +2859,12 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) if (m_tabpanel->GetSelection() != (int)new_selection) m_tabpanel->SetSelection(new_selection); #ifdef _MSW_DARK_MODE - if (wxGetApp().tabs_as_menu()) { + /*if (wxGetApp().tabs_as_menu()) { if (Tab* cur_tab = dynamic_cast(m_tabpanel->GetPage(new_selection))) update_marker_for_tabs_menu((m_layout == ESettingsLayout::Old ? m_menubar : m_settings_dialog.menubar()), cur_tab->title(), m_layout == ESettingsLayout::Old); else if (tab == 0 && m_layout == ESettingsLayout::Old) m_plater->get_current_canvas3D()->render(); - } + }*/ #endif if (tab == MainFrame::tp3DEditor && m_layout == ESettingsLayout::Old) m_plater->canvas3D()->render(); @@ -2739,7 +2945,7 @@ void MainFrame::on_config_changed(DynamicPrintConfig* config) const void MainFrame::set_print_button_to_default(PrintSelectType select_type) { if (select_type == PrintSelectType::ePrintPlate) { - m_print_btn->SetLabel(_L("Print")); + m_print_btn->SetLabel(_L("Print plate")); m_print_select = ePrintPlate; if (m_print_enable) m_print_enable = get_enable_print_status(); @@ -2851,7 +3057,7 @@ void MainFrame::open_recent_project(size_t file_id, wxString const & filename) } else { - MessageDialog msg(this, _L("The project is no longer available."), _L("Error"), wxYES | wxYES_DEFAULT); + MessageDialog msg(this, _L("The project is no longer available."), _L("Error"), wxOK | wxYES_DEFAULT); if (msg.ShowModal() == wxID_YES) { m_recent_projects.RemoveFileFromHistory(file_id); @@ -3010,7 +3216,7 @@ std::string MainFrame::get_dir_name(const wxString &full_name) const // ---------------------------------------------------------------------------- SettingsDialog::SettingsDialog(MainFrame* mainframe) -:DPIFrame(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog"), +:DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "settings_dialog"), //: DPIDialog(mainframe, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _L("Settings"), wxDefaultPosition, wxDefaultSize, // wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX, "settings_dialog"), m_main_frame(mainframe) @@ -3045,9 +3251,9 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe) #ifdef _MSW_DARK_MODE if (wxGetApp().tabs_as_menu()) { // menubar - m_menubar = new wxMenuBar(); - add_tabs_as_menu(m_menubar, mainframe, this); - this->SetMenuBar(m_menubar); + //m_menubar = new wxMenuBar(); + //add_tabs_as_menu(m_menubar, mainframe, this); + //this->SetMenuBar(m_menubar); } #endif diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 94841f09be..0a0c295615 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -66,7 +66,7 @@ struct PresetTab { // SettingsDialog // ---------------------------------------------------------------------------- -class SettingsDialog : public DPIFrame//DPIDialog +class SettingsDialog : public DPIDialog//DPIDialog { //wxNotebook* m_tabpanel { nullptr }; Notebook* m_tabpanel{ nullptr }; @@ -91,7 +91,9 @@ class MainFrame : public DPIFrame wxString m_qs_last_input_file = wxEmptyString; wxString m_qs_last_output_file = wxEmptyString; wxString m_last_config = wxEmptyString; + wxMenuBar* m_menubar{ nullptr }; + wxMenu* publishMenu{ nullptr }; #if 0 wxMenuItem* m_menu_item_repeat { nullptr }; // doesn't used now @@ -114,6 +116,8 @@ class MainFrame : public DPIFrame bool can_export_toolpaths() const; bool can_export_supports() const; bool can_export_gcode() const; + bool can_export_all_gcode() const; + bool can_print_3mf() const; bool can_send_gcode() const; //bool can_export_gcode_sd() const; //bool can_eject() const; @@ -176,6 +180,9 @@ class MainFrame : public DPIFrame eSlicePlate = 1, }; + //jump to editor under preview only mode + bool preview_only_to_editor = false; + protected: virtual void on_dpi_changed(const wxRect &suggested_rect) override; virtual void on_sys_color_changed() override; @@ -185,6 +192,21 @@ protected: #endif public: + + //BBS GUI refactor + enum PrintSelectType + { + ePrintAll = 0, + ePrintPlate = 1, + eExportSlicedFile = 2, + eExportGcode = 3, + eSendGcode = 4, + eSendToPrinter = 5, + eSendToPrinterAll = 6, + eUploadGcode = 7, + eExportAllSlicedFile = 8 + }; + MainFrame(); ~MainFrame() = default; @@ -197,18 +219,7 @@ public: tpPreview = 2, tpMonitor = 3, tpProject = 4, - }; - - //BBS GUI refactor - enum PrintSelectType - { - ePrintAll = 0, - ePrintPlate = 1, - eExportSlicedFile = 2, - eExportGcode = 3, - eSendGcode = 4, - eSendToPrinter = 5, - eUploadGcode = 6 + toDebugTool = 5, }; //BBS: add slice&&print status update logic @@ -232,10 +243,11 @@ public: BBLTopbar* topbar() { return m_topbar; } void update_title(); + void show_publish_button(bool show); void update_title_colour_after_set_title(); void show_option(bool show); - void init_tabpanel(); + void init_tabpanel(); void create_preset_tabs(); //BBS: GUI refactor void add_created_tab(Tab* panel, const std::string& bmp_name = ""); @@ -282,6 +294,8 @@ public: void load_config(const DynamicPrintConfig& config); //BBS: jump to monitor void jump_to_monitor(std::string dev_id = ""); + //BBS: hint when jump to 3Deditor under preview only mode + bool preview_only_hint(); // Select tab in m_tabpanel // When tab == -1, will be selected last selected tab //BBS: GUI refactor @@ -366,6 +380,7 @@ public: wxDECLARE_EVENT(EVT_HTTP_ERROR, wxCommandEvent); wxDECLARE_EVENT(EVT_USER_LOGIN, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPDATE_PRESET_CB, SimpleEvent); } // GUI } //Slic3r diff --git a/src/slic3r/GUI/MarkdownTip.cpp b/src/slic3r/GUI/MarkdownTip.cpp index cb62678d23..f4c2b919f6 100644 --- a/src/slic3r/GUI/MarkdownTip.cpp +++ b/src/slic3r/GUI/MarkdownTip.cpp @@ -81,6 +81,16 @@ MarkdownTip::MarkdownTip() _timer = new wxTimer; _timer->Bind(wxEVT_TIMER, &MarkdownTip::OnTimer, this); + + Bind(EVT_WEBVIEW_RECREATED, [this](auto &evt) { + Hide(); + _lastTip.clear(); +#ifdef __WXMSW__ + _tipView = dynamic_cast(evt.GetEventObject()); + GetSizer()->Add(_tipView, wxSizerFlags().Expand().Proportion(1)); + Layout(); +#endif + }); } MarkdownTip::~MarkdownTip() { delete _timer; } @@ -226,9 +236,9 @@ void MarkdownTip::RunScript(std::string const& script) wxWebView* MarkdownTip::CreateTipView(wxWindow* parent) { wxWebView *tipView = WebView::CreateWebView(parent, ""); - tipView->Bind(wxEVT_WEBVIEW_LOADED, &MarkdownTip::OnLoaded, this); - tipView->Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &MarkdownTip::OnTitleChanged, this); - tipView->Bind(wxEVT_WEBVIEW_ERROR, &MarkdownTip::OnError, this); + Bind(wxEVT_WEBVIEW_LOADED, &MarkdownTip::OnLoaded, this); + Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &MarkdownTip::OnTitleChanged, this); + Bind(wxEVT_WEBVIEW_ERROR, &MarkdownTip::OnError, this); return tipView; } diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index ca5e0066eb..d7de0fe418 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -40,7 +40,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) b->SetTextColor(StateColor( std::make_pair(0x3B4446, (int) StateColor::Checked), std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered), - std::make_pair(0xACACAC, (int) StateColor::Normal) + std::make_pair(0xABACAC, (int) StateColor::Normal) )); } @@ -95,11 +95,13 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) m_button_delete->SetTextColorNormal(wxColor("#FF6F00")); m_button_management->SetBorderWidth(0); m_button_management->SetBackgroundColorNormal(wxColor("#00AE42")); + m_button_management->SetTextColorNormal(*wxWHITE); + m_button_management->Enable(false); wxBoxSizer *manage_sizer = new wxBoxSizer(wxHORIZONTAL); manage_sizer->AddStretchSpacer(1); - manage_sizer->Add(m_button_delete, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 24)->Show(false); manage_sizer->Add(m_button_download, 0, wxALIGN_CENTER_VERTICAL)->Show(false); + manage_sizer->Add(m_button_delete, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 24)->Show(false); manage_sizer->Add(m_button_management, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 24); m_manage_panel->SetSizer(manage_sizer); top_sizer->Add(m_manage_panel, 1, wxEXPAND); @@ -107,7 +109,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) sizer->Add(top_sizer, 0, wxEXPAND); m_image_grid = new ImageGrid(this); - m_image_grid->SetStatus(m_bmp_failed.bmp(), _L("No printers.")); + m_image_grid->SetStatus(m_bmp_failed, _L("No printers.")); sizer->Add(m_image_grid, 1, wxEXPAND); SetSizer(sizer); @@ -124,13 +126,7 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) m_button_year->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked); m_button_month->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked); m_button_all->Bind(wxEVT_COMMAND_BUTTON_CLICKED, time_button_clicked); - - { - wxCommandEvent e(wxEVT_CHECKBOX); - auto b = m_button_all; - e.SetEventObject(b); - b->GetEventHandler()->ProcessEvent(e); - } + m_button_all->SetValue(true); // File type auto type_button_clicked = [this](wxEvent &e) { @@ -142,26 +138,12 @@ MediaFilePanel::MediaFilePanel(wxWindow * parent) return; m_image_grid->SetFileType(type); m_last_type = type; - { - wxCommandEvent e(wxEVT_CHECKBOX); - e.SetEventObject(m_button_timelapse); - m_button_timelapse->GetEventHandler()->ProcessEvent(e); - } - { - wxCommandEvent e(wxEVT_CHECKBOX); - e.SetEventObject(m_button_video); - m_button_video->GetEventHandler()->ProcessEvent(e); - } + m_button_timelapse->SetValue(!m_button_timelapse->GetValue()); + m_button_video->SetValue(!m_button_video->GetValue()); }; m_button_video->Bind(wxEVT_COMMAND_BUTTON_CLICKED, type_button_clicked); m_button_timelapse->Bind(wxEVT_COMMAND_BUTTON_CLICKED, type_button_clicked); - - { - wxCommandEvent e(wxEVT_CHECKBOX); - auto b = m_button_timelapse; - e.SetEventObject(b); - b->GetEventHandler()->ProcessEvent(e); - } + m_button_timelapse->SetValue(true); // File management m_button_management->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &e) { @@ -196,15 +178,17 @@ 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; m_lan_mode = obj->is_lan_mode_printer(); m_lan_ip = obj->is_function_supported(PrinterFunction::FUNC_LOCAL_TUNNEL) ? obj->dev_ip : ""; m_lan_passwd = obj->access_code; m_tutk_support = obj->is_function_supported(PrinterFunction::FUNC_REMOTE_TUNNEL); } else { - m_lan_mode = false; + m_supported = false; + m_lan_mode = false; m_lan_ip.clear(); m_lan_passwd.clear(); - m_tutk_support = true; + m_tutk_support = false; } if (machine == m_machine) return; @@ -218,9 +202,9 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) m_button_management->Enable(false); SetSelecting(false); if (m_machine.empty()) { - m_image_grid->SetStatus(m_bmp_failed.bmp(), _L("No printers.")); - } else if (m_lan_ip.empty() && (m_lan_mode && !m_tutk_support)) { - m_image_grid->SetStatus(m_bmp_failed.bmp(), _L("Not supported.")); + m_image_grid->SetStatus(m_bmp_failed, _L("No printers.")); + } else if (!m_supported) { + m_image_grid->SetStatus(m_bmp_failed, _L("Not supported by this model of printer!")); } else { boost::shared_ptr fs(new PrinterFileSystem); fs->Attached(); @@ -249,19 +233,19 @@ void MediaFilePanel::SetMachineObject(MachineObject* obj) boost::shared_ptr fs(wfs.lock()); if (m_image_grid->GetFileSystem() != fs) // canceled return; - wxBitmap icon; + ScalableBitmap icon; wxString msg; switch (e.GetInt()) { - case PrinterFileSystem::Initializing: icon = m_bmp_loading.bmp(); msg = _L("Initializing..."); fetchUrl(boost::weak_ptr(fs)); break; - case PrinterFileSystem::Connecting: icon = m_bmp_loading.bmp(); msg = _L("Connecting..."); break; - case PrinterFileSystem::Failed: icon = m_bmp_failed.bmp(); msg = _L("Connect failed [%d]!"); break; - case PrinterFileSystem::ListSyncing: icon = m_bmp_loading.bmp(); msg = _L("Loading file list..."); break; - case PrinterFileSystem::ListReady: icon = m_bmp_empty.bmp(); msg = _L("No files"); break; + case PrinterFileSystem::Initializing: icon = m_bmp_loading; msg = _L("Initializing..."); break; + case PrinterFileSystem::Connecting: icon = m_bmp_loading; msg = _L("Connecting..."); break; + case PrinterFileSystem::Failed: icon = m_bmp_failed; msg = _L("Connect failed [%d]!"); break; + case PrinterFileSystem::ListSyncing: icon = m_bmp_loading; msg = _L("Loading file list..."); break; + case PrinterFileSystem::ListReady: icon = m_bmp_empty; msg = _L("No files"); break; } if (fs->GetCount() == 0) m_image_grid->SetStatus(icon, msg); - else - (void) 0; // TODO: show dialog + if (e.GetInt() == PrinterFileSystem::Initializing) + fetchUrl(boost::weak_ptr(fs)); }); if (IsShown()) fs->Start(); } @@ -285,8 +269,8 @@ void MediaFilePanel::Rescale() m_button_timelapse->Rescale(); m_type_panel->SetMinSize({-1, 48 * em_unit(this) / 10}); - m_button_video->Rescale(); - m_button_timelapse->Rescale(); + m_button_download->Rescale(); + m_button_delete->Rescale(); m_button_management->Rescale(); m_image_grid->Rescale(); @@ -309,28 +293,30 @@ void MediaFilePanel::modeChanged(wxCommandEvent& e1) if (m_last_mode == mode) return; ::Button* buttons[] = {m_button_all, m_button_month, m_button_year}; - wxCommandEvent e(wxEVT_CHECKBOX); auto b = buttons[m_last_mode]; b->SetFont(Label::Body_14); - e.SetEventObject(b); - b->GetEventHandler()->ProcessEvent(e); + b->SetValue(false); b = buttons[mode]; b->SetFont(Label::Head_14); - e.SetEventObject(b); - b->GetEventHandler()->ProcessEvent(e); + b->SetValue(true); m_last_mode = mode; } void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) { + boost::shared_ptr fs(wfs.lock()); + if (!fs || fs != m_image_grid->GetFileSystem()) return; if (!m_lan_ip.empty()) { - std::string url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; - boost::shared_ptr fs(wfs.lock()); - if (!fs || fs != m_image_grid->GetFileSystem()) return; + std::string url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; fs->SetUrl(url); return; } - if (m_lan_mode && !m_tutk_support) { // not support tutk + if (m_lan_mode ) { // not support tutk + m_image_grid->SetStatus(m_bmp_failed, _L("Not accessible in LAN-only mode!")); + return; + } + if (!m_tutk_support) { // not support tutk + m_image_grid->SetStatus(m_bmp_failed, _L("Missing LAN ip of printer!")); return; } NetworkAgent *agent = wxGetApp().getAgent(); @@ -341,7 +327,10 @@ void MediaFilePanel::fetchUrl(boost::weak_ptr wfs) CallAfter([this, url, wfs] { boost::shared_ptr fs(wfs.lock()); if (!fs || fs != m_image_grid->GetFileSystem()) return; - fs->SetUrl(url); + if (boost::algorithm::starts_with(url, "bambu:///")) + fs->SetUrl(url); + else + m_image_grid->SetStatus(m_bmp_failed, url.empty() ? _L("Network unreachable") : from_u8(url)); }); }); } diff --git a/src/slic3r/GUI/MediaFilePanel.h b/src/slic3r/GUI/MediaFilePanel.h index 6a07fe28d8..9f8ed0d1c5 100644 --- a/src/slic3r/GUI/MediaFilePanel.h +++ b/src/slic3r/GUI/MediaFilePanel.h @@ -70,7 +70,8 @@ private: std::string m_lan_ip; std::string m_lan_user; std::string m_lan_passwd; - bool m_lan_mode = false; + bool m_supported = false; + bool m_lan_mode = false; bool m_tutk_support = false; ImageGrid * m_image_grid = nullptr; diff --git a/src/slic3r/GUI/MediaPlayCtrl.cpp b/src/slic3r/GUI/MediaPlayCtrl.cpp index 0df1b9fcad..342c1405da 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.cpp +++ b/src/slic3r/GUI/MediaPlayCtrl.cpp @@ -5,6 +5,21 @@ #include "GUI_App.hpp" #include "libslic3r/AppConfig.hpp" #include "I18N.hpp" +#include "MsgDialog.hpp" +#include "DownloadProgressDialog.hpp" + +#undef pid_t +#include +#ifdef __WIN32__ +#include +#elif __APPLE__ +#include +#include +#else +#include +#include /* For mode constants */ +#include /* For O_* constants */ +#endif namespace Slic3r { namespace GUI { @@ -20,9 +35,9 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w m_button_play->SetCanFocus(false); m_label_status = new Label(this, "", LB_HYPERLINK); + m_label_status->SetForegroundColour(wxColour("#2C2C2E")); - m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto & e) { TogglePlay(); }); - + m_button_play->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](auto &e) { TogglePlay(); }); m_button_play->Bind(wxEVT_RIGHT_UP, [this](auto & e) { m_media_ctrl->Play(); }); m_label_status->Bind(wxEVT_LEFT_UP, [this](auto &e) { auto url = wxString::Format(L"https://wiki.bambulab.com/%s/software/bambu-studio/faq/live-view", L"en"); @@ -45,13 +60,8 @@ MediaPlayCtrl::MediaPlayCtrl(wxWindow *parent, wxMediaCtrl2 *media_ctrl, const w // m_next_retry = wxDateTime::Now(); //#endif - auto onShowHide = [this](auto &e) { - e.Skip(); - if (m_isBeingDeleted) return; - IsShownOnScreen() ? Play() : Stop(); - }; - parent->Bind(wxEVT_SHOW, onShowHide); - parent->GetParent()->GetParent()->Bind(wxEVT_SHOW, onShowHide); + parent->Bind(wxEVT_SHOW, &MediaPlayCtrl::on_show_hide, this); + parent->GetParent()->GetParent()->Bind(wxEVT_SHOW, &MediaPlayCtrl::on_show_hide, this); m_lan_user = "bblp"; m_lan_passwd = "bblp"; @@ -89,7 +99,14 @@ void MediaPlayCtrl::SetMachineObject(MachineObject* obj) return; } m_machine = machine; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl switch machine: " << m_machine; m_failed_retry = 0; + std::string stream_url; + if (get_stream_url(&stream_url)) { + m_streaming = boost::algorithm::contains(stream_url, "device=" + m_machine); + } else { + m_streaming = false; + } if (m_last_state != MEDIASTATE_IDLE) Stop(); if (m_next_retry.IsValid()) @@ -122,7 +139,7 @@ void MediaPlayCtrl::Play() m_button_play->SetIcon("media_stop"); SetStatus(_L("Initializing...")); - if (!m_lan_ip.empty()) { + if (!m_lan_ip.empty() && (!m_lan_mode || !m_lan_passwd.empty())) { m_url = "bambu:///local/" + m_lan_ip + ".?port=6000&user=" + m_lan_user + "&passwd=" + m_lan_passwd; m_last_state = MEDIASTATE_LOADING; SetStatus(_L("Loading...")); @@ -141,7 +158,7 @@ void MediaPlayCtrl::Play() m_cond.notify_all(); return; } - + if (m_lan_mode) { Stop(); SetStatus(m_lan_passwd.empty() @@ -152,14 +169,16 @@ void MediaPlayCtrl::Play() if (!m_tutk_support) { // not support tutk Stop(); - SetStatus(_L("Initialize failed (Not supported without remote video tunnel)!")); + SetStatus(m_lan_ip.empty() + ? _L("Initialize failed (Missing LAN ip of printer)!") + : _L("Initialize failed (Not supported by printer)!")); return; } NetworkAgent* agent = wxGetApp().getAgent(); if (agent) { agent->get_camera_url(m_machine, [this, m = m_machine](std::string url) { - BOOST_LOG_TRIVIAL(info) << "camera_url: " << url; + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl camera_url: " << url << ", machine: " << m_machine; CallAfter([this, m, url] { if (m != m_machine) return; m_url = url; @@ -178,6 +197,8 @@ void MediaPlayCtrl::Play() m_tasks.push_back(m_url); m_cond.notify_all(); } + } else { + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl drop late ttcode for state: " << m_last_state; } }); }); @@ -217,6 +238,84 @@ void MediaPlayCtrl::TogglePlay() } } +void MediaPlayCtrl::ToggleStream() +{ + std::string file_url = data_dir() + "/cameratools/url.txt"; + if (m_streaming) { + boost::nowide::ofstream file(file_url); + file.close(); + m_streaming = false; + return; + } else if (!boost::filesystem::exists(file_url)) { + boost::nowide::ofstream file(file_url); + file.close(); + } + std::string url; + if (!get_stream_url(&url)) { + // create stream pipeline + bool need_install = false; + if (!start_stream_service(&need_install)) { + if (!need_install) return; + auto res = MessageDialog(this->GetParent(), _L("Virtual Camera Tools is required for this task!\nDo you want to install them?"), _L("Info"), + wxOK | wxCANCEL).ShowModal(); + if (res == wxID_OK) { + // download tools + struct DownloadProgressDialog2 : DownloadProgressDialog + { + MediaPlayCtrl *ctrl; + DownloadProgressDialog2(MediaPlayCtrl *ctrl) : DownloadProgressDialog(_L("Downloading Virtual Camera Tools")), ctrl(ctrl) {} + struct UpgradeNetworkJob2 : UpgradeNetworkJob + { + UpgradeNetworkJob2(std::shared_ptr pri) : UpgradeNetworkJob(pri) { + name = "cameratools"; + package_name = "camera_tools.zip"; + } + }; + std::shared_ptr make_job(std::shared_ptr pri) override + { return std::make_shared(pri); } + void on_finish() override + { + wxGetApp().CallAfter([ctrl = this->ctrl] { ctrl->ToggleStream(); }); + EndModal(wxID_CLOSE); + } + }; + DownloadProgressDialog2 dlg(this); + dlg.ShowModal(); + } + return; + } + } + if (!url.empty() && wxGetApp().app_config->get("not_show_vcamera_stop_prev") != "1") { + MessageDialog dlg(this->GetParent(), _L("Another virtual camera is running.\nBambu Studio supports only a single virtual camera.\nDo you want to stop this virtual camera?"), _L("Warning"), + wxYES | wxCANCEL | wxICON_INFORMATION); + dlg.show_dsa_button(); + auto res = dlg.ShowModal(); + if (dlg.get_checkbox_state()) + wxGetApp().app_config->set("not_show_vcamera_stop_prev", "1"); + if (res == wxID_CANCEL) return; + } + NetworkAgent *agent = wxGetApp().getAgent(); + if (!agent) return; + agent->get_camera_url(m_machine, [this, m = m_machine](std::string url) { + BOOST_LOG_TRIVIAL(info) << "camera_url: " << url; + CallAfter([this, m, url] { + if (m != m_machine) return; + if (url.empty() || !boost::algorithm::starts_with(url, "bambu:///")) { + MessageDialog(this->GetParent(), wxString::Format(_L("Virtual camera initialize failed (%s)!"), url.empty() ? _L("Network unreachable") : from_u8(url)), _L("Information"), + wxICON_INFORMATION) + .ShowModal(); + return; + } + std::string file_url = data_dir() + "/cameratools/url.txt"; + boost::nowide::ofstream file(file_url); + auto url2 = encode_path((url + "&device=" + m).c_str()); + file.write(url2.c_str(), url2.size()); + file.close(); + m_streaming = true; + }); + }); +} + void MediaPlayCtrl::SetStatus(wxString const &msg2, bool hyperlink) { auto msg = wxString::Format(msg2, m_failed_code); @@ -236,6 +335,15 @@ void MediaPlayCtrl::SetStatus(wxString const &msg2, bool hyperlink) Layout(); } +bool MediaPlayCtrl::IsStreaming() const { return m_streaming; } + +void MediaPlayCtrl::on_show_hide(wxShowEvent &evt) +{ + evt.Skip(); + if (m_isBeingDeleted) return; + IsShownOnScreen() ? Play() : Stop(); +} + void MediaPlayCtrl::media_proc() { boost::unique_lock lock(m_mutex); @@ -270,6 +378,119 @@ void MediaPlayCtrl::media_proc() } } +#ifdef __WIN32__ +struct detach_process + : public ::boost::process::detail::windows::handler_base_ext +{ + template void on_setup(Executor &exec) const { exec.creation_flags |= ::boost::winapi::CREATE_NO_WINDOW_; } +}; +#endif + +bool MediaPlayCtrl::start_stream_service(bool *need_install) +{ +#ifdef __WIN32__ + std::string file_source = data_dir() + "\\cameratools\\bambu_source.exe"; + std::string file_ffmpeg = data_dir() + "\\cameratools\\ffmpeg.exe"; + std::string file_ff_cfg = data_dir() + "\\cameratools\\ffmpeg.cfg"; +#else + std::string file_source = data_dir() + "/cameratools/bambu_source"; + std::string file_ffmpeg = data_dir() + "/cameratools/ffmpeg"; + std::string file_ff_cfg = data_dir() + "/cameratools/ffmpeg.cfg"; +#endif + if (!boost::filesystem::exists(file_source) || !boost::filesystem::exists(file_ffmpeg) || !boost::filesystem::exists(file_ff_cfg)) { + if (need_install) *need_install = true; + return false; + } + std::string file_url = data_dir() + "/cameratools/url.txt"; + if (!boost::filesystem::exists(file_url)) { + boost::nowide::ofstream file(file_url); + file.close(); + } + wxString file_url2 = L"bambu:///camera/" + from_u8(file_url); + file_url2.Replace("\\", "/"); + file_url2 = wxURI(file_url2).BuildURI(); + try { + std::string configs; + boost::filesystem::load_string_file(file_ff_cfg, configs); + std::vector configss; + boost::algorithm::split(configss, configs, boost::algorithm::is_any_of("\r\n")); + configss.erase(std::remove(configss.begin(), configss.end(), std::string()), configss.end()); + boost::process::pipe intermediate; + boost::filesystem::path start_dir(boost::filesystem::path(data_dir()) / "plugins"); +#ifdef __WXMSW__ + start_dir = boost::filesystem::path(data_dir()) / "cameratools"; + std::string file_dll = data_dir() + "/cameratools/BambuSource.dll"; + 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::std_out > intermediate, detach_process(), + boost::process::start_dir(start_dir), boost::process::limit_handles); + boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::std_in < intermediate, detach_process(), boost::process::limit_handles); +#else + boost::filesystem::permissions(file_source, boost::filesystem::owner_exe | boost::filesystem::add_perms); + boost::filesystem::permissions(file_ffmpeg, boost::filesystem::owner_exe | boost::filesystem::add_perms); + // TODO: limit_handles has bugs on posix + boost::process::child process_source(file_source, file_url2.data().AsInternal(), boost::process::std_out > intermediate, + boost::process::start_dir(start_dir)); + boost::process::child process_ffmpeg(file_ffmpeg, configss, boost::process::std_in < intermediate); +#endif + process_source.detach(); + process_ffmpeg.detach(); + } catch (std::exception &e) { + BOOST_LOG_TRIVIAL(info) << "MediaPlayCtrl failed to start camera stream: " << e.what(); + return false; + } + return true; +} + +bool MediaPlayCtrl::get_stream_url(std::string *url) +{ +#ifdef __WIN32__ + HANDLE shm = ::OpenFileMapping(FILE_MAP_READ, FALSE, L"bambu_stream_url"); + if (shm == NULL) return false; + if (url) { + char *addr = (char *) MapViewOfFile(shm, FILE_MAP_READ, 0, 0, 0); + if (addr) { + *url = addr; + UnmapViewOfFile(addr); + url = nullptr; + } + } + CloseHandle(shm); +#elif __APPLE__ + std::string file_url = data_dir() + "/cameratools/url.txt"; + key_t key = ::ftok(file_url.c_str(), 1000); + int shm = ::shmget(key, 1024, 0); + if (shm == -1) return false; + struct shmid_ds ds; + ::shmctl(shm, IPC_STAT, &ds); + if (ds.shm_nattch == 0) { + return false; + } + if (url) { + char *addr = (char *) ::shmat(shm, nullptr, 0); + if (addr != (void*) -1) { + *url = addr; + ::shmdt(addr); + url = nullptr; + } + } +#else + int shm = ::shm_open("bambu_stream_url", O_RDONLY, 0); + if (shm == -1) return false; + if (url) { + char *addr = (char *) ::mmap(nullptr, 1024, PROT_READ, MAP_SHARED, shm, 0); + if (addr != MAP_FAILED) { + *url = addr; + ::munmap(addr, 1024); + url = nullptr; + } + } + ::close(shm); +#endif + return url == nullptr; +} + void MediaPlayCtrl::onStateChanged(wxMediaEvent& event) { auto last_state = m_last_state; @@ -284,7 +505,7 @@ void MediaPlayCtrl::onStateChanged(wxMediaEvent& event) return; } } - if (last_state == MEDIASTATE_IDLE && state == wxMEDIASTATE_STOPPED) { + if ((last_state == MEDIASTATE_IDLE || last_state == MEDIASTATE_INITIALIZING) && state == wxMEDIASTATE_STOPPED) { return; } if ((last_state == wxMEDIASTATE_PAUSED || last_state == wxMEDIASTATE_PLAYING) && diff --git a/src/slic3r/GUI/MediaPlayCtrl.h b/src/slic3r/GUI/MediaPlayCtrl.h index 6cf059eb2a..5bd5817c49 100644 --- a/src/slic3r/GUI/MediaPlayCtrl.h +++ b/src/slic3r/GUI/MediaPlayCtrl.h @@ -35,6 +35,10 @@ public: void SetMachineObject(MachineObject * obj); + bool IsStreaming() const; + + void ToggleStream(); + protected: void onStateChanged(wxMediaEvent & event); @@ -47,8 +51,14 @@ protected: void SetStatus(wxString const &msg, bool hyperlink = true); private: + void on_show_hide(wxShowEvent & evt); + void media_proc(); + static bool start_stream_service(bool *need_install = nullptr); + + static bool get_stream_url(std::string *url = nullptr); + private: static constexpr wxMediaState MEDIASTATE_IDLE = (wxMediaState) 3; static constexpr wxMediaState MEDIASTATE_INITIALIZING = (wxMediaState) 4; @@ -71,11 +81,12 @@ private: boost::condition_variable m_cond; boost::thread m_thread; + bool m_streaming = false; int m_failed_retry = 0; int m_failed_code = 0; wxDateTime m_next_retry; - ::Button * m_button_play; + ::Button *m_button_play; ::Label * m_label_status; }; diff --git a/src/slic3r/GUI/ModelMall.cpp b/src/slic3r/GUI/ModelMall.cpp new file mode 100644 index 0000000000..9ae80d2bea --- /dev/null +++ b/src/slic3r/GUI/ModelMall.cpp @@ -0,0 +1,233 @@ +#include "ModelMall.hpp" +#include "GUI_App.hpp" + +#include +#include +#include +#include "wx/evtloop.h" + +#include "libslic3r/Model.hpp" +#include "MainFrame.hpp" +#include "GUI_App.hpp" +#include "Plater.hpp" + +namespace Slic3r { +namespace GUI { + ModelMallDialog::ModelMallDialog(Plater* plater /*= nullptr*/) + :DPIFrame(nullptr, wxID_ANY, _L("3D Models"), wxDefaultPosition, wxDefaultSize, wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER) + { + // icon + std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetSize(MODEL_MALL_PAGE_SIZE); + SetMinSize(wxSize(MODEL_MALL_PAGE_SIZE.x / 4, MODEL_MALL_PAGE_SIZE.y / 4)); + + wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL); + + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL); + m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); + + m_web_control_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, MODEL_MALL_PAGE_CONTROL_SIZE, wxTAB_TRAVERSAL); + m_web_control_panel->SetBackgroundColour(*wxWHITE); + m_web_control_panel->SetSize(MODEL_MALL_PAGE_CONTROL_SIZE); + + + wxBoxSizer* m_sizer_web_control = new wxBoxSizer(wxHORIZONTAL); + + auto m_control_back = new ScalableButton(m_web_control_panel, wxID_ANY, "mall_control_back", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); + m_control_back->SetBackgroundColour(*wxWHITE); + m_control_back->SetSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_back->SetMinSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_back->SetMaxSize(wxSize(FromDIP(25), FromDIP(30))); + + m_control_back->Bind(wxEVT_LEFT_DOWN, &ModelMallDialog::on_back, this); + m_control_back->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_HAND));}); + m_control_back->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_ARROW));}); + + + auto m_control_forward = new ScalableButton(m_web_control_panel, wxID_ANY, "mall_control_forward", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); + m_control_forward->SetBackgroundColour(*wxWHITE); + m_control_forward->SetSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_forward->SetMinSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_forward->SetMaxSize(wxSize(FromDIP(25), FromDIP(30))); + + m_control_forward->Bind(wxEVT_LEFT_DOWN, &ModelMallDialog::on_forward, this); + m_control_forward->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_HAND)); }); + m_control_forward->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_ARROW)); }); + + auto m_control_refresh = new ScalableButton(m_web_control_panel, wxID_ANY, "mall_control_refresh", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true); + m_control_refresh->SetBackgroundColour(*wxWHITE); + m_control_refresh->SetSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_refresh->SetMinSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_refresh->SetMaxSize(wxSize(FromDIP(25), FromDIP(30))); + m_control_refresh->Bind(wxEVT_LEFT_DOWN, &ModelMallDialog::on_refresh, this); + m_control_refresh->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_HAND)); }); + m_control_refresh->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {SetCursor(wxCursor(wxCURSOR_ARROW)); }); + +#ifdef __APPLE__ + m_control_back->SetToolTip(_L("Click to return (Command + Left Arrow)")); + m_control_forward->SetToolTip(_L("Click to continue (Command + Right Arrow)")); +#else + m_control_back->SetToolTip(_L("Click to return (Alt + Left Arrow)")); + m_control_forward->SetToolTip(_L("Click to continue (Alt + Right Arrow)")); +#endif + + m_control_refresh->SetToolTip(_L("Refresh")); + /* auto m_textCtrl1 = new wxTextCtrl(m_web_control_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(600, 30), 0); + auto m_button1 = new wxButton(m_web_control_panel, wxID_ANY, wxT("GO"), wxDefaultPosition, wxDefaultSize, 0); + m_button1->Bind(wxEVT_BUTTON, [this,m_textCtrl1](auto& e) { + go_to_url(m_textCtrl1->GetValue()); + });*/ + + m_sizer_web_control->Add( m_control_back, 0, wxALIGN_CENTER | wxLEFT, FromDIP(26) ); + m_sizer_web_control->Add(m_control_forward, 0, wxALIGN_CENTER | wxLEFT, FromDIP(26)); + m_sizer_web_control->Add(m_control_refresh, 0, wxALIGN_CENTER | wxLEFT, FromDIP(26)); + //m_sizer_web_control->Add(m_button1, 0, wxALIGN_CENTER|wxLEFT, 5); + //m_sizer_web_control->Add(m_textCtrl1, 0, wxALIGN_CENTER|wxLEFT, 5); + + m_web_control_panel->SetSizer(m_sizer_web_control); + m_web_control_panel->Layout(); + m_sizer_web_control->Fit(m_web_control_panel); + + m_browser = WebView::CreateWebView(this, wxEmptyString); + if (m_browser == nullptr) { + wxLogError("Could not init m_browser"); + return; + } + + m_browser->SetSize(MODEL_MALL_PAGE_WEB_SIZE); + m_browser->SetMinSize(MODEL_MALL_PAGE_WEB_SIZE); + m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ModelMallDialog::OnScriptMessage, this, m_browser->GetId()); + + m_sizer_main->Add(m_web_control_panel, 0, wxEXPAND, 0); + m_sizer_main->Add(m_browser, 1, wxEXPAND, 0); + SetSizer(m_sizer_main); + Layout(); + Fit(); + + Centre(wxBOTH); + Bind(wxEVT_SHOW, &ModelMallDialog::on_show, this); + + Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) { + this->Hide(); + }); + } + + + ModelMallDialog::~ModelMallDialog() + { + } + + void ModelMallDialog::OnScriptMessage(wxWebViewEvent& evt) + { + try { + wxString strInput = evt.GetString(); + json j = json::parse(strInput); + + wxString strCmd = j["command"]; + + if (strCmd == "request_model_download") { + + std::string model_id = ""; + if (j["data"].contains("download_url")) + model_id = j["data"]["model_id"].get(); + + std::string profile_id = ""; + if (j["data"].contains("profile_id")) + profile_id = j["data"]["profile_id"].get(); + + std::string download_url = ""; + if (j["data"].contains("download_url")) + download_url = j["data"]["download_url"].get(); + + std::string filename = ""; + if (j["data"].contains("filename")) + filename = j["data"]["filename"].get(); + + if (download_url.empty()) return; + wxGetApp().plater()->request_model_download(download_url, filename); + } + else if(strCmd == "request_close_publish_window") { + this->Hide(); + } + + } + catch (std::exception& e) { + // wxMessageBox(e.what(), "json Exception", MB_OK); + } + } + + void ModelMallDialog::on_dpi_changed(const wxRect& suggested_rect) + { + } + + void ModelMallDialog::on_show(wxShowEvent& event) + { + wxGetApp().UpdateFrameDarkUI(this); + if (event.IsShown()) { + Centre(wxBOTH); + } + /*else { + go_to_url(m_url); + }*/ + event.Skip(); + } + + void ModelMallDialog::on_refresh(wxMouseEvent& evt) + { + if (!m_browser->GetCurrentURL().empty()) { + m_browser->Reload(); + } + } + + void ModelMallDialog::on_back(wxMouseEvent& evt) + { + if (m_browser->CanGoBack()) { + m_browser->GoBack(); + } + } + + void ModelMallDialog::on_forward(wxMouseEvent& evt) + { + if (m_browser->CanGoForward()) { + m_browser->GoForward(); + } + } + + void ModelMallDialog::go_to_url(wxString url) + { + //m_browser->LoadURL(url); + WebView::LoadUrl(m_browser, url); + } + + void ModelMallDialog::show_control(bool show) + { + m_web_control_panel->Show(show); + Layout(); + Fit(); + } + + void ModelMallDialog::go_to_mall(wxString url) + { + /*if (!url.empty() && m_homepage_url.empty()) { + m_homepage_url = url; + }*/ + if(url.empty())return; + m_url = url; + go_to_url(url); + } + + void ModelMallDialog::go_to_publish(wxString url) + { + /*if (!url.empty() && m_publish_url.empty()) { + m_publish_url = url; + }*/ + if(url.empty())return; + m_url = url; + go_to_url(url); + } + +} +} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/ModelMall.hpp b/src/slic3r/GUI/ModelMall.hpp new file mode 100644 index 0000000000..06b6ebbfe3 --- /dev/null +++ b/src/slic3r/GUI/ModelMall.hpp @@ -0,0 +1,68 @@ +#ifndef slic3r_ModelMall_hpp_ +#define slic3r_ModelMall_hpp_ + +#include "I18N.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if wxUSE_WEBVIEW_IE +#include "wx/msw/webview_ie.h" +#endif +#if wxUSE_WEBVIEW_EDGE +#include "wx/msw/webview_edge.h" +#endif + +#include "Widgets/WebView.hpp" +#include "wx/webviewarchivehandler.h" +#include "wx/webviewfshandler.h" + +#include +#include +#include "wxExtensions.hpp" +#include "Plater.hpp" +#include "Widgets/StepCtrl.hpp" +#include "Widgets/Button.hpp" + + +#define MODEL_MALL_PAGE_SIZE wxSize(FromDIP(1400 * 0.85), FromDIP(1040 * 0.75)) +#define MODEL_MALL_PAGE_CONTROL_SIZE wxSize(FromDIP(1400 * 0.85), FromDIP(40 * 0.75)) +#define MODEL_MALL_PAGE_WEB_SIZE wxSize(FromDIP(1400 * 0.85), FromDIP(1000 * 0.75)) + +namespace Slic3r { namespace GUI { + + class ModelMallDialog : public DPIFrame + { + public: + ModelMallDialog(Plater* plater = nullptr); + ~ModelMallDialog(); + + void OnScriptMessage(wxWebViewEvent& evt); + void on_dpi_changed(const wxRect& suggested_rect) override; + void on_show(wxShowEvent& event); + void on_back(wxMouseEvent& evt); + void on_forward(wxMouseEvent& evt); + void go_to_url(wxString url); + void show_control(bool show); + void go_to_mall(wxString url); + void go_to_publish(wxString url); + void on_refresh(wxMouseEvent& evt); + public: + wxPanel* m_web_control_panel{nullptr}; + wxWebView* m_browser{nullptr}; + wxString m_url; + }; + +}} // namespace Slic3r::GUI + +#endif diff --git a/src/slic3r/GUI/Monitor.cpp b/src/slic3r/GUI/Monitor.cpp index 3563ecde61..8a9687c628 100644 --- a/src/slic3r/GUI/Monitor.cpp +++ b/src/slic3r/GUI/Monitor.cpp @@ -195,7 +195,7 @@ MonitorPanel::~MonitorPanel() sizer_side_tools->Add(m_connection_info, 0, wxEXPAND, 0); sizer_side_tools->Add(m_side_tools, 1, wxEXPAND, 0); m_tabpanel = new Tabbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, sizer_side_tools, wxNB_LEFT | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME); - m_tabpanel->SetBackgroundColour(*wxWHITE); + m_tabpanel->SetBackgroundColour(wxColour("#FEFFFF")); m_tabpanel->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, [this](wxBookCtrlEvent& e) { ; }); @@ -245,6 +245,12 @@ wxWindow* MonitorPanel::create_side_tools() return panel; } +void MonitorPanel::on_sys_color_changed() +{ + m_status_info_panel->on_sys_color_changed(); + m_upgrade_panel->on_sys_color_changed(); +} + void MonitorPanel::msw_rescale() { init_bitmap(); @@ -315,9 +321,9 @@ void MonitorPanel::on_printer_clicked(wxMouseEvent &event) wxPoint rect = m_side_tools->ClientToScreen(wxPoint(0, 0)); if (!m_side_tools->is_in_interval()) { - wxPoint pos = m_side_tools->ClientToScreen(wxPoint(0, 0)); + wxPoint pos = m_side_tools->ClientToScreen(wxPoint(0, 0)); pos.y += m_side_tools->GetRect().height; - pos.x = pos.x < 0? 0:pos.x; + //pos.x = pos.x < 0? 0:pos.x; m_select_machine.Position(pos, wxSize(0, 0)); #ifdef __linux__ @@ -390,6 +396,7 @@ void MonitorPanel::update_all() //BBS check mqtt connections if user is login if (wxGetApp().is_user_login()) { + dev->check_pushing(); // check mqtt connection and reconnect if disconnected try { m_agent->refresh_connection(); @@ -506,7 +513,7 @@ void MonitorPanel::show_status(int status) return; last_status = status; - BOOST_LOG_TRIVIAL(trace) << "monitor: show_status = " << status; + BOOST_LOG_TRIVIAL(info) << "monitor: show_status = " << status; if (((status & (int) MonitorStatus::MONITOR_DISCONNECTED) != 0) || ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER) != 0)) { if ((status & (int) MonitorStatus::MONITOR_DISCONNECTED_SERVER)) @@ -535,11 +542,16 @@ void MonitorPanel::show_status(int status) } Freeze(); + + // update panels + m_status_info_panel->show_status(status); + m_hms_panel->show_status(status); + m_upgrade_panel->show_status(status); + if ((status & (int)MonitorStatus::MONITOR_NO_PRINTER) != 0) { set_default(); m_side_tools->set_none_printer_mode(); m_connection_info->Hide(); - m_status_info_panel->show_status(status); m_tabpanel->Refresh(); m_tabpanel->Layout(); #if !BBL_RELEASE_TO_PUBLIC @@ -556,8 +568,6 @@ void MonitorPanel::show_status(int status) m_side_tools->set_current_printer_signal(WifiSignal::NONE); set_default(); } - - m_status_info_panel->show_status(status); m_tabpanel->Refresh(); m_tabpanel->Layout(); } diff --git a/src/slic3r/GUI/Monitor.hpp b/src/slic3r/GUI/Monitor.hpp index 998004ea38..5586bcd163 100644 --- a/src/slic3r/GUI/Monitor.hpp +++ b/src/slic3r/GUI/Monitor.hpp @@ -130,7 +130,8 @@ public: void set_default(); wxWindow* create_side_tools(); - void msw_rescale(); + void on_sys_color_changed(); + void msw_rescale(); void select_machine(std::string machine_sn); void on_update_all(wxMouseEvent &event); diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index f90656410e..d1c05e5314 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -26,6 +26,7 @@ namespace Slic3r { namespace GUI { +wxDEFINE_EVENT(EVT_CHECKBOX_CHANGE, wxCommandEvent); MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, long style, wxBitmap bitmap) : DPIDialog(parent ? parent : dynamic_cast(wxGetApp().mainframe), wxID_ANY, title, wxDefaultPosition, wxSize(360, -1),wxDEFAULT_DIALOG_STYLE) @@ -59,11 +60,15 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he 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, 1, wxEXPAND, 5); main_sizer->Add(btn_sizer, 0, wxBOTTOM | wxRIGHT | wxEXPAND, BORDER); apply_style(style); - SetSizerAndFit(main_sizer); + wxGetApp().UpdateDlgDarkUI(this); } MsgDialog::~MsgDialog() @@ -71,6 +76,34 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he for (auto mb : m_buttons) { delete mb.second->buttondata ; delete mb.second; } } +void MsgDialog::show_dsa_button() +{ + m_checkbox_dsa = new CheckBox(this); + m_dsa_sizer->Add(m_checkbox_dsa, 0, wxALL | wxALIGN_CENTER, FromDIP(2)); + m_checkbox_dsa->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& e) { + auto event = wxCommandEvent(EVT_CHECKBOX_CHANGE); + event.SetInt(m_checkbox_dsa->GetValue()?1:0); + event.SetEventObject(this); + wxPostEvent(this, event); + e.Skip(); + }); + + auto m_text_dsa = new wxStaticText(this, wxID_ANY, _L("Don't show again"), wxDefaultPosition, wxDefaultSize, 0); + m_dsa_sizer->Add(m_text_dsa, 0, wxALL | wxALIGN_CENTER, FromDIP(2)); + m_text_dsa->SetFont(::Label::Body_13); + m_text_dsa->SetForegroundColour(StateColor::darkModeColorFor(wxColour("#323A3D"))); + btn_sizer->Layout(); + //Fit(); +} + +bool MsgDialog::get_checkbox_state() +{ + if (m_checkbox_dsa) { + return m_checkbox_dsa->GetValue(); + } + return false; +} + void MsgDialog::on_dpi_changed(const wxRect &suggested_rect) { if (m_buttons.size() > 0) { @@ -135,7 +168,7 @@ Button* MsgDialog::add_button(wxWindowID btn_id, bool set_focus /*= false*/, con ); StateColor btn_text_green( - std::pair(wxColour(255, 255, 255), StateColor::Normal) + std::pair(wxColour(255, 255, 254), StateColor::Normal) ); StateColor btn_bg_white( @@ -210,6 +243,7 @@ void MsgDialog::finalize() static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxString msg, bool monospaced_font = false, bool is_marked_msg = false) { wxHtmlWindow* html = new wxHtmlWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO); + html->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); // count lines in the message int msg_lines = 0; @@ -231,11 +265,7 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); wxFont monospace = wxGetApp().code_font(); -#if 1 wxColour text_clr = wxGetApp().get_label_clr_default(); -#else - wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); -#endif wxColour bgr_clr = parent->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); @@ -289,7 +319,7 @@ static void add_msg_content(wxWindow* parent, wxBoxSizer* content_sizer, wxStrin msg_escaped = std::string("
") + msg_escaped + "
"; html->SetPage("" + wxString::FromUTF8(msg_escaped.data()) + ""); content_sizer->Add(html, 1, wxEXPAND); - wxGetApp().UpdateDarkUI(html); + wxGetApp().UpdateDarkUIWin(html); } // ErrorDialog @@ -333,6 +363,7 @@ MessageDialog::MessageDialog(wxWindow* parent, { add_msg_content(this, content_sizer, message); finalize(); + wxGetApp().UpdateDlgDarkUI(this); } diff --git a/src/slic3r/GUI/MsgDialog.hpp b/src/slic3r/GUI/MsgDialog.hpp index c6dc0b5637..ec45776029 100644 --- a/src/slic3r/GUI/MsgDialog.hpp +++ b/src/slic3r/GUI/MsgDialog.hpp @@ -13,6 +13,7 @@ #include #include #include "Widgets/Button.hpp" +#include "Widgets/CheckBox.hpp" #include "BBLStatusBar.hpp" #include "BBLStatusBarSend.hpp" @@ -60,7 +61,9 @@ struct MsgDialog : DPIDialog MsgDialog &operator=(const MsgDialog &) = delete; virtual ~MsgDialog(); - virtual void on_dpi_changed(const wxRect &suggested_rect); + void show_dsa_button(); + bool get_checkbox_state(); + virtual void on_dpi_changed(const wxRect& suggested_rect); void SetButtonLabel(wxWindowID btn_id, const wxString& label, bool set_focus = false); protected: @@ -85,10 +88,12 @@ protected: wxFont boldfont; wxBoxSizer *content_sizer; wxBoxSizer *btn_sizer; + wxBoxSizer *m_dsa_sizer; wxStaticBitmap *logo; MsgButtonsHash m_buttons; + CheckBox* m_checkbox_dsa{nullptr}; }; - +wxDECLARE_EVENT(EVT_CHECKBOX_CHANGE, wxCommandEvent); // Generic error dialog, used for displaying exceptions class ErrorDialog : public MsgDialog @@ -125,21 +130,21 @@ public: #if 1 // Generic static line, used intead of wxStaticLine -class StaticLine: public wxTextCtrl -{ -public: - StaticLine( wxWindow* parent, - wxWindowID id = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxLI_HORIZONTAL, - const wxString& name = wxString::FromAscii(wxTextCtrlNameStr)) - : wxTextCtrl(parent, id, wxEmptyString, pos, size!=wxDefaultSize ? size : (style == wxLI_HORIZONTAL ? wxSize(10, 1) : wxSize(1, 10)), wxSIMPLE_BORDER, wxDefaultValidator, name) - { - this->Enable(false); - } - ~StaticLine() {} -}; +//class StaticLine: public wxTextCtrl +//{ +//public: +// StaticLine( wxWindow* parent, +// wxWindowID id = wxID_ANY, +// const wxPoint& pos = wxDefaultPosition, +// const wxSize& size = wxDefaultSize, +// long style = wxLI_HORIZONTAL, +// const wxString& name = wxString::FromAscii(wxTextCtrlNameStr)) +// : wxTextCtrl(parent, id, wxEmptyString, pos, size!=wxDefaultSize ? size : (style == wxLI_HORIZONTAL ? wxSize(10, 1) : wxSize(1, 10)), wxSIMPLE_BORDER, wxDefaultValidator, name) +// { +// this->Enable(false); +// } +// ~StaticLine() {} +//}; // Generic message dialog, used intead of wxMessageDialog class MessageDialog : public MsgDialog diff --git a/src/slic3r/GUI/NetworkTestDialog.cpp b/src/slic3r/GUI/NetworkTestDialog.cpp index ccf3c9a375..bc61230888 100644 --- a/src/slic3r/GUI/NetworkTestDialog.cpp +++ b/src/slic3r/GUI/NetworkTestDialog.cpp @@ -566,7 +566,7 @@ void NetworkTestDialog::start_test_oss_download() tmp_path += (boost::format(".%1%%2%") % get_current_pid() % ".tmp").str(); // get_url - std::string url = wxGetApp().get_plugin_url(app_config->get_country_code()); + 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); update_status(-1, "[test_oss_download]: url=" + url); diff --git a/src/slic3r/GUI/Notebook.cpp b/src/slic3r/GUI/Notebook.cpp index 717fdae55f..bc80e8862f 100644 --- a/src/slic3r/GUI/Notebook.cpp +++ b/src/slic3r/GUI/Notebook.cpp @@ -20,7 +20,15 @@ ButtonsListCtrl::ButtonsListCtrl(wxWindow *parent, wxBoxSizer* side_tools) : #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ - wxColour default_btn_bg("#3B4446"); // Gradient #414B4E + + wxColour default_btn_bg; +#ifdef __APPLE__ + default_btn_bg = wxColour("#3B4446"); // Gradient #414B4E +#else + default_btn_bg = wxColour("#2D2D30"); // Gradient #414B4E +#endif + + SetBackgroundColour(default_btn_bg); int em = em_unit(this);// Slic3r::GUI::wxGetApp().em_unit(); @@ -48,11 +56,13 @@ ButtonsListCtrl::ButtonsListCtrl(wxWindow *parent, wxBoxSizer* side_tools) : // BBS: disable custom paint //this->Bind(wxEVT_PAINT, &ButtonsListCtrl::OnPaint, this); + Bind(wxEVT_SYS_COLOUR_CHANGED, [this](auto& e){ + }); } void ButtonsListCtrl::OnPaint(wxPaintEvent&) { - Slic3r::GUI::wxGetApp().UpdateDarkUI(this); + //Slic3r::GUI::wxGetApp().UpdateDarkUI(this); const wxSize sz = GetSize(); wxPaintDC dc(this); @@ -139,8 +149,7 @@ void ButtonsListCtrl::SetSelection(int sel) std::pair{wxColour(59, 68, 70), (int) StateColor::Normal}); m_pageButtons[m_selection]->SetBackgroundColor(bg_color); StateColor text_color = StateColor( - std::pair{wxColour(255, 255, 255), (int) StateColor::Hovered}, - std::pair{wxColour(238,238, 238), (int) StateColor::Normal} + std::pair{wxColour(254,254, 254), (int) StateColor::Normal} ); m_pageButtons[m_selection]->SetSelected(false); m_pageButtons[m_selection]->SetTextColor(text_color); @@ -153,8 +162,7 @@ void ButtonsListCtrl::SetSelection(int sel) m_pageButtons[m_selection]->SetBackgroundColor(bg_color); StateColor text_color = StateColor( - std::pair{wxColour(255, 255, 255), (int) StateColor::Hovered}, - std::pair{wxColour(255, 255, 255), (int) StateColor::Normal} + std::pair{wxColour(254, 254, 254), (int) StateColor::Normal} ); m_pageButtons[m_selection]->SetSelected(true); m_pageButtons[m_selection]->SetTextColor(text_color); @@ -177,8 +185,7 @@ bool ButtonsListCtrl::InsertPage(size_t n, const wxString &text, bool bSelect /* btn->SetBackgroundColor(bg_color); StateColor text_color = StateColor( - std::pair{wxColour(255, 255, 255), (int) StateColor::Hovered}, - std::pair{wxColour(238,238, 238), (int) StateColor::Normal}); + std::pair{wxColour(254,254, 254), (int) StateColor::Normal}); btn->SetTextColor(text_color); btn->SetInactiveIcon(inactive_bmp_name); btn->SetSelected(false); @@ -241,4 +248,15 @@ wxString ButtonsListCtrl::GetPageText(size_t n) const //#endif // _WIN32 +void Notebook::Init() +{ + // We don't need any border as we don't have anything to separate the + // page contents from. + SetInternalBorder(0); + // No effects by default. + m_showEffect = m_hideEffect = wxSHOW_EFFECT_NONE; + + m_showTimeout = m_hideTimeout = 0; + SetBackgroundStyle(wxBG_STYLE_TRANSPARENT); +} diff --git a/src/slic3r/GUI/Notebook.hpp b/src/slic3r/GUI/Notebook.hpp index acf1510565..2cd975e9b3 100644 --- a/src/slic3r/GUI/Notebook.hpp +++ b/src/slic3r/GUI/Notebook.hpp @@ -391,19 +391,7 @@ protected: } private: - void Init() - { - // We don't need any border as we don't have anything to separate the - // page contents from. - SetInternalBorder(0); - - // No effects by default. - m_showEffect = - m_hideEffect = wxSHOW_EFFECT_NONE; - - m_showTimeout = - m_hideTimeout = 0; - } + void Init(); wxShowEffect m_showEffect, m_hideEffect; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 0da971614d..23a2f1c2eb 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -7,6 +7,7 @@ #include "ObjectDataViewModel.hpp" #include "GUI_ObjectList.hpp" #include "ParamsPanel.hpp" +#include "MainFrame.hpp" #include "libslic3r/Config.hpp" #include "format.hpp" @@ -144,6 +145,8 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, , m_evt_handler (evt_handler) , m_notification_start (GLCanvas3D::timestamp_now()) { + m_is_dark = wxGetApp().plater()->get_current_canvas3D()->get_dark_mode_status(); + m_ErrorColor = ImVec4(0.9, 0.36, 0.36, 1); m_WarnColor = ImVec4(0.99, 0.69, 0.455, 1); m_NormalColor = ImVec4(0.03, 0.6, 0.18, 1); @@ -157,6 +160,10 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, m_WindowRadius = 4.0f * wxGetApp().plater()->get_current_canvas3D()->get_scale(); } +void NotificationManager::PopNotification::on_change_color_mode(bool is_dark) +{ + m_is_dark = is_dark; +} void NotificationManager::PopNotification::use_bbl_theme() { @@ -187,9 +194,13 @@ void NotificationManager::PopNotification::use_bbl_theme() // OldStyle.Colors[ImGuiCol_WindowBg] = m_WindowBkgColor; // OldStyle.Colors[ImGuiCol_Text] = m_TextColor; - push_style_color(ImGuiCol_Border, m_CurrentColor, true, m_current_fade_opacity); + m_WindowBkgColor = m_is_dark ? ImVec4(45 / 255.f, 45 / 255.f, 49 / 255.f, 1.f) : ImVec4(1, 1, 1, 1); + m_TextColor = m_is_dark ? ImVec4(224 / 255.f, 224 / 255.f, 224 / 255.f, 1.f) : ImVec4(.2f, .2f, .2f, 1.0f); + m_HyperTextColor = m_is_dark ? ImVec4(0.03, 0.6, 0.18, 1) : ImVec4(0.03, 0.6, 0.18, 1); + 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); push_style_color(ImGuiCol_WindowBg, m_WindowBkgColor, true, m_current_fade_opacity); push_style_color(ImGuiCol_Text, m_TextColor, true, m_current_fade_opacity); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, m_WindowRadius / 4); } @@ -201,6 +212,7 @@ void NotificationManager::PopNotification::restore_default_theme() OldStyle.WindowRounding = m_DefaultTheme.mWindowRound; ImGui::PopStyleColor(3); + ImGui::PopStyleVar(); //OldStyle.Colors[ImGuiCol_WindowBg] = m_DefaultTheme.mWindowBkg; // OldStyle.Colors[ImGuiCol_Text] = m_DefaultTheme.mTextColor; // OldStyle.Colors[ImGuiCol_Border] = m_DefaultTheme.mBorderColor; @@ -540,8 +552,8 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); - std::string button_text; - button_text = ImGui::CloseNotifButton; + std::wstring button_text; + button_text = m_is_dark ? ImGui::CloseNotifDarkButton : ImGui::CloseNotifButton; //button_text = ImGui::PreferencesButton; //if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), @@ -549,9 +561,9 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img // true)) if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), ImVec2(win_pos.x, win_pos.y + 2 * m_line_height+10),true)) { - button_text = ImGui::CloseNotifHoverButton; + button_text = m_is_dark ? ImGui::CloseNotifHoverDarkButton : ImGui::CloseNotifHoverButton; } - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(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); @@ -586,12 +598,11 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img void NotificationManager::PopNotification::bbl_render_left_sign(ImGuiWrapper &imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { ImDrawList *draw_list = ImGui::GetWindowDrawList(); - - ImVec2 round_rect_pos = ImVec2(win_pos_x - win_size_x, win_pos_y); - ImVec2 round_rect_size = ImVec2(m_WindowRadius * 2, win_size_y); + ImVec2 round_rect_pos = ImVec2(win_pos_x - win_size_x + ImGui::GetStyle().WindowBorderSize, win_pos_y + ImGui::GetStyle().WindowBorderSize); + ImVec2 round_rect_size = ImVec2(m_WindowRadius * 2, win_size_y - 2 * ImGui::GetStyle().WindowBorderSize); ImVec2 rect_pos = round_rect_pos + ImVec2(m_WindowRadius, 0); - ImVec2 rect_size = ImVec2(m_WindowRadius + 2 * wxGetApp().plater()->get_current_canvas3D()->get_scale(), win_size_y); + ImVec2 rect_size = ImVec2(round_rect_size.x / 2, round_rect_size.y); ImU32 clr = ImGui::GetColorU32(ImVec4(m_CurrentColor.x, m_CurrentColor.y, m_CurrentColor.z, m_current_fade_opacity)); @@ -625,15 +636,15 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& //button - if part if treggered - std::string button_text; - button_text = ImGui::MinimalizeButton; + std::wstring button_text; + button_text = m_is_dark ? ImGui::MinimalizeDarkButton : ImGui::MinimalizeButton; if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1), ImVec2(win_pos_x, win_pos_y + m_window_height), true)) { - button_text = ImGui::MinimalizeHoverButton; + button_text = m_is_dark ? ImGui::MinimalizeHoverDarkButton : ImGui::MinimalizeHoverButton; } - ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str()); ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); ImGui::SetCursorPosX(m_window_width - m_line_height * 1.8f); ImGui::SetCursorPosY(m_window_height - button_size.y - 5); @@ -791,7 +802,7 @@ void NotificationManager::ExportFinishedNotification::render_text(ImGuiWrapper& ImGui::SetCursorPosY(starting_y + i * shift_y); imgui.text(line.c_str()); //hyperlink text - if ( i == 0 && !m_eject_pending) { + if ( i == 0 && !m_eject_pending && !m_export_dir_path.empty()) { render_hypertext(imgui, x_offset + ImGui::CalcTextSize(line.c_str()).x + ImGui::CalcTextSize(" ").x, starting_y, _u8L("Open Folder.")); } } @@ -1536,6 +1547,13 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : { } +void NotificationManager::on_change_color_mode(bool is_dark) { + m_is_dark = is_dark; + for (std::unique_ptr& notification : m_pop_notifications){ + notification->on_change_color_mode(is_dark); + } +} + void NotificationManager::push_notification(const NotificationType type, int timestamp) { auto it = std::find_if(std::begin(basic_notifications), std::end(basic_notifications), @@ -1582,7 +1600,9 @@ void NotificationManager::push_validate_error_notification(StringObjectException 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(); auto link = (mo || !error.opt_key.empty()) ? _u8L("Jump to") : ""; @@ -1592,15 +1612,37 @@ void NotificationManager::push_validate_error_notification(StringObjectException set_slicing_progress_hidden(); } -void NotificationManager::push_slicing_error_notification(const std::string& text) +void NotificationManager::push_slicing_error_notification(const std::string &text, ModelObject const *obj) { - set_all_slicing_errors_gray(false); - push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("Error:") + "\n" + text }, 0); + 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().obj_list()->select_items({{*iter, nullptr}}); + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } + return false; + } : std::function(); + auto link = callback ? _u8L("Jump to") : ""; + if (obj) link += std::string(" [") + obj->name + "]"; + set_all_slicing_errors_gray(false); + push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("Error:") + "\n" + text, link, callback }, 0); set_slicing_progress_hidden(); } -void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ObjectID oid, int warning_step, int warning_msg_id) +void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ModelObject const * obj, ObjectID oid, int warning_step, int warning_msg_id) { - NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotificationLevel, 0, _u8L("Warning:") + "\n" + text }; + 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().obj_list()->select_items({{*iter, nullptr}}); + wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor); + } + return false; + } : std::function(); + auto link = callback ? _u8L("Jump to") : ""; + if (obj) link += std::string(" [") + obj->name + "]"; + NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotificationLevel, 0, _u8L("Warning:") + "\n" + text, link, callback }; data.sub_msg_id = warning_msg_id; data.ori_text = text; @@ -1751,7 +1793,7 @@ void NotificationManager::set_simplify_suggestion_multiline(const ObjectID oid, void NotificationManager::push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable) { close_notification_of_type(NotificationType::ExportFinished); - NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Export ok.") + "\n" + path }; + NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Export successfully.") + "\n" + path }; push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0); set_slicing_progress_hidden(); } @@ -2095,11 +2137,11 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay { sort_notifications(); - float last_y = bottom_margin; + float last_y = bottom_margin * m_scale; for (const auto& notification : m_pop_notifications) { if (notification->get_state() != PopNotification::EState::Hidden) { - notification->render(canvas, last_y, m_move_from_overlay && !m_in_preview, overlay_width, right_margin * m_scale); + notification->render(canvas, last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale); if (notification->get_state() != PopNotification::EState::Finished) last_y = notification->get_top() + GAP_WIDTH; } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 41dd810b2d..b71f487d2b 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -166,6 +166,7 @@ public: NotificationManager(wxEvtHandler* evt_handler); ~NotificationManager(){} + void on_change_color_mode(bool is_dark); // init is called after canvas3d is created. Notifications added before init are not showed or updated void init() { m_initialized = true; } // Push a prefabricated notification from basic_notifications (see the table at the end of this file). @@ -188,9 +189,9 @@ public: void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host); void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); // Creates Slicing Error notification with a custom text and no fade out. - void push_slicing_error_notification(const std::string& text); + void push_slicing_error_notification(const std::string &text, ModelObject const *obj); // Creates Slicing Warning notification with a custom text and no fade out. - void push_slicing_warning_notification(const std::string& text, bool gray, ObjectID oid, int warning_step, int warning_msg_id); + void push_slicing_warning_notification(const std::string &text, bool gray, ModelObject const *obj, ObjectID oid, int warning_step, int warning_msg_id); // marks slicing errors as gray void set_all_slicing_errors_gray(bool g); // marks slicing warings as gray @@ -394,6 +395,7 @@ private: // 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); protected: // Call after every size change @@ -430,6 +432,8 @@ private: // used this function instead of reading directly m_data.duration. Some notifications might need to return changing value. virtual int get_duration() { return m_data.duration; } + bool m_is_dark = false; + const NotificationData m_data; // For reusing ImGUI windows. NotificationIDProvider &m_id_provider; @@ -821,6 +825,7 @@ private: } } + bool m_is_dark = false; // set by init(), until false notifications are only added not updated and frame is not requested after push bool m_initialized{ false }; // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index c9c32b0848..521f5b5592 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -48,6 +48,7 @@ OG_CustomCtrl::OG_CustomCtrl( wxWindow* parent, { if (!wxOSX) SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX + SetBackgroundColour(parent->GetBackgroundColour()); // BBS: new font m_font = Label::Body_14; @@ -332,7 +333,7 @@ void OG_CustomCtrl::OnPaint(wxPaintEvent&) // BBS: new layout if (!GetLabel().IsEmpty()) { dc.SetFont(Label::Head_16); - wxColour color("#283436"); + wxColour color = StateColor::darkModeColorFor("#283436"); draw_title(dc, {0, v_pos}, GetLabel(), &color, h_pos); dc.SetFont(m_font); } @@ -759,10 +760,10 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord h_pos, wxCoord v_pos) const std::vector