Merge branch 'main' into patch-4
@@ -172,17 +172,17 @@ jobs:
|
||||
# binary); this covers src/engine PRs with the PR-built binary. Runs in
|
||||
# parallel off build_linux's artifact so it doesn't lengthen the build leg.
|
||||
slice_check_linux:
|
||||
name: Slice check (Linux x86_64)
|
||||
name: Slice check (Linux aarch64)
|
||||
needs: build_linux
|
||||
if: ${{ !cancelled() && success() }}
|
||||
runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }}
|
||||
runs-on: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
- name: Download profile validator
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ github.sha }}-profile-validator-linux-x86_64
|
||||
name: ${{ github.sha }}-profile-validator-linux-aarch64
|
||||
path: validator-bin
|
||||
- name: Validate slice (expand custom g-code)
|
||||
timeout-minutes: 60
|
||||
|
||||
@@ -510,13 +510,15 @@ jobs:
|
||||
|
||||
# Ship the freshly-built validator so the parallel slice_check_linux job
|
||||
# (build_all.yml) can slice-sweep the shipped profiles with this PR's
|
||||
# engine. Stable sha-based name mirrors the tests artifact above so the
|
||||
# engine. Taken from the aarch64 leg so the sweep runs on arm64 (its
|
||||
# GitHub-hosted runner is free, and it also exercises the arm build).
|
||||
# Stable sha-based name mirrors the tests artifact above so the
|
||||
# downstream job downloads it by exact name.
|
||||
- name: Upload profile validator (for slice check)
|
||||
if: runner.os == 'Linux' && inputs.arch != 'aarch64'
|
||||
if: runner.os == 'Linux' && inputs.arch == 'aarch64'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ github.sha }}-profile-validator-linux-x86_64
|
||||
name: ${{ github.sha }}-profile-validator-linux-aarch64
|
||||
overwrite: true
|
||||
path: ./build/src/Release/OrcaSlicer_profile_validator
|
||||
retention-days: 5
|
||||
|
||||
@@ -8891,10 +8891,10 @@ msgid "Show incompatible/unsupported presets in the printer and filament dropdow
|
||||
msgstr "Zeigt inkompatible/nicht unterstützte Profile in den Dropdown-Listen für Drucker und Filament an. Diese Profile können nicht ausgewählt werden."
|
||||
|
||||
msgid "Experimental Features"
|
||||
msgstr ""
|
||||
msgstr "Experimentelle Funktionen"
|
||||
|
||||
msgid "Keep painted feature after mesh change"
|
||||
msgstr ""
|
||||
msgstr "Bemalte Funktionen nach Mesh-Änderung beibehalten"
|
||||
|
||||
msgid ""
|
||||
"Attempt to keep painted features (color/seam/support/fuzzy etc.) after changing the object mesh (such as cut/reload from disk/simplify/fix etc.)\n"
|
||||
@@ -9719,10 +9719,10 @@ msgid "Search in preset"
|
||||
msgstr "In Profilen suchen"
|
||||
|
||||
msgid "Synchronization of different extruder drives or nozzle volume types is not supported."
|
||||
msgstr ""
|
||||
msgstr "Die Synchronisierung verschiedener Extrudertypen oder Düsenvolumentypen wird nicht unterstützt."
|
||||
|
||||
msgid "Synchronize the modification of parameters to the corresponding parameters of another extruder."
|
||||
msgstr ""
|
||||
msgstr "Änderungen der Parameter mit den entsprechenden Parametern eines anderen Extruders synchronisieren."
|
||||
|
||||
msgid "Click to reset all settings to the last saved preset."
|
||||
msgstr "Klicken Sie hier, um alle Einstellungen auf die zuletzt gespeicherten Parameter zurückzusetzen."
|
||||
@@ -10018,13 +10018,13 @@ msgid "Chamber temperature"
|
||||
msgstr "Druckraum Temperatur"
|
||||
|
||||
msgid "Target chamber temperature, and the minimal chamber temperature at which printing should start"
|
||||
msgstr ""
|
||||
msgstr "Ziel-Druckraumtemperatur und die minimale Druckraumtemperatur, bei der der Druck beginnen sollte"
|
||||
|
||||
msgid "Target"
|
||||
msgstr ""
|
||||
msgstr "Ziel"
|
||||
|
||||
msgid "Minimal"
|
||||
msgstr ""
|
||||
msgstr "Minimal"
|
||||
|
||||
msgid "Print temperature"
|
||||
msgstr "Drucktemperatur"
|
||||
@@ -10047,7 +10047,7 @@ msgstr "Strukturierte kalte Druckplatte"
|
||||
|
||||
# TODO: Review, changed by lang refactor. PR 14254
|
||||
msgid "This is the bed temperature when the Textured Cool Plate is installed. A value of 0 means the filament does not support printing on the Textured Cool Plate."
|
||||
msgstr "Dies ist die Betttemperatur, wenn die kalte Druckplatte installiert ist. Ein Wert von 0 bedeutet, dass das Filament auf der texturierten kalten Druckplatte nicht unterstützt wird."
|
||||
msgstr "Dies ist die Betttemperatur, wenn die texturierte kalte Druckplatte installiert ist. Ein Wert von 0 bedeutet, dass das Filament auf der texturierten kalten Druckplatte nicht unterstützt wird."
|
||||
|
||||
# TODO: Review, changed by lang refactor. PR 14254
|
||||
msgid "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."
|
||||
@@ -10368,21 +10368,21 @@ msgstr "Nicht erneut für dieses Profil warnen"
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid "%s: %s"
|
||||
msgstr ""
|
||||
msgstr "%s: %s"
|
||||
|
||||
msgid "No modifications need to be copied."
|
||||
msgstr ""
|
||||
msgstr "Es müssen keine Änderungen kopiert werden."
|
||||
|
||||
msgid "Copy paramters"
|
||||
msgstr ""
|
||||
msgstr "Parameter kopieren"
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid "Modify paramters of %s"
|
||||
msgstr ""
|
||||
msgstr "Parameter von %s ändern"
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid "Do you want to modify the following parameters of the %s to that of the %s?"
|
||||
msgstr ""
|
||||
msgstr "Möchten Sie die folgenden Parameter von %s auf die von %s ändern?"
|
||||
|
||||
msgid "Click to reset current value and attach to the global value."
|
||||
msgstr "Klicken Sie hier, um den aktuellen Wert zurückzusetzen und ihn dem globalen Wert zuzuordnen."
|
||||
@@ -10528,10 +10528,10 @@ msgid "Capabilities"
|
||||
msgstr "Fähigkeiten"
|
||||
|
||||
msgid "Left: "
|
||||
msgstr ""
|
||||
msgstr "Links: "
|
||||
|
||||
msgid "Right: "
|
||||
msgstr ""
|
||||
msgstr "Rechts: "
|
||||
|
||||
msgid "Show all presets (including incompatible)"
|
||||
msgstr "Alle Profile anzeigen (auch inkompatible)"
|
||||
@@ -13887,7 +13887,7 @@ msgid "layer"
|
||||
msgstr "Schicht"
|
||||
|
||||
msgid "First layer fan speed"
|
||||
msgstr ""
|
||||
msgstr "Lüftergeschwindigkeit der ersten Schicht"
|
||||
|
||||
msgid ""
|
||||
"Sets an exact fan speed for the first layer, overriding all other cooling settings. Useful for protecting 3D-printed toolhead parts (e.g. Voron-style ABS/ASA ducts) from a hot bed. A small amount of airflow cools the ducts down, without using full cooling that may in certain conditions hurt first-layer adhesion.\n"
|
||||
@@ -13896,6 +13896,11 @@ msgid ""
|
||||
"Only available when \"No cooling for the first\" is 0.\n"
|
||||
"Set to -1 to disable it."
|
||||
msgstr ""
|
||||
"Legt eine genaue Lüftergeschwindigkeit für die erste Schicht fest und überschreibt alle anderen Kühlungseinstellungen. Nützlich zum Schutz von 3D-gedruckten Werkzeugkopfteilen (z.B. Voron-Style ABS/ASA-Düsen) vor einem heißen Bett. Eine kleine Menge Luftstrom kühlt die Düsen ab, ohne die volle Kühlung zu verwenden, die unter bestimmten Bedingungen die Haftung der ersten Schicht beeinträchtigen kann.\n"
|
||||
"Ab der zweiten Schicht wird die normale Kühlung wieder aufgenommen.\n"
|
||||
"Wenn auch \"Volle Lüfterdrehzahl ab Schicht\" eingestellt ist, steigt der Lüfter von diesem Wert in der ersten Schicht bis zu Ihrem Zielwert in der gewählten Schicht.\n"
|
||||
"Nur verfügbar, wenn \"Keine Kühlung für die erste\" 0 ist.\n"
|
||||
"Auf -1 setzen, um es zu deaktivieren."
|
||||
|
||||
msgid "Support interface fan speed"
|
||||
msgstr "Stützstruktur-Schnittstelle"
|
||||
@@ -16297,9 +16302,14 @@ msgid ""
|
||||
"\n"
|
||||
"Unlike the \"Target\" chamber temperature, this option does not emit any M141/M191 commands; it only exposes the value to your custom G-code. It should not exceed the \"Target\" chamber temperature."
|
||||
msgstr ""
|
||||
"Dies ist die Druckraumtemperatur, bei der der Druckvorgang beginnen soll, während der Druckraum weiterhin auf die \"Ziel\"-Druckraumtemperatur erhitzt wird. Zum Beispiel: Setzen Sie das Ziel auf 60 und das Minimum auf 50, um mit dem Drucken zu beginnen, sobald der Druckraum 50°C erreicht hat, ohne auf die vollen 60°C zu warten.\n"
|
||||
"\n"
|
||||
"Es wird eine G-Code-Variable namens chamber_minimal_temperature gesetzt, die an Ihr Druckstart-Makro oder ein Wärmespeicher-Makro übergeben werden kann, wie z.B.: PRINT_START (andere Variablen) CHAMBER_MIN_TEMP=[chamber_minimal_temperature].\n"
|
||||
"\n"
|
||||
"Im Gegensatz zur \"Ziel\"-Druckraumtemperatur sendet diese Option keine M141/M191-Befehle; sie stellt den Wert nur Ihrem benutzerdefinierten G-Code zur Verfügung. Sie sollte die \"Ziel\"-Druckraumtemperatur nicht überschreiten."
|
||||
|
||||
msgid "Chamber minimal temperature"
|
||||
msgstr ""
|
||||
msgstr "Minimale Druckraumtemperatur"
|
||||
|
||||
# TODO: Review, changed by lang refactor. PR 14254
|
||||
msgid "Nozzle temperature after the first layer"
|
||||
@@ -19110,130 +19120,132 @@ msgid "Connection to printers connected via the print host failed."
|
||||
msgstr "Die Verbindung zu den über den Druck-Host verbundenen Druckern ist fehlgeschlagen."
|
||||
|
||||
msgid "Detect Creality K-series printer"
|
||||
msgstr ""
|
||||
msgstr "Creality K-Serie Drucker erkennen"
|
||||
|
||||
msgid "Click Scan to look for K-series printers on your network."
|
||||
msgstr ""
|
||||
msgstr "Klicken Sie auf 'Scannen', um nach K-Serie Druckern in Ihrem Netzwerk zu suchen."
|
||||
|
||||
msgid "Use Selected"
|
||||
msgstr ""
|
||||
msgstr "Ausgewählten verwenden"
|
||||
|
||||
msgid "Scanning the LAN for K-series printers... this takes a few seconds."
|
||||
msgstr ""
|
||||
msgstr "Suche im LAN nach K-Serie Druckern... dies dauert einige Sekunden."
|
||||
|
||||
msgid "No K-series printers found. Make sure the printer is on the same network and not blocked by Wi-Fi client isolation, then click Scan again."
|
||||
msgstr ""
|
||||
msgstr "Keine K-Serie Drucker gefunden. Stellen Sie sicher, dass der Drucker im selben Netzwerk ist und nicht durch Wi-Fi-Client-Isolation blockiert wird, und klicken Sie dann erneut auf 'Scannen'."
|
||||
|
||||
#, c-format
|
||||
msgid "Found %zu Creality printer(s). Select one and click Use Selected."
|
||||
msgstr ""
|
||||
msgstr "Es wurden %zu Creality-Drucker gefunden. Wählen Sie einen aus und klicken Sie auf 'Ausgewählten verwenden'."
|
||||
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
msgstr "Aktiv"
|
||||
|
||||
msgid "Printers"
|
||||
msgstr ""
|
||||
msgstr "Drucker"
|
||||
|
||||
msgid "Processes"
|
||||
msgstr ""
|
||||
msgstr "Prozesse"
|
||||
|
||||
msgid "Show/Hide system information"
|
||||
msgstr ""
|
||||
msgstr "Systeminformationen anzeigen/verbergen"
|
||||
|
||||
msgid "Copy system information to clipboard"
|
||||
msgstr ""
|
||||
msgstr "Systeminformationen in die Zwischenablage kopieren"
|
||||
|
||||
msgid "We need information for diagnosing source of the issue. Check wiki page for detailed guide."
|
||||
msgstr ""
|
||||
msgstr "Wir benötigen Informationen zur Diagnose der Ursache des Problems. Überprüfen Sie die Wiki-Seite für eine detaillierte Anleitung."
|
||||
|
||||
msgid "Pack button collects project file and logs of current session onto a zip file."
|
||||
msgstr ""
|
||||
msgstr "Die Schaltfläche „Packen“ sammelt die Projektdatei und Protokolle der aktuellen Sitzung in einer ZIP-Datei."
|
||||
|
||||
msgid "Any additional visual examples like images or screen recordings might be helpful while reporting the issue."
|
||||
msgstr ""
|
||||
msgstr "Zusätzliche visuelle Beispiele wie Bilder oder Bildschirmaufnahmen könnten beim Melden des Problems hilfreich sein."
|
||||
|
||||
msgid "Report issue"
|
||||
msgstr ""
|
||||
msgstr "Problem melden"
|
||||
|
||||
msgid "Pack"
|
||||
msgstr ""
|
||||
msgstr "Packen"
|
||||
|
||||
msgid "Cleans and rebuilds system profiles cache on next launch"
|
||||
msgstr ""
|
||||
msgstr "Bereinigt und erstellt den Systemprofil-Cache beim nächsten Start neu"
|
||||
|
||||
msgid "Clean system profiles cache"
|
||||
msgstr ""
|
||||
msgstr "Systemprofil-Cache bereinigen"
|
||||
|
||||
msgid "Clean"
|
||||
msgstr ""
|
||||
msgstr "Bereinigen"
|
||||
|
||||
msgid "Loaded profiles overview"
|
||||
msgstr ""
|
||||
msgstr "Übersicht der geladenen Profile"
|
||||
|
||||
msgid "This section shows information for loaded profiles"
|
||||
msgstr ""
|
||||
msgstr "Dieser Abschnitt zeigt Informationen zu den geladenen Profilen"
|
||||
|
||||
msgid "Exports detailed overview of loaded profiles in json format"
|
||||
msgstr ""
|
||||
msgstr "Exportiert eine detaillierte Übersicht der geladenen Profile im JSON-Format"
|
||||
|
||||
msgid "Configurations folder"
|
||||
msgstr ""
|
||||
msgstr "Konfigurationsordner"
|
||||
|
||||
msgid "Opens configurations folder"
|
||||
msgstr ""
|
||||
msgstr "Öffnet den Konfigurationsordner"
|
||||
|
||||
msgid "Log level"
|
||||
msgstr ""
|
||||
msgstr "Protokollstufe"
|
||||
|
||||
msgid "Stored logs"
|
||||
msgstr ""
|
||||
msgstr "Gespeicherte Protokolle"
|
||||
|
||||
msgid "Packs all stored logs onto a zip file."
|
||||
msgstr ""
|
||||
msgstr "Packt alle gespeicherten Protokolle in eine ZIP-Datei."
|
||||
|
||||
msgid "Profiles"
|
||||
msgstr ""
|
||||
msgstr "Profile"
|
||||
|
||||
msgid "Select NO to close dialog and review project"
|
||||
msgstr ""
|
||||
msgstr "Wählen Sie NEIN, um das Dialogfeld zu schließen und das Projekt zu überprüfen"
|
||||
|
||||
msgid "No project file on current session. Only logs will be included to package"
|
||||
msgstr ""
|
||||
msgstr "Keine Projektdatei in der aktuellen Sitzung. Nur Protokolle werden in das Paket aufgenommen"
|
||||
|
||||
msgid "Select NO to close dialog and review project."
|
||||
msgstr ""
|
||||
msgstr "Wählen Sie NEIN, um das Dialogfeld zu schließen und das Projekt zu überprüfen."
|
||||
|
||||
msgid "Please make sure any instances of OrcaSlicer are not running"
|
||||
msgstr ""
|
||||
msgstr "Bitte stellen Sie sicher, dass keine Instanzen von OrcaSlicer ausgeführt werden."
|
||||
|
||||
msgid "System folder cannot be deleted because some files are in use by another application. Please close any applications using these files and try again."
|
||||
msgstr ""
|
||||
msgstr "Der Systemordner kann nicht gelöscht werden, da einige Dateien von einer anderen Anwendung verwendet werden. Bitte schließen Sie alle Anwendungen, die diese Dateien verwenden, und versuchen Sie es erneut."
|
||||
|
||||
msgid "Failed to delete system folder..."
|
||||
msgstr ""
|
||||
msgstr "Systemordner konnte nicht gelöscht werden..."
|
||||
|
||||
msgid "Failed to determine executable path."
|
||||
msgstr ""
|
||||
msgstr "Konnte den Pfad zur ausführbaren Datei nicht bestimmen."
|
||||
|
||||
msgid "Failed to launch a new instance."
|
||||
msgstr ""
|
||||
msgstr "Konnte keine neue Instanz starten."
|
||||
|
||||
msgid "log(s)"
|
||||
msgstr ""
|
||||
msgstr "Protokoll(e)"
|
||||
|
||||
msgid "Choose where to save the exported JSON file"
|
||||
msgstr ""
|
||||
msgstr "Wählen Sie, wo die exportierte JSON-Datei gespeichert werden soll"
|
||||
|
||||
msgid ""
|
||||
"Export failed\n"
|
||||
"Please check write permissions or file in use by another application"
|
||||
msgstr ""
|
||||
"Export fehlgeschlagen\n"
|
||||
"Bitte überprüfen Sie die Schreibberechtigungen oder ob die Datei von einer anderen Anwendung verwendet wird."
|
||||
|
||||
msgid "Choose where to save the exported ZIP file"
|
||||
msgstr ""
|
||||
msgstr "Wählen Sie, wo die exportierte ZIP-Datei gespeichert werden soll"
|
||||
|
||||
msgid "File already exists. Overwrite?"
|
||||
msgstr ""
|
||||
msgstr "Datei existiert bereits. Überschreiben?"
|
||||
|
||||
msgid "3DPrinterOS Cloud upload options"
|
||||
msgstr "3DPrinterOS Cloud-Upload-Optionen"
|
||||
@@ -19318,17 +19330,17 @@ msgid "Could not connect to MKS"
|
||||
msgstr "Konnte keine Verbindung zu MKS herstellen"
|
||||
|
||||
msgid "Connection to Moonraker is working correctly."
|
||||
msgstr ""
|
||||
msgstr "Verbindung zu Moonraker funktioniert korrekt."
|
||||
|
||||
msgid "Could not connect to Moonraker"
|
||||
msgstr ""
|
||||
msgstr "Konnte keine Verbindung zu Moonraker herstellen"
|
||||
|
||||
msgid "The host responded but it doesn't look like Moonraker (missing result.klippy_state)."
|
||||
msgstr ""
|
||||
msgstr "Der Host hat geantwortet, sieht aber nicht wie Moonraker aus (fehlender result.klippy_state)."
|
||||
|
||||
#, c-format, boost-format
|
||||
msgid "Could not parse Moonraker server response: %s"
|
||||
msgstr ""
|
||||
msgstr "Konnte die Moonraker-Serverantwort nicht analysieren: %s"
|
||||
|
||||
msgid "Connection to OctoPrint is working correctly."
|
||||
msgstr "Verbindung zu OctoPrint funktioniert korrekt."
|
||||
|
||||
@@ -287,4 +287,6 @@ src/slic3r/GUI/DownloaderFileGet.cpp
|
||||
src/slic3r/GUI/FileArchiveDialog.cpp
|
||||
src/slic3r/GUI/PrinterCloudAuthDialog.cpp
|
||||
src/slic3r/GUI/PrinterWebViewHandler.cpp
|
||||
src/slic3r/GUI/AMSDryControl.cpp
|
||||
src/slic3r/GUI/AMSDryControl.hpp
|
||||
src/libslic3r/PresetBundle.cpp
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="9.35422" fill="#E14747" stroke="#E14747" stroke-width="1.29157"/>
|
||||
<rect x="11" y="6" width="2" height="9" rx="1" fill="white"/>
|
||||
<rect x="11" y="16" width="2" height="2" rx="1" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 321 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.80005 12.3C1.80005 6.83238 6.23243 2.4 11.7 2.4C17.1677 2.4 21.6 6.83238 21.6 12.3C21.6 17.7676 17.1677 22.2 11.7 22.2C6.23243 22.2 1.80005 17.7676 1.80005 12.3Z" fill="#009688"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.7742 8.66235C18.0746 8.9415 18.0918 9.41131 17.8126 9.7117L12.2128 15.7376C11.5275 16.4751 10.36 16.4751 9.67461 15.7376L6.82482 12.6709C6.54567 12.3706 6.56289 11.9007 6.86328 11.6216C7.16367 11.3424 7.63348 11.3597 7.91263 11.66L10.7624 14.7267C10.8603 14.832 11.0271 14.832 11.125 14.7267L16.7248 8.70081C17.004 8.40042 17.4738 8.3832 17.7742 8.66235Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 759 B |
|
After Width: | Height: | Size: 103 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.3125 0.7125V2.6125C8.3125 3.00734 7.99484 3.325 7.6 3.325C7.20516 3.325 6.8875 3.00734 6.8875 2.6125V0.7125C6.8875 0.317656 7.20516 0 7.6 0C7.99484 0 8.3125 0.317656 8.3125 0.7125ZM12.9734 3.23297L11.6286 4.57781C11.3495 4.85687 10.8983 4.85687 10.6222 4.57781C10.3461 4.29875 10.3431 3.8475 10.6222 3.57141L11.967 2.22656C12.2461 1.9475 12.6973 1.9475 12.9734 2.22656C13.2495 2.50562 13.2525 2.95688 12.9734 3.23297ZM3.23297 2.22656L4.57781 3.57141C4.85687 3.85047 4.85687 4.30172 4.57781 4.57781C4.29875 4.85391 3.8475 4.85687 3.57141 4.57781L2.22656 3.23297C1.9475 2.95391 1.9475 2.50266 2.22656 2.22656C2.50562 1.95047 2.95688 1.9475 3.23297 2.22656ZM0.7125 6.8875H2.6125C3.00734 6.8875 3.325 7.20516 3.325 7.6C3.325 7.99484 3.00734 8.3125 2.6125 8.3125H0.7125C0.317656 8.3125 0 7.99484 0 7.6C0 7.20516 0.317656 6.8875 0.7125 6.8875ZM12.5875 6.8875H14.4875C14.8823 6.8875 15.2 7.20516 15.2 7.6C15.2 7.99484 14.8823 8.3125 14.4875 8.3125H12.5875C12.1927 8.3125 11.875 7.99484 11.875 7.6C11.875 7.20516 12.1927 6.8875 12.5875 6.8875ZM4.57781 11.6316L3.23297 12.9734C2.95391 13.2525 2.50266 13.2525 2.22656 12.9734C1.95047 12.6944 1.9475 12.2431 2.22656 11.967L3.57141 10.6222C3.85047 10.3431 4.30172 10.3431 4.57781 10.6222C4.85391 10.9012 4.85687 11.3525 4.57781 11.6286V11.6316ZM11.6316 10.6252L12.9734 11.967C13.2525 12.2461 13.2525 12.6973 12.9734 12.9734C12.6944 13.2495 12.2431 13.2525 11.967 12.9734L10.6222 11.6286C10.3431 11.3495 10.3431 10.8983 10.6222 10.6222C10.9012 10.3461 11.3525 10.3431 11.6286 10.6222L11.6316 10.6252ZM8.3125 12.5875V14.4875C8.3125 14.8823 7.99484 15.2 7.6 15.2C7.20516 15.2 6.8875 14.8823 6.8875 14.4875V12.5875C6.8875 12.1927 7.20516 11.875 7.6 11.875C7.99484 11.875 8.3125 12.1927 8.3125 12.5875ZM9.5 7.6C9.5 7.09609 9.29982 6.61282 8.9435 6.2565C8.58718 5.90018 8.10391 5.7 7.6 5.7C7.09609 5.7 6.61282 5.90018 6.2565 6.2565C5.90018 6.61282 5.7 7.09609 5.7 7.6C5.7 8.10391 5.90018 8.58718 6.2565 8.9435C6.61282 9.29982 7.09609 9.5 7.6 9.5C8.10391 9.5 8.58718 9.29982 8.9435 8.9435C9.29982 8.58718 9.5 8.10391 9.5 7.6ZM4.275 7.6C4.275 6.71815 4.62531 5.87243 5.24887 5.24887C5.87243 4.62531 6.71815 4.275 7.6 4.275C8.48184 4.275 9.32757 4.62531 9.95113 5.24887C10.5747 5.87243 10.925 6.71815 10.925 7.6C10.925 8.48184 10.5747 9.32757 9.95113 9.95113C9.32757 10.5747 8.48184 10.925 7.6 10.925C6.71815 10.925 5.87243 10.5747 5.24887 9.95113C4.62531 9.32757 4.275 8.48184 4.275 7.6Z" fill="#F09A17"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -42,8 +42,8 @@
|
||||
"filament_z_hop_types": [
|
||||
"Normal Lift"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"70"
|
||||
],
|
||||
"impact_strength_z": [
|
||||
"3.4"
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"95"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"100"
|
||||
],
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
"full_fan_speed_layer": [
|
||||
"2"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"16"
|
||||
],
|
||||
"impact_strength_z": [
|
||||
"13.3"
|
||||
],
|
||||
|
||||
@@ -45,6 +45,27 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"800"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"165"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"150"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"150"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"100"
|
||||
],
|
||||
|
||||
@@ -24,6 +24,24 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"703"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"16"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"85"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"280"
|
||||
],
|
||||
|
||||
@@ -24,11 +24,20 @@
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"702"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"60",
|
||||
"60",
|
||||
"50",
|
||||
"50"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"50"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"55"
|
||||
],
|
||||
"slow_down_layer_time": [
|
||||
"8"
|
||||
|
||||
@@ -27,14 +27,26 @@
|
||||
"filament_max_volumetric_speed": [
|
||||
"6"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
],
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"705"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"60",
|
||||
"60",
|
||||
"50",
|
||||
"50"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"50"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"55"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"60"
|
||||
|
||||
@@ -21,11 +21,26 @@
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"701"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"16"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"85"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"280"
|
||||
|
||||
@@ -27,11 +27,14 @@
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"706"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"4",
|
||||
"12",
|
||||
"4"
|
||||
],
|
||||
"nozzle_temperature_range_high": [
|
||||
"270"
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
"filament_max_volumetric_speed": [
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"65"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"85"
|
||||
],
|
||||
"nozzle_temperature": [
|
||||
"260"
|
||||
],
|
||||
|
||||
@@ -38,6 +38,34 @@
|
||||
"filament_max_volumetric_speed": [
|
||||
"6"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"55"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"65",
|
||||
"55",
|
||||
"55"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"60"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"70"
|
||||
],
|
||||
|
||||
@@ -4,5 +4,26 @@
|
||||
"inherits": "fdm_filament_pps",
|
||||
"from": "system",
|
||||
"filament_id": "GFT97",
|
||||
"instantiation": "false"
|
||||
"instantiation": "false",
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"85"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -41,6 +41,30 @@
|
||||
"filament_vendor": [
|
||||
"Polymaker"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"800"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"165"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"150"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"150"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"70"
|
||||
],
|
||||
@@ -83,9 +107,6 @@
|
||||
"textured_plate_temp_initial_layer": [
|
||||
"70"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"800"
|
||||
],
|
||||
"filament_start_gcode": [
|
||||
"; filament start gcode\n{if (bed_temperature[current_extruder] >80)||(bed_temperature_initial_layer[current_extruder] >80)}M106 P3 S255\n{elsif (bed_temperature[current_extruder] >60)||(bed_temperature_initial_layer[current_extruder] >60)}M106 P3 S180\n{endif}\n\n{if activate_air_filtration[current_extruder] && support_air_filtration}\nM106 P3 S{during_print_exhaust_fan_speed_num[current_extruder]} \n{endif}"
|
||||
]
|
||||
|
||||
@@ -43,6 +43,27 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"200"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"8.0",
|
||||
"12",
|
||||
"8.0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"80"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"90"
|
||||
],
|
||||
|
||||
@@ -43,6 +43,27 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"200"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"8.0",
|
||||
"12",
|
||||
"8.0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"100"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"85"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"85"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"90"
|
||||
],
|
||||
|
||||
@@ -43,6 +43,34 @@
|
||||
"filament_type": [
|
||||
"BVOH"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"65"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"40"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"60",
|
||||
"60",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,34 @@
|
||||
"filament_type": [
|
||||
"EVA"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"70"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"40"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"45",
|
||||
"45",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"supertack_plate_temp": [
|
||||
"0"
|
||||
],
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
"inherits": "fdm_filament_common",
|
||||
"from": "system",
|
||||
"instantiation": "false",
|
||||
"additional_cooling_fan_speed": [
|
||||
"0"
|
||||
],
|
||||
"cool_plate_temp": [
|
||||
"0"
|
||||
],
|
||||
@@ -42,6 +39,27 @@
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"798"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"80"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"90"
|
||||
|
||||
@@ -43,6 +43,30 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"400"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"18"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"165"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"150"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"85",
|
||||
"65",
|
||||
"85"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"150"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"100"
|
||||
],
|
||||
|
||||
@@ -40,6 +40,27 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"500"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"8.0",
|
||||
"12",
|
||||
"8.0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"105"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"90"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"80",
|
||||
"65",
|
||||
"80"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"90"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
],
|
||||
|
||||
@@ -28,6 +28,37 @@
|
||||
"filament_type": [
|
||||
"PCTG"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"55"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"65",
|
||||
"55",
|
||||
"55"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"60"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"80"
|
||||
],
|
||||
|
||||
@@ -40,6 +40,31 @@
|
||||
"filament_type": [
|
||||
"PE"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"70"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"50"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"45",
|
||||
"45",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
],
|
||||
|
||||
@@ -31,6 +31,34 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"300"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"80"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"55"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"65",
|
||||
"55",
|
||||
"55"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"60"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"80"
|
||||
],
|
||||
|
||||
@@ -40,6 +40,31 @@
|
||||
"filament_type": [
|
||||
"PHA"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"70"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"45"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"45",
|
||||
"45",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
],
|
||||
|
||||
@@ -37,14 +37,39 @@
|
||||
"filament_max_volumetric_speed": [
|
||||
"12"
|
||||
],
|
||||
"filament_scarf_seam_type": [
|
||||
"none"
|
||||
],
|
||||
"filament_scarf_gap": [
|
||||
"15%"
|
||||
],
|
||||
"filament_adhesiveness_category": [
|
||||
"100"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"70"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"45"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"45",
|
||||
"45",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
|
||||
@@ -43,6 +43,34 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"902"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"70"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1",
|
||||
"0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"60"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"50"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"60",
|
||||
"60",
|
||||
"50",
|
||||
"50"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"55"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
],
|
||||
|
||||
@@ -46,6 +46,34 @@
|
||||
"filament_vendor": [
|
||||
"Bambu Lab"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"100"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"18"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"165"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"150"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"85",
|
||||
"65",
|
||||
"85"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"150"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"100"
|
||||
],
|
||||
|
||||
@@ -43,6 +43,31 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"801"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"100"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"12",
|
||||
"12",
|
||||
"12"
|
||||
],
|
||||
"filament_dev_ams_drying_ams_limitations": [],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"165"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"150"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"85",
|
||||
"65",
|
||||
"85"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"150"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"110"
|
||||
],
|
||||
|
||||
@@ -49,6 +49,27 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"704"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"18",
|
||||
"12",
|
||||
"18"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"75"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"40"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"85",
|
||||
"65",
|
||||
"70"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"75"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"55"
|
||||
],
|
||||
|
||||
@@ -46,6 +46,30 @@
|
||||
"filament_adhesiveness_category": [
|
||||
"600"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"12",
|
||||
"18",
|
||||
"12",
|
||||
"18"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"16"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"40"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"65",
|
||||
"75",
|
||||
"45",
|
||||
"45"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"50"
|
||||
],
|
||||
"hot_plate_temp": [
|
||||
"35"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "0.40mm Standard @Creality K1 SE 0.8 nozzle",
|
||||
"inherits": "fdm_process_creality_common",
|
||||
"from": "system",
|
||||
"setting_id": "caYmVSsFmtESzLNF",
|
||||
"setting_id": "5mfhrVJYlK4lWDUs",
|
||||
"instantiation": "true",
|
||||
"reduce_crossing_wall": "0",
|
||||
"max_travel_detour_distance": "0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Qidi",
|
||||
"version": "02.04.00.07",
|
||||
"version": "02.04.00.08",
|
||||
"force_update": "0",
|
||||
"description": "Qidi configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -10,36 +10,6 @@
|
||||
"machine_pause_gcode": "M0",
|
||||
"support_chamber_temp_control": "1",
|
||||
"wipe_tower_type": "type1",
|
||||
"filament_dev_ams_drying_ams_limitations": [
|
||||
"1"
|
||||
],
|
||||
"filament_dev_ams_drying_temperature": [
|
||||
"40.0",
|
||||
"40.0",
|
||||
"40.0",
|
||||
"40.0"
|
||||
],
|
||||
"filament_dev_ams_drying_time": [
|
||||
"8.0",
|
||||
"8.0",
|
||||
"8.0",
|
||||
"8.0"
|
||||
],
|
||||
"filament_dev_drying_softening_temperature": [
|
||||
"40.0"
|
||||
],
|
||||
"filament_dev_ams_drying_heat_distortion_temperature": [
|
||||
"45.0"
|
||||
],
|
||||
"filament_dev_drying_cooling_temperature": [
|
||||
"35.0"
|
||||
],
|
||||
"filament_dev_chamber_drying_bed_temperature": [
|
||||
"90.0"
|
||||
],
|
||||
"filament_dev_chamber_drying_time": [
|
||||
"12.0"
|
||||
],
|
||||
"retraction_length": [
|
||||
"1"
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"name": "0.30mm Big @RatRig V-Core 4 0.8",
|
||||
"inherits": "fdm_process_ratrig_common",
|
||||
"from": "system",
|
||||
"setting_id": "7FOG8fkUbrLknvuz",
|
||||
"setting_id": "2tM04aSQ8NcTsmQo",
|
||||
"instantiation": "true",
|
||||
"layer_height": "0.3",
|
||||
"inital_layer_height": "0.35",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.15mm Standard @iQ TiQ2 (0.25 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "PNxZXC0peOlGlKwG",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.25 Nozzle"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.15mm Standard @iQ TiQ8 (0.25 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "K0Ybw0qUqEIL05PY",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.25 Nozzle"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.30mm Standard @iQ TiQ2 (0.6 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "IGN3ZUR73J0veLrE",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.6 Nozzle"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.30mm Standard @iQ TiQ8 (0.6 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "QEODQzrO9UZEgrtB",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.6 Nozzle"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.40mm Standard @iQ TiQ2 (0.8 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "ZoiYkGXOTBh39HTB",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ2 0.8 Nozzle"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "0.40mm Standard @iQ TiQ8 (0.8 Nozzle)",
|
||||
"inherits": "fdm_process_tiq_common",
|
||||
"from": "system",
|
||||
"setting_id": "C7TZWdCzQroB8pKL",
|
||||
"instantiation": "true",
|
||||
"compatible_printers": [
|
||||
"iQ TiQ8 0.8 Nozzle"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#version 110
|
||||
|
||||
uniform sampler2D Texture;
|
||||
uniform sampler2D s_texture;
|
||||
|
||||
varying vec2 Frag_UV;
|
||||
varying vec4 Frag_Color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);
|
||||
gl_FragColor = Frag_Color * texture2D(s_texture, Frag_UV.st);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#version 140
|
||||
|
||||
uniform sampler2D Texture;
|
||||
uniform sampler2D s_texture;
|
||||
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
@@ -9,5 +9,5 @@ out vec4 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_color = Frag_Color * texture(Texture, Frag_UV.st);
|
||||
out_color = Frag_Color * texture(s_texture, Frag_UV.st);
|
||||
}
|
||||
@@ -212,14 +212,26 @@ void install_slice_context_log_sink()
|
||||
// -v). Unlike the static reference/placeholder checks, this expands every custom *_gcode - including
|
||||
// change_filament_gcode at the one filament change - against the printer's fully-resolved config, so
|
||||
// undefined-placeholder / invalid-flow bugs surface here. Reports every offending printer and returns 1
|
||||
// if any failed, 0 otherwise. The sweep is SEQUENTIAL by necessity: Print::process() keeps
|
||||
// process-global state, so slicing printers concurrently in one process races even with per-slice
|
||||
// Model+Print. Load in validation mode so the vendors are read straight from the -p profiles dir
|
||||
// (no data_dir/system tree) and -v scoping is honoured for free.
|
||||
int slice_all_printers(const std::string &vendor)
|
||||
// if any failed, 0 otherwise. When outdir is non-empty, each printer's g-code is also written there as
|
||||
// "<vendor>__<printer>.gcode" for manual inspection. The sweep is SEQUENTIAL by necessity:
|
||||
// Print::process() keeps process-global state, so slicing printers concurrently in one process races
|
||||
// even with per-slice Model+Print. Load in validation mode so the vendors are read straight from the -p
|
||||
// profiles dir (no data_dir/system tree) and -v scoping is honoured for free.
|
||||
int slice_all_printers(const std::string &vendor, const std::string &outdir)
|
||||
{
|
||||
install_slice_context_log_sink();
|
||||
|
||||
if (!outdir.empty()) {
|
||||
boost::system::error_code ec;
|
||||
fs::create_directories(outdir, ec);
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Could not create output directory \"" << outdir << "\": " << ec.message();
|
||||
std::cout << "Validation failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Saving sliced g-code to " << outdir << std::endl;
|
||||
}
|
||||
|
||||
PresetBundle bundle;
|
||||
bundle.set_is_validation_mode(true);
|
||||
bundle.set_vendor_to_validate(vendor); // empty == all vendors
|
||||
@@ -323,6 +335,10 @@ int slice_all_printers(const std::string &vendor)
|
||||
|
||||
try {
|
||||
const std::string out = slice_two_color_cube_and_export(cfg, bundle.is_bbl_vendor());
|
||||
if (!outdir.empty() && !out.empty()) {
|
||||
const fs::path f = fs::path(outdir) / (sanitize_filename(vendor_name) + "__" + sanitize_filename(printer) + ".gcode");
|
||||
save_string_file(f, out);
|
||||
}
|
||||
if (out.empty() || out.find("G1") == std::string::npos) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Printer \"" << printer << "\" produced no g-code";
|
||||
++failures;
|
||||
@@ -364,6 +380,7 @@ int main(int argc, char* argv[])
|
||||
("vendor,v", po::value<std::string>()->default_value(""), "Vendor name. Optional, all profiles present in the folder will be validated if not specified")
|
||||
("generate_presets,g", po::value<bool>()->default_value(false), "Generate user presets for mock test")
|
||||
("slice,s", po::bool_switch()->default_value(false), "Slice a two-colour cube through every printer to expand all custom g-code (catches placeholder/flow errors that static checks miss). Off unless this flag is present.")
|
||||
("outdir,o", po::value<std::string>()->default_value(""), "With -s, also save each printer's g-code to this folder (as <vendor>__<printer>.gcode) for manual inspection. Optional.")
|
||||
("check_filament_subtypes,f", po::bool_switch()->default_value(false), "Also flag printers with duplicate (ambiguous) filament subtypes. Off unless this flag is present.")
|
||||
("log_level,l", po::value<int>()->default_value(2), "Log level. Optional, default is 2 (warning). Higher values produce more detailed logs.");
|
||||
// clang-format on
|
||||
@@ -389,6 +406,7 @@ int main(int argc, char* argv[])
|
||||
int log_level = vm["log_level"].as<int>();
|
||||
bool generate_user_preset = vm["generate_presets"].as<bool>();
|
||||
bool slice_mode = vm["slice"].as<bool>();
|
||||
std::string slice_outdir = vm["outdir"].as<std::string>();
|
||||
bool check_filament_subtypes = vm["check_filament_subtypes"].as<bool>();
|
||||
|
||||
// check if path is valid, and return error if not
|
||||
@@ -419,7 +437,7 @@ int main(int argc, char* argv[])
|
||||
// Slice mode expands every printer's custom g-code by actually slicing (see slice_all_printers).
|
||||
// A distinct opt-in mode so the default static checks stay fast for every profile PR.
|
||||
if (slice_mode)
|
||||
return slice_all_printers(vendor);
|
||||
return slice_all_printers(vendor, slice_outdir);
|
||||
|
||||
auto preset_bundle = new PresetBundle();
|
||||
// preset_bundle->setup_directories();
|
||||
|
||||
@@ -352,8 +352,7 @@ namespace Slic3r
|
||||
int k,
|
||||
const std::vector<unsigned int>& used_filaments,
|
||||
const std::unordered_map<int, std::vector<int>>& unplaceable_limits,
|
||||
int* cost,
|
||||
int timeout_ms)
|
||||
int* cost)
|
||||
{
|
||||
auto distance_evaluator = std::make_shared<FlushDistanceEvaluator>(ctx.model_info.flush_matrix, used_filaments, ctx.model_info.layer_filaments);
|
||||
KMediods PAM(k, (int)used_filaments.size(), distance_evaluator, ctx.machine_info.master_extruder_id);
|
||||
@@ -369,7 +368,7 @@ namespace Slic3r
|
||||
}
|
||||
PAM.set_cluster_group_size(cluster_size_limit);
|
||||
|
||||
PAM.do_clustering(ctx, timeout_ms, 30);
|
||||
PAM.do_clustering(ctx, m_clustering_budget);
|
||||
|
||||
m_memoryed_heap = PAM.get_memoryed_groups();
|
||||
|
||||
@@ -793,7 +792,7 @@ namespace Slic3r
|
||||
2.1 In each cluster, make the point that minimizes the sum of distances within the cluster the medoid
|
||||
2.2 Reassign each point to the cluster defined by the closest medoid determined in the previous step
|
||||
*/
|
||||
void KMediods::do_clustering(const FilamentGroupContext &context, int timeout_ms, int retry)
|
||||
void KMediods::do_clustering(const FilamentGroupContext& context, const ClusteringBudget& budget)
|
||||
{
|
||||
FlushTimeMachine T;
|
||||
T.time_machine_start();
|
||||
@@ -817,7 +816,11 @@ namespace Slic3r
|
||||
double best_cluster_cost = std::numeric_limits<double>::max();
|
||||
int retry_count = 0;
|
||||
|
||||
while (retry_count < retry && T.time_machine_end() < timeout_ms) {
|
||||
// Run at least one restart; otherwise every filament would stay in the default group.
|
||||
const int retry = std::max(1, budget.max_restarts);
|
||||
auto within_budget = [&]() { return budget.timeout_ms <= 0 || T.time_machine_end() < budget.timeout_ms; };
|
||||
|
||||
while (retry_count < retry && within_budget()) {
|
||||
std::vector<int> curr_cluster_centers = init_cluster_center(m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size, retry_count);
|
||||
std::vector<int> curr_cluster_labels = assign_cluster_label(curr_cluster_centers, m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size);
|
||||
double curr_cluster_cost = evaluate_labels(curr_cluster_labels);
|
||||
@@ -826,7 +829,7 @@ namespace Slic3r
|
||||
update_memoryed_groups(g, memory_threshold, memoryed_groups);
|
||||
|
||||
bool mediods_changed = true;
|
||||
while (mediods_changed && T.time_machine_end() < timeout_ms) {
|
||||
while (mediods_changed && within_budget()) {
|
||||
mediods_changed = false;
|
||||
double best_swap_cost = curr_cluster_cost;
|
||||
int best_swap_cluster = -1;
|
||||
@@ -889,7 +892,7 @@ namespace Slic3r
|
||||
if (estimated < ENUM_THRESHOLD)
|
||||
result = calc_group_by_enum(k, used_filaments, unplaceable_limits, cost);
|
||||
else
|
||||
result = calc_group_by_kmedoids(k, used_filaments, unplaceable_limits, cost, 3000);
|
||||
result = calc_group_by_kmedoids(k, used_filaments, unplaceable_limits, cost);
|
||||
|
||||
change_memoryed_heaps_to_arrays(m_memoryed_heap, ctx.group_info.total_filament_num, used_filaments, m_memoryed_groups);
|
||||
|
||||
|
||||
@@ -142,6 +142,16 @@ namespace Slic3r
|
||||
FilamentGroupContext::SpeedInfo m_speed_info;
|
||||
};
|
||||
|
||||
// Search budget for the k-medoids clustering, an anytime search. Each restart is seeded from its
|
||||
// own index, so what it returns depends on how many restarts complete before the clock expires,
|
||||
// and therefore on the speed of the machine. A timeout_ms <= 0 removes the clock and bounds the
|
||||
// search by max_restarts alone.
|
||||
struct ClusteringBudget
|
||||
{
|
||||
int timeout_ms = 3000;
|
||||
int max_restarts = 30;
|
||||
};
|
||||
|
||||
class FilamentGroup
|
||||
{
|
||||
using MemoryedGroup = FilamentGroupUtils::MemoryedGroup;
|
||||
@@ -149,6 +159,8 @@ namespace Slic3r
|
||||
public:
|
||||
explicit FilamentGroup(const FilamentGroupContext& ctx_) :ctx(ctx_) {}
|
||||
public:
|
||||
void set_clustering_budget(const ClusteringBudget& budget) { m_clustering_budget = budget; }
|
||||
|
||||
std::vector<int> calc_filament_group(int * cost = nullptr);
|
||||
std::vector<std::vector<int>> get_memoryed_groups()const { return m_memoryed_groups; }
|
||||
|
||||
@@ -162,7 +174,7 @@ namespace Slic3r
|
||||
std::vector<int> calc_group_by_enum(int k, const std::vector<unsigned int>& used_filaments,
|
||||
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr);
|
||||
std::vector<int> calc_group_by_kmedoids(int k, const std::vector<unsigned int>& used_filaments,
|
||||
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr, int timeout_ms = 500);
|
||||
const std::unordered_map<int, std::vector<int>>& unplaceable_limits, int* cost = nullptr);
|
||||
|
||||
std::map<int, int> rebuild_unprintables(const std::vector<unsigned int>& used_filaments, const std::map<int,int>& extruder_unprintables);
|
||||
std::unordered_map<int, std::vector<int>> rebuild_nozzle_unprintables(const std::vector<unsigned int>& used_filaments, const std::unordered_map<int, std::vector<int>>& extruder_unprintables, const std::vector<int>& filament_volume_map);
|
||||
@@ -175,6 +187,7 @@ namespace Slic3r
|
||||
FilamentGroupContext ctx;
|
||||
MemoryedGroupHeap m_memoryed_heap;
|
||||
std::vector<std::vector<int>> m_memoryed_groups;
|
||||
ClusteringBudget m_clustering_budget;
|
||||
public:
|
||||
std::optional<std::function<bool(int, std::vector<int>&)>> get_custom_seq;
|
||||
};
|
||||
@@ -220,7 +233,7 @@ namespace Slic3r
|
||||
void set_memory_threshold(double threshold) { memory_threshold = threshold; }
|
||||
MemoryedGroupHeap get_memoryed_groups()const { return memoryed_groups; }
|
||||
|
||||
void do_clustering(const FilamentGroupContext& context, int timeout_ms = 100, int retry = 10);
|
||||
void do_clustering(const FilamentGroupContext& context, const ClusteringBudget& budget);
|
||||
std::vector<int> get_cluster_labels()const { return m_cluster_labels; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -162,11 +162,14 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
|
||||
out.push_back(eec = new ExtrusionEntityCollection());
|
||||
// Only concentric fills are not sorted.
|
||||
eec->no_sort = this->no_sort();
|
||||
// ORCA: special flag for flow rate calibration
|
||||
auto is_flow_calib = params.extrusion_role == erTopSolidInfill && this->print_object_config->has("calib_flowrate_topinfill_special_order") &&
|
||||
this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool();
|
||||
// Orca: a forced surface fill order must survive the G-code path planner, which would
|
||||
// otherwise re-chain and possibly reverse the paths. This also covers the flow rate
|
||||
// calibration, which forces an outward fill order on its top surfaces.
|
||||
// otherwise re-chain and possibly reverse the paths. The same applies to the flow rate
|
||||
// calibration's special toolpath order.
|
||||
const bool keep_fill_order = params.fill_order != SurfaceFillOrder::Default;
|
||||
if (keep_fill_order) {
|
||||
if (is_flow_calib || keep_fill_order) {
|
||||
eec->no_sort = true;
|
||||
}
|
||||
size_t idx = eec->entities.size();
|
||||
@@ -181,7 +184,7 @@ void Fill::fill_surface_extrusion(const Surface* surface, const FillParams& para
|
||||
params.extrusion_role,
|
||||
flow_mm3_per_mm, float(flow_width), params.flow.height());
|
||||
}
|
||||
if (!params.can_reverse || keep_fill_order) {
|
||||
if (!params.can_reverse || is_flow_calib || keep_fill_order) {
|
||||
for (size_t i = idx; i < eec->entities.size(); i++)
|
||||
eec->entities[i]->set_reverse();
|
||||
}
|
||||
|
||||
@@ -134,7 +134,34 @@ void FillPlanePath::_fill_surface_single(
|
||||
if (!polylines.empty()) {
|
||||
Polylines chained;
|
||||
if (params.dont_connect() || params.density > 0.5) {
|
||||
if (params.fill_order != SurfaceFillOrder::Default) {
|
||||
// ORCA: special flag for flow rate calibration. The chords chained ahead of the
|
||||
// inside-out center spiral collide with it in opposing directions, raising a
|
||||
// tactile lip that the calibration reads. Only applies while the fill order is
|
||||
// Default, so it can be overridden from the calibration objects.
|
||||
auto is_flow_calib = params.fill_order == SurfaceFillOrder::Default &&
|
||||
params.extrusion_role == erTopSolidInfill &&
|
||||
this->print_object_config->has("calib_flowrate_topinfill_special_order") &&
|
||||
this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool() &&
|
||||
dynamic_cast<FillArchimedeanChords*>(this);
|
||||
if (is_flow_calib) {
|
||||
// We want the spiral part to be printed inside-out
|
||||
// Find the center spiral line first, by looking for the longest one
|
||||
auto it = std::max_element(polylines.begin(), polylines.end(),
|
||||
[](const Polyline& a, const Polyline& b) { return a.length() < b.length(); });
|
||||
Polyline center_spiral = std::move(*it);
|
||||
|
||||
// Ensure the spiral is printed from inside to out
|
||||
if (center_spiral.first_point().squaredNorm() > center_spiral.last_point().squaredNorm()) {
|
||||
center_spiral.reverse();
|
||||
}
|
||||
|
||||
// Chain the other polylines
|
||||
polylines.erase(it);
|
||||
chained = chain_polylines(std::move(polylines), nullptr);
|
||||
|
||||
// Then add the center spiral back
|
||||
chained.push_back(std::move(center_spiral));
|
||||
} else if (params.fill_order != SurfaceFillOrder::Default) {
|
||||
// Orca: print the fragments in the order they appear along the generated
|
||||
// path, which runs from the center outwards. The Euclidean distance from
|
||||
// the center cannot be used for this: along the Octagram Spiral the radius
|
||||
|
||||
@@ -470,6 +470,8 @@ void Preset::normalize(DynamicPrintConfig &config)
|
||||
continue;
|
||||
if (filament_options_with_variant.find(key) != filament_options_with_variant.end())
|
||||
continue;
|
||||
if (filament_dev_options.find(key) != filament_dev_options.end())
|
||||
continue;
|
||||
auto *opt = config.option(key, false);
|
||||
/*assert(opt != nullptr);
|
||||
assert(opt->is_vector());*/
|
||||
@@ -1308,6 +1310,7 @@ static std::vector<std::string> s_Preset_print_options{
|
||||
"interlocking_depth",
|
||||
"interlocking_boundary_avoidance",
|
||||
"interlocking_beam_width",
|
||||
"calib_flowrate_topinfill_special_order",
|
||||
// Z Anti-Aliasing (ZAA)
|
||||
"zaa_enabled",
|
||||
"zaa_minimize_perimeter_height",
|
||||
@@ -1371,7 +1374,11 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
|
||||
"filament_pre_cooling_temperature", "filament_pre_cooling_temperature_nc",
|
||||
"filament_preheat_temperature_delta", "filament_retract_length_nc",
|
||||
"filament_change_length_nc", "filament_prime_volume_nc",
|
||||
"long_retractions_when_ec", "retraction_distances_when_ec"
|
||||
"long_retractions_when_ec", "retraction_distances_when_ec",
|
||||
//ams chamber
|
||||
"filament_dev_ams_drying_ams_limitations", "filament_dev_ams_drying_temperature", "filament_dev_ams_drying_time", "filament_dev_ams_drying_heat_distortion_temperature",
|
||||
"filament_dev_chamber_drying_bed_temperature", "filament_dev_chamber_drying_time",
|
||||
"filament_dev_drying_softening_temperature", "filament_dev_drying_cooling_temperature"
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_machine_limits_options {
|
||||
@@ -3812,6 +3819,26 @@ void PresetCollection::set_custom_preset_alias(Preset &preset)
|
||||
set_printer_hold_alias(preset.alias, preset);
|
||||
}
|
||||
|
||||
std::string PresetCollection::get_preset_alias(Preset &preset, bool force)
|
||||
{
|
||||
if (!preset.alias.empty())
|
||||
return preset.alias;
|
||||
else
|
||||
set_custom_preset_alias(preset);
|
||||
|
||||
if (!preset.alias.empty() || !force)
|
||||
return preset.alias;
|
||||
|
||||
std::string alias_name;
|
||||
std::string preset_name = preset.name;
|
||||
size_t end_pos = preset_name.find_first_of("@");
|
||||
if (end_pos != std::string::npos) {
|
||||
alias_name = preset_name.substr(0, end_pos);
|
||||
boost::trim_right(alias_name);
|
||||
}
|
||||
return alias_name;
|
||||
}
|
||||
|
||||
void PresetCollection::set_printer_hold_alias(const std::string &alias, Preset &preset, bool remove)
|
||||
{
|
||||
auto compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset.config.option("compatible_printers"));
|
||||
|
||||
@@ -805,6 +805,9 @@ public:
|
||||
std::string path_from_name(const std::string &new_name, bool detach = false) const;
|
||||
std::string path_for_preset(const Preset & preset) const;
|
||||
|
||||
// Get the alias of a preset, setting it if it's empty
|
||||
std::string get_preset_alias(Preset &preset, bool force = false);
|
||||
|
||||
size_t num_default_presets() { return m_num_default_presets; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -4647,6 +4647,11 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(2));
|
||||
|
||||
// ORCA: special flag for flow rate calibration
|
||||
def = this->add("calib_flowrate_topinfill_special_order", coBool);
|
||||
def->mode = comDevelop;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("ironing_type", coEnum);
|
||||
def->label = L("Ironing type");
|
||||
def->category = L("Quality");
|
||||
@@ -7797,6 +7802,30 @@ void PrintConfigDef::init_fff_params()
|
||||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionPercent(85));
|
||||
|
||||
def = this->add("filament_dev_ams_drying_ams_limitations", coStrings);
|
||||
def->set_default_value(new ConfigOptionStrings{""});
|
||||
|
||||
def = this->add("filament_dev_ams_drying_temperature", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_ams_drying_time", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_ams_drying_heat_distortion_temperature", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_chamber_drying_bed_temperature", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_chamber_drying_time", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_drying_softening_temperature", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
def = this->add("filament_dev_drying_cooling_temperature", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats{0});
|
||||
|
||||
// Declare retract values for filament profile, overriding the printer's extruder profile.
|
||||
for (auto& opt_key : filament_extruder_override_keys) {
|
||||
const std::string filament_prefix = "filament_";
|
||||
@@ -8992,7 +9021,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
"internal_bridge_support_thickness", "top_area_threshold", "reduce_wall_solid_infill","filament_load_time","filament_unload_time",
|
||||
"smooth_coefficient", "overhang_totally_speed", "silent_mode",
|
||||
"overhang_speed_classic", "filament_prime_volume",
|
||||
"calib_flowrate_topinfill_special_order",
|
||||
"anisotropic_surfaces", // superseded by top_surface_fill_order / bottom_surface_fill_order
|
||||
};
|
||||
|
||||
@@ -9232,6 +9260,17 @@ std::set<std::string> printer_options_with_variant_2 = {
|
||||
|
||||
std::set<std::string> empty_options;
|
||||
|
||||
std::set<std::string> filament_dev_options = {
|
||||
"filament_dev_ams_drying_ams_limitations",
|
||||
"filament_dev_ams_drying_temperature",
|
||||
"filament_dev_ams_drying_time",
|
||||
"filament_dev_ams_drying_heat_distortion_temperature",
|
||||
"filament_dev_chamber_drying_bed_temperature",
|
||||
"filament_dev_chamber_drying_time",
|
||||
"filament_dev_drying_softening_temperature",
|
||||
"filament_dev_drying_cooling_temperature"
|
||||
};
|
||||
|
||||
DynamicPrintConfig DynamicPrintConfig::full_print_config()
|
||||
{
|
||||
return DynamicPrintConfig((const PrintRegionConfig&)FullPrintConfig::defaults());
|
||||
|
||||
@@ -840,6 +840,8 @@ extern std::set<std::string> printer_options_with_variant_1;
|
||||
extern std::set<std::string> printer_options_with_variant_2;
|
||||
extern std::set<std::string> empty_options;
|
||||
|
||||
extern std::set<std::string> filament_dev_options;
|
||||
|
||||
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
|
||||
extern void compute_filament_override_value(const std::string& opt_key, const ConfigOption *opt_old_machine, const ConfigOption *opt_new_machine, const ConfigOption *opt_new_filament, const DynamicPrintConfig& new_full_config,
|
||||
t_config_option_keys& diff_keys, DynamicPrintConfig& filament_overrides, std::vector<int>& f_map_indices);
|
||||
@@ -1219,6 +1221,9 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionInt, interlocking_beam_layer_count))
|
||||
((ConfigOptionInt, interlocking_depth))
|
||||
((ConfigOptionInt, interlocking_boundary_avoidance))
|
||||
|
||||
// Orca: internal use only
|
||||
((ConfigOptionBool, calib_flowrate_topinfill_special_order)) // ORCA: special flag for flow rate calibration
|
||||
)
|
||||
|
||||
// This object is mapped to Perl as Slic3r::Config::PrintRegion.
|
||||
@@ -1678,6 +1683,16 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
// Printer flag: whether the printer offers the fast-purge mode selector.
|
||||
// Default false; no shipping profile sets it, so the fast-purge UI stays hidden.
|
||||
((ConfigOptionBool, support_fast_purge_mode))
|
||||
|
||||
//ams chamber
|
||||
((ConfigOptionStrings, filament_dev_ams_drying_ams_limitations))
|
||||
((ConfigOptionFloats, filament_dev_ams_drying_temperature))
|
||||
((ConfigOptionFloats, filament_dev_ams_drying_time))
|
||||
((ConfigOptionFloats, filament_dev_ams_drying_heat_distortion_temperature))
|
||||
((ConfigOptionFloats, filament_dev_chamber_drying_bed_temperature))
|
||||
((ConfigOptionFloats, filament_dev_chamber_drying_time))
|
||||
((ConfigOptionFloats, filament_dev_drying_softening_temperature))
|
||||
((ConfigOptionFloats, filament_dev_drying_cooling_temperature))
|
||||
)
|
||||
|
||||
// This object is mapped to Perl as Slic3r::Config::Print.
|
||||
|
||||
@@ -28,6 +28,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/AMSMaterialsSetting.hpp
|
||||
GUI/AMSSetting.cpp
|
||||
GUI/AMSSetting.hpp
|
||||
GUI/AMSDryControl.cpp
|
||||
GUI/AMSDryControl.hpp
|
||||
GUI/AmsWidgets.cpp
|
||||
GUI/AmsWidgets.hpp
|
||||
GUI/Auxiliary.cpp
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
#pragma once
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "slic3r/GUI/Widgets/AMSItem.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
#include "slic3r/GUI/Widgets/PopupWindow.hpp"
|
||||
|
||||
#include "slic3r/GUI/wxExtensions.hpp"
|
||||
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
|
||||
//Previous defintions
|
||||
class wxGrid;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
||||
enum class DryCtrState {
|
||||
IDLE,
|
||||
DRY_WHEN_PRINT,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
enum class DryCtrDev {
|
||||
N3S,
|
||||
N3F,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
struct DryingPreset {
|
||||
DryCtrState state;
|
||||
DryCtrDev dev;
|
||||
int dry_temp;
|
||||
int dry_time;
|
||||
};
|
||||
|
||||
class FilamentItemPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
FilamentItemPanel(wxWindow* parent, const wxString& text, const std::string& icon_name = "",
|
||||
wxWindowID id = wxID_ANY);
|
||||
|
||||
void SetText(const wxString& text);
|
||||
void SetIcon(const std::string& icon_name);
|
||||
void msw_rescale();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnSize(wxSizeEvent& event);
|
||||
|
||||
Label* m_text_label;
|
||||
wxStaticBitmap* m_icon_bitmap;
|
||||
int m_target_size;
|
||||
std::string m_icon_name;
|
||||
ScalableBitmap m_icon;
|
||||
};
|
||||
|
||||
class AMSFilamentPanel : public wxPanel
|
||||
{
|
||||
wxBoxSizer* m_filament_sizer;
|
||||
Label* m_ams_name_label;
|
||||
int m_border_radius;
|
||||
wxPanel* m_filament_container{nullptr};
|
||||
std::vector<FilamentItemPanel*> m_filament_items;
|
||||
|
||||
public:
|
||||
AMSFilamentPanel(wxWindow* parent, const wxString& ams_name, wxWindowID id = wxID_ANY);
|
||||
|
||||
void AddFilamentItem(const wxString& text, const std::string& icon_name);
|
||||
void AddFilamentItem(FilamentItemPanel* panel);
|
||||
void SetAmsName(const wxString& ams_name);
|
||||
void Clear();
|
||||
void msw_rescale();
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
};
|
||||
|
||||
|
||||
class AMSDryCtrWin : public DPIDialog
|
||||
{
|
||||
public:
|
||||
AMSDryCtrWin(wxWindow *parent);
|
||||
~AMSDryCtrWin();
|
||||
|
||||
void msw_rescale();
|
||||
void update(std::shared_ptr<DevFilaSystem> fila_system, MachineObject* obj);
|
||||
void set_ams_id(const std::string& ams_id);
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
|
||||
private:
|
||||
wxSimplebook* m_main_simplebook{nullptr};
|
||||
wxPanel* m_original_page{nullptr};
|
||||
|
||||
wxWindow* m_amswin{nullptr};
|
||||
wxBoxSizer* m_sizer_ams_items{nullptr};
|
||||
wxScrolledWindow* m_panel_prv_left {nullptr};
|
||||
wxScrolledWindow* m_panel_prv_right{nullptr};
|
||||
wxBoxSizer* m_sizer_prv_left{nullptr};
|
||||
wxBoxSizer* m_sizer_prv_right{nullptr};
|
||||
|
||||
// left panel related members
|
||||
ScalableBitmap m_humidity_image;
|
||||
wxStaticBitmap* m_humidity_img{nullptr};
|
||||
Label* m_image_description{nullptr};
|
||||
wxStaticBitmap* m_image_description_icon{nullptr};
|
||||
ScalableBitmap m_description_icon_bitmap;
|
||||
|
||||
Label* m_humidity_data_label = nullptr;
|
||||
Label* m_temperature_data_label = nullptr;
|
||||
Label* m_time_data_label = nullptr;
|
||||
wxBoxSizer* m_time_descrition_container = nullptr;
|
||||
|
||||
// right panel related members
|
||||
wxBoxSizer* m_normal_state_sizer{nullptr};
|
||||
wxBoxSizer* m_cannot_dry_sizer{nullptr};
|
||||
wxBoxSizer* m_dry_error_sizer{nullptr};
|
||||
Label* m_cannot_dry_description_label = nullptr;
|
||||
|
||||
// right panel normal state
|
||||
ComboBox* m_trays_combo;
|
||||
std::vector<FilamentBaseInfo> m_tray_ids;
|
||||
wxTextCtrl* m_temperature_input;
|
||||
wxTextCtrl* m_time_input;
|
||||
Label* m_normal_description;
|
||||
Button* m_start_button{nullptr};
|
||||
Button* m_next_button{nullptr};
|
||||
Button* m_stop_button{nullptr};
|
||||
Button* m_back_button{nullptr};
|
||||
Button* m_unload_button{nullptr};
|
||||
|
||||
// guide page description
|
||||
Label* m_guide_title_label{nullptr};
|
||||
Label* m_guide_description_label{nullptr};
|
||||
|
||||
wxCheckBox* m_rotate_spool_toggle{nullptr};
|
||||
|
||||
wxPanel* m_progress_page;
|
||||
ProgressBar* m_progress_gauge;
|
||||
wxTimer* m_progress_timer;
|
||||
|
||||
std::optional<std::chrono::steady_clock::time_point> m_stop_button_restore_deadline;
|
||||
std::optional<std::chrono::steady_clock::time_point> m_unload_button_restore_deadline;
|
||||
|
||||
Label* m_progress_title;
|
||||
int m_progress_value;
|
||||
int m_progress_message_index;
|
||||
std::vector<wxString> m_progress_text = {
|
||||
_L("Starting: Checking adapter connection"),
|
||||
_L("Starting: Checking filament status"),
|
||||
_L("Starting: Checking drying presets"),
|
||||
_L("Starting: Checking filament location"),
|
||||
_L("Starting: Checking air intake"),
|
||||
_L("Starting: Checking air vent")
|
||||
};
|
||||
|
||||
// Guide page
|
||||
wxPanel* m_guide_page{nullptr};
|
||||
AMSFilamentPanel* m_ams_filament_panel{nullptr};
|
||||
std::map<std::string, FilamentItemPanel*> m_filament_items;
|
||||
wxStaticBitmap* m_image_placeholder{nullptr};
|
||||
ScalableBitmap m_guide_image;
|
||||
|
||||
|
||||
bool m_is_ams_changed = false;
|
||||
std::weak_ptr<DevFilaSystem> m_fila_system;
|
||||
struct {
|
||||
std::string m_ams_id;
|
||||
DevAmsType m_model = DevAmsType::EXT_SPOOL;
|
||||
DevAms::DryStatus m_dry_status = DevAms::DryStatus::Off;
|
||||
DevAms::DrySubStatus m_dry_sub_status = DevAms::DrySubStatus::Off;
|
||||
int m_humidity_percent;
|
||||
int m_temperature;
|
||||
int m_left_dry_time;
|
||||
float m_recommand_dry_temp;
|
||||
} m_ams_info;
|
||||
|
||||
struct {
|
||||
std::unordered_map<std::string, std::string> m_filament_names;
|
||||
std::unordered_map<std::string, std::string> m_filament_type;
|
||||
std::unordered_map<std::string, int> m_dry_temp;
|
||||
std::unordered_map<std::string, int> m_dry_time;
|
||||
} m_dry_setting;
|
||||
|
||||
struct {
|
||||
bool m_is_printing = false;
|
||||
} m_printer_status;
|
||||
|
||||
private:
|
||||
void create();
|
||||
wxBoxSizer* create_guide_page_sizer(wxPanel* parent);
|
||||
wxBoxSizer* create_main_content_section(wxPanel* parent);
|
||||
wxBoxSizer* create_guide_info_filament(wxPanel* parent);
|
||||
wxBoxSizer* create_guide_info_section(wxPanel* parent);
|
||||
wxBoxSizer* create_guide_right_section(wxPanel* parent);
|
||||
wxBoxSizer* create_main_page_sizer(wxPanel* parent);
|
||||
wxBoxSizer* create_left_panel(wxPanel* parent);
|
||||
wxBoxSizer* create_humidity_status_section(wxPanel* parent);
|
||||
wxBoxSizer* create_description_item(wxPanel* parent, const wxString& title, Label*& dataLabel);
|
||||
wxBoxSizer* create_status_descriptions_section(wxPanel* parent);
|
||||
|
||||
wxBoxSizer* create_right_panel(wxPanel* parent);
|
||||
wxBoxSizer* create_normal_state_panel(wxPanel* parent);
|
||||
wxBoxSizer* create_cannot_dry_panel(wxPanel* parent);
|
||||
wxBoxSizer* create_drying_error_panel(wxPanel* parent);
|
||||
Button* create_button(wxPanel* parent, const wxString& title,
|
||||
const wxColour& background_color, const wxColour& border_color, const wxColour& text_color);
|
||||
|
||||
wxBoxSizer* create_progress_page_sizer(wxPanel* parent);
|
||||
void OnProgressTimer(wxTimerEvent& event);
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnShow(wxShowEvent& event);
|
||||
|
||||
void OnFilamentSelectionChanged(wxCommandEvent& event);
|
||||
|
||||
|
||||
wxScrolledWindow* create_preview_scrolled_window(wxWindow* parent);
|
||||
|
||||
bool check_values_changed(DevAms* dev_ams);
|
||||
int update_image(DevAmsType type, DevAms::DryStatus status, DevAms::DrySubStatus sub_status, int humidity_percent);
|
||||
void update_img_description(DevAms::DryStatus status, DevAms::DrySubStatus sub_status);
|
||||
void update_normal_description(DevAms* dev_ams);
|
||||
int update_state(DevAms* dev_ams);
|
||||
int update_dryness_status(DevAms* dev_ams);
|
||||
int update_ams_change(DevAms* dev_ams);
|
||||
int update_filament_list(DevAms* dev_ams, MachineObject* obj);
|
||||
void update_filament_guide_info(DevAms* dev_ams);
|
||||
void update_normal_state(DevAms* dev_ams);
|
||||
void update_printer_state(MachineObject* obj);
|
||||
|
||||
std::shared_ptr<DevFilaSystem> get_fila_system() const;
|
||||
void start_sending_drying_command();
|
||||
void restore_stop_button_if_deadline_passed();
|
||||
void restore_unload_button_if_deadline_passed();
|
||||
void update_button_size(Button* button);
|
||||
|
||||
bool is_dry_status_changed(DevAms* dev_ams);
|
||||
bool is_dry_ctr_idle(DevAms* dev_ams);
|
||||
bool is_ams_changed(DevAms* dev_ams);
|
||||
bool is_dry_ctr_idle();
|
||||
bool is_tray_changed(DevAms* dev_ams);
|
||||
bool is_dry_ctr_err(DevAms* dev_ams);
|
||||
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
@@ -41,6 +41,16 @@ enum AmsStatusMain
|
||||
AMS_STATUS_MAIN_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
enum DevAmsType : int
|
||||
{
|
||||
EXT_SPOOL = 0, // EXT
|
||||
AMS = 1, // AMS1
|
||||
AMS_LITE = 2, // AMS-Lite
|
||||
N3F = 3, // N3F, AMS 2PRO
|
||||
N3S = 4, // N3S, AMS HT
|
||||
AMS_LITE_MIXED = 5, // AMS-Lite for N9
|
||||
};
|
||||
|
||||
// Device-numbered filament-change step codes. Newer firmware reports the exact change-step
|
||||
// sequence through the AMS (ams.cfs), keyed by these codes, instead of the client hardcoding
|
||||
// steps per model. Distinct from the legacy GUI-side Slic3r::GUI::FilamentStep enum.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
#include "DevUtil.h"
|
||||
#include "DevUtilBackend.h"
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
@@ -99,6 +100,11 @@ std::string DevAmsTray::get_filament_type()
|
||||
return m_fila_type;
|
||||
}
|
||||
|
||||
std::optional<Slic3r::DevFilamentDryingPreset> DevAmsTray::get_ams_drying_preset() const
|
||||
{
|
||||
return DevUtilBackend::GetFilamentDryingPreset(setting_id);
|
||||
}
|
||||
|
||||
|
||||
DevAms::DevAms(const std::string& ams_id, int extruder_id, AmsType type)
|
||||
{
|
||||
@@ -112,7 +118,7 @@ DevAms::DevAms(const std::string& ams_id, int nozzle_id, int type)
|
||||
m_ams_id = ams_id;
|
||||
m_ext_id = nozzle_id;
|
||||
m_ams_type = (AmsType)type;
|
||||
assert(DUMMY < type && m_ams_type <= AMS_LITE_MIXED);
|
||||
assert(EXT_SPOOL < type && m_ams_type <= AMS_LITE_MIXED);
|
||||
}
|
||||
|
||||
DevAms::~DevAms()
|
||||
@@ -193,6 +199,27 @@ DevAmsTray* DevAms::GetTray(const std::string& tray_id) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DevAms::IsSupportRemoteDry(const MachineObject* obj) const
|
||||
{
|
||||
if (obj && obj->is_support_remote_dry) {
|
||||
return SupportDrying();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DevAms::AmsIsDrying()
|
||||
{
|
||||
if (!GetDryStatus().has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetDryStatus().value() == DevAms::DryStatus::Checking
|
||||
|| GetDryStatus().value() == DevAms::DryStatus::Drying
|
||||
|| GetDryStatus().value() == DevAms::DryStatus::Error
|
||||
|| GetDryStatus().value() == DevAms::DryStatus::CannotStopHeatOutofControl;
|
||||
}
|
||||
|
||||
DevFilaSystem::~DevFilaSystem()
|
||||
{
|
||||
for (auto it = amsList.begin(); it != amsList.end(); it++)
|
||||
@@ -515,9 +542,18 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
||||
;
|
||||
}
|
||||
|
||||
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
|
||||
|
||||
if (it->contains("temp"))
|
||||
{
|
||||
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
|
||||
std::string temp = (*it)["temp"].get<std::string>();
|
||||
try
|
||||
{
|
||||
curr_ams->m_current_temperature = DevUtil::string_to_float(temp);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (it->contains("humidity"))
|
||||
@@ -546,17 +582,32 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (it->contains("temp"))
|
||||
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
|
||||
{
|
||||
std::string temp = (*it)["temp"].get<std::string>();
|
||||
try
|
||||
{
|
||||
curr_ams->m_current_temperature = DevUtil::string_to_float(temp);
|
||||
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
|
||||
}
|
||||
|
||||
// Drying status — only parse if printer supports remote drying
|
||||
if (obj->is_support_remote_dry) {
|
||||
if (it->contains("info")) {
|
||||
const std::string& info = (*it)["info"].get<std::string>();
|
||||
curr_ams->m_dry_status = (DevAms::DryStatus)DevUtil::get_flag_bits(info, 4, 4);
|
||||
curr_ams->m_dry_fan1_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 18, 2);
|
||||
curr_ams->m_dry_fan2_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 20, 2);
|
||||
curr_ams->m_dry_sub_status = (DevAms::DrySubStatus)DevUtil::get_flag_bits(info, 22, 2);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE;
|
||||
|
||||
if (it->contains("dry_setting")) {
|
||||
const auto& j_dry_settings = (*it)["dry_setting"];
|
||||
DevAms::DrySettings dry_settings;
|
||||
DevJsonValParser::ParseVal(j_dry_settings, "dry_filament", dry_settings.dry_filament);
|
||||
DevJsonValParser::ParseVal(j_dry_settings, "dry_temperature", dry_settings.dry_temp);
|
||||
DevJsonValParser::ParseVal(j_dry_settings, "dry_duration", dry_settings.dry_hour);
|
||||
curr_ams->m_dry_settings = dry_settings;
|
||||
}
|
||||
|
||||
if (it->contains("dry_sf_reason")) {
|
||||
curr_ams->m_dry_cannot_reasons = DevJsonValParser::GetVal<std::vector<DevAms::CannotDryReason>>((*it), "dry_sf_reason");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
#include <wx/colour.h>
|
||||
|
||||
@@ -20,6 +23,7 @@
|
||||
namespace Slic3r
|
||||
{
|
||||
class MachineObject;
|
||||
struct DevFilamentDryingPreset;
|
||||
|
||||
/**
|
||||
* DevAmsTray - Represents a single filament tray/slot in an AMS unit or virtual tray.
|
||||
@@ -106,6 +110,8 @@ public:
|
||||
|
||||
// static
|
||||
static wxColour decode_color(const std::string& color);
|
||||
|
||||
std::optional<DevFilamentDryingPreset> get_ams_drying_preset() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -133,14 +139,67 @@ class DevAms
|
||||
{
|
||||
friend class DevFilaSystemParser;
|
||||
public:
|
||||
enum AmsType : int
|
||||
using AmsType = DevAmsType;
|
||||
static constexpr AmsType EXT_SPOOL = DevAmsType::EXT_SPOOL;
|
||||
static constexpr AmsType AMS = DevAmsType::AMS;
|
||||
static constexpr AmsType AMS_LITE = DevAmsType::AMS_LITE;
|
||||
static constexpr AmsType N3F = DevAmsType::N3F;
|
||||
static constexpr AmsType N3S = DevAmsType::N3S;
|
||||
static constexpr AmsType AMS_LITE_MIXED = DevAmsType::AMS_LITE_MIXED;
|
||||
|
||||
public:
|
||||
|
||||
enum class DryCtrlMode : int
|
||||
{
|
||||
DUMMY = 0,
|
||||
AMS = 1, // AMS
|
||||
AMS_LITE = 2, // AMS-Lite
|
||||
N3F = 3, // N3F
|
||||
N3S = 4, // N3S
|
||||
AMS_LITE_MIXED = 5, // AMS-Lite mixed (A2L / N9). Presents as AMS_LITE to generic callers; see GetAmsType()/IsAmsLiteMixed().
|
||||
Off = 0,
|
||||
OnTime = 1,
|
||||
OnHumidity = 2,
|
||||
};
|
||||
|
||||
enum class DryStatus : char
|
||||
{
|
||||
Off = 0,
|
||||
Checking = 1,
|
||||
Drying = 2,
|
||||
Cooling = 3,
|
||||
Stopping = 4,
|
||||
Error = 5,
|
||||
CannotStopHeatOutofControl = 6,
|
||||
PrdTesting = 7,
|
||||
};
|
||||
|
||||
enum class DrySubStatus
|
||||
{
|
||||
Off = 0,
|
||||
Heating = 1,
|
||||
Dehumidify = 2,
|
||||
};
|
||||
|
||||
enum class DryFanStatus : char
|
||||
{
|
||||
Off = 0,
|
||||
On = 1,
|
||||
};
|
||||
|
||||
enum class CannotDryReason : int
|
||||
{
|
||||
TaskOccupied = 0,
|
||||
InsufficientPower = 1,
|
||||
AmsBusy = 2,
|
||||
ConsumableAtAmsOutlet = 3,
|
||||
InitiatingAmsDrying = 4,
|
||||
NotSupportedIn2dMode = 5,
|
||||
DryingInProgress = 6,
|
||||
Upgrading = 7,
|
||||
InsufficientPowerNeedPluginPower = 8,
|
||||
FilamentAtAmsOutletManualUnload = 10,
|
||||
};
|
||||
|
||||
struct DrySettings
|
||||
{
|
||||
std::string dry_filament;
|
||||
int dry_temp = -1; // -1 means invalid
|
||||
int dry_hour = -1; // -1 means invalid, hours
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -193,11 +252,20 @@ public:
|
||||
int GetHumidityLevel() const { return m_humidity_level; }
|
||||
int GetHumidityPercent() const { return m_humidity_percent; }
|
||||
|
||||
// Only N3F/N3S dry. Written explicitly (not `> AMS_LITE`) so the new AMS_LITE_MIXED (N9) is
|
||||
// excluded; identical to the old expression for every pre-existing type.
|
||||
bool SupportDrying() const { return (m_ams_type == N3F) || (m_ams_type == N3S); }
|
||||
bool SupportDrying() const { return m_ams_type == DevAmsType::N3F || m_ams_type == DevAmsType::N3S; }
|
||||
int GetLeftDryTime() const { return m_left_dry_time; }
|
||||
|
||||
// remote drying control
|
||||
bool IsSupportRemoteDry(const MachineObject* obj) const;
|
||||
std::optional<DryStatus> GetDryStatus() const { return m_dry_status; };
|
||||
std::optional<DrySubStatus> GetDrySubStatus() const { return m_dry_sub_status; }
|
||||
std::optional<DryFanStatus> GetFan1Status() const { return m_dry_fan1_status; }
|
||||
std::optional<DryFanStatus> GetFan2Status() const { return m_dry_fan2_status; }
|
||||
std::optional<std::vector<CannotDryReason>> GetCannotDryReason() const { return m_dry_cannot_reasons; }
|
||||
std::optional<DrySettings> GetDrySettings() const { return m_dry_settings; };
|
||||
|
||||
bool AmsIsDrying();
|
||||
|
||||
private:
|
||||
AmsType m_ams_type = AmsType::AMS;
|
||||
std::string m_ams_id;
|
||||
@@ -218,6 +286,14 @@ private:
|
||||
int m_humidity_level = 5; // AmsType::AMS
|
||||
int m_humidity_percent = -1; // N3F N3S, the percentage, -1 means invalid. eg. 100 means 100%
|
||||
int m_left_dry_time = 0;
|
||||
|
||||
// see is_support_remote_dry
|
||||
std::optional<DryStatus> m_dry_status;
|
||||
std::optional<DrySubStatus> m_dry_sub_status;
|
||||
std::optional<DryFanStatus> m_dry_fan1_status;
|
||||
std::optional<DryFanStatus> m_dry_fan2_status;
|
||||
std::optional<std::vector<CannotDryReason>> m_dry_cannot_reasons;
|
||||
std::optional<DrySettings> m_dry_settings;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -299,7 +375,11 @@ public:
|
||||
public:
|
||||
// ctrls
|
||||
int CtrlAmsReset() const;
|
||||
|
||||
|
||||
// crtl
|
||||
int CtrlAmsStartDryingHour(int ams_id, std::string filament_type, int tag_temp, int tag_duration_hour, bool rotate_tray, int cooling_temp, bool close_power_conflict = false) const;
|
||||
int CtrlAmsStopDrying(int ams_id) const;
|
||||
|
||||
public:
|
||||
static bool IsBBL_Filament(std::string tag_uid);
|
||||
|
||||
@@ -337,4 +417,18 @@ public:
|
||||
static void ParseV1_0(const json& print_json, MachineObject* obj, DevFilaSystem* system, bool key_field_only);
|
||||
};
|
||||
|
||||
struct DevFilamentDryingPreset
|
||||
{
|
||||
std::string filament_id;
|
||||
|
||||
std::unordered_set<DevAmsType> ams_limitations; // only use ams types in the set
|
||||
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_idle; // hour
|
||||
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_idle;
|
||||
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_print; // hour
|
||||
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_print;
|
||||
float filament_dev_drying_cooling_temperature = 0.0f;
|
||||
float filament_dev_drying_softening_temperature = 0.0f;
|
||||
float filament_dev_ams_drying_heat_distortion_temperature = 0.0f;
|
||||
};
|
||||
|
||||
}// namespace Slic3r
|
||||
@@ -16,4 +16,44 @@ int DevFilaSystem::CtrlAmsReset() const
|
||||
return m_owner->publish_json(jj_command);
|
||||
}
|
||||
|
||||
int DevFilaSystem::CtrlAmsStartDryingHour(int ams_id,
|
||||
std::string filament_type,
|
||||
int tag_temp,
|
||||
int tag_duration_hour,
|
||||
bool rotate_tray,
|
||||
int cooling_temp,
|
||||
bool close_power_conflict) const
|
||||
{
|
||||
json jj_command;
|
||||
jj_command["print"]["command"] = "ams_filament_drying";
|
||||
jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||
jj_command["print"]["ams_id"] = ams_id;
|
||||
jj_command["print"]["mode"] = static_cast<int>(DevAms::DryCtrlMode::OnTime);
|
||||
jj_command["print"]["filament"] = filament_type;
|
||||
jj_command["print"]["temp"] = tag_temp;
|
||||
jj_command["print"]["duration"] = tag_duration_hour;
|
||||
jj_command["print"]["humidity"] = 0;
|
||||
jj_command["print"]["rotate_tray"] = rotate_tray;
|
||||
jj_command["print"]["cooling_temp"] = cooling_temp;
|
||||
jj_command["print"]["close_power_conflict"] = close_power_conflict;
|
||||
return m_owner->publish_json(jj_command);
|
||||
}
|
||||
|
||||
int DevFilaSystem::CtrlAmsStopDrying(int ams_id) const
|
||||
{
|
||||
json jj_command;
|
||||
jj_command["print"]["command"] = "ams_filament_drying";
|
||||
jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||
jj_command["print"]["ams_id"] = ams_id;
|
||||
jj_command["print"]["mode"] = static_cast<int>(DevAms::DryCtrlMode::Off);
|
||||
jj_command["print"]["filament"] = "";
|
||||
jj_command["print"]["temp"] = 0;
|
||||
jj_command["print"]["duration"] = 0;
|
||||
jj_command["print"]["humidity"] = 0;
|
||||
jj_command["print"]["rotate_tray"] = false;
|
||||
jj_command["print"]["cooling_temp"] = 0;
|
||||
jj_command["print"]["close_power_conflict"] = false;
|
||||
return m_owner->publish_json(jj_command);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace Slic3r
|
||||
}
|
||||
}
|
||||
FilamentInfo info;
|
||||
_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::DUMMY, tray, info);
|
||||
_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::EXT_SPOOL, tray, info);
|
||||
tray_filaments.emplace(std::make_pair(info.tray_id, info));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include "DevUtilBackend.h"
|
||||
|
||||
#include "slic3r/GUI/BackgroundSlicingProcess.hpp"
|
||||
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
@@ -15,4 +19,68 @@ std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> DevUtilBackend::GetNozz
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, DevAmsType> s_ams_type_map = {
|
||||
{"0", DevAmsType::N3F},
|
||||
{"1", DevAmsType::N3S},
|
||||
};
|
||||
|
||||
std::optional<Slic3r::DevFilamentDryingPreset> DevUtilBackend::GetFilamentDryingPreset(const std::string& fila_id)
|
||||
{
|
||||
if (fila_id.empty() || !GUI::wxGetApp().preset_bundle) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for (auto iter = GUI::wxGetApp().preset_bundle->filaments.begin(); iter != GUI::wxGetApp().preset_bundle->filaments.end(); ++iter) {
|
||||
const Preset& filament_preset = *iter;
|
||||
const auto& config = filament_preset.config;
|
||||
if (filament_preset.filament_id == fila_id) {
|
||||
DevFilamentDryingPreset info;
|
||||
info.filament_id = fila_id;
|
||||
try {
|
||||
if (config.has("filament_dev_ams_drying_ams_limitations")) {
|
||||
std::vector<std::string> types = config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values;
|
||||
for (auto type : types) {
|
||||
if (s_ams_type_map.count(type) == 0) {
|
||||
continue;
|
||||
}
|
||||
info.ams_limitations.insert(s_ams_type_map[type]);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.has("filament_dev_ams_drying_temperature")) {
|
||||
info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(0);
|
||||
info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(1);
|
||||
info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(2);
|
||||
info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(3);
|
||||
}
|
||||
|
||||
if (config.has("filament_dev_ams_drying_time")) {
|
||||
info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(0);
|
||||
info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(1);
|
||||
info.filament_dev_ams_drying_time_on_print[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(2);
|
||||
info.filament_dev_ams_drying_time_on_print[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(3);
|
||||
}
|
||||
|
||||
if (config.has("filament_dev_drying_softening_temperature")) {
|
||||
info.filament_dev_drying_softening_temperature = config.option<ConfigOptionFloats>("filament_dev_drying_softening_temperature")->get_at(0);
|
||||
}
|
||||
|
||||
if (config.has("filament_dev_ams_drying_heat_distortion_temperature")) {
|
||||
info.filament_dev_ams_drying_heat_distortion_temperature = config.option<ConfigOptionFloats>("filament_dev_ams_drying_heat_distortion_temperature")->get_at(0);
|
||||
}
|
||||
|
||||
if (config.has("filament_dev_drying_cooling_temperature")) {
|
||||
info.filament_dev_drying_cooling_temperature = config.option<ConfigOptionFloats>("filament_dev_drying_cooling_temperature")->get_at(0);
|
||||
}
|
||||
|
||||
return info;
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " exception: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
/**
|
||||
* @file DevUtilBackend.h
|
||||
* @brief Static helpers bridging the backend (slicer/preset) to the device GUI.
|
||||
*
|
||||
* Scope (H2C nozzle rack): exposes only GetNozzleGroupResult — the accessor the print-dispatch
|
||||
* nozzle-mapping V1 request and result-resolve helpers read. Related helpers (per-nozzle info
|
||||
* collection via the ExtruderNozzleInfos/NozzleDef type pair, and the drying-preset lookup) are
|
||||
* not implemented here and left to the consuming code.
|
||||
* @brief Provides common static utility methods for backend (preset/slicing).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "DevDefs.h"
|
||||
#include "DevFilaSystem.h"
|
||||
|
||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
@@ -23,10 +20,15 @@ class DevUtilBackend
|
||||
public:
|
||||
DevUtilBackend() = delete;
|
||||
|
||||
public:
|
||||
|
||||
// for rack: the slicer's per-filament -> logical-nozzle grouping for the current plate, read off
|
||||
// the post-slice GCodeProcessorResult (plater->background_process().get_current_gcode_result()).
|
||||
// Returns nullptr when there is no plater / no current result.
|
||||
static std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> GetNozzleGroupResult(Slic3r::GUI::Plater* plater);
|
||||
|
||||
// for filament preset
|
||||
static std::optional<DevFilamentDryingPreset> GetFilamentDryingPreset(const std::string& fila_id);
|
||||
};
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
@@ -568,7 +568,7 @@ MachineObject::MachineObject(DeviceManager* manager, NetworkAgent* agent, std::s
|
||||
m_extder_system = new DevExtderSystem(this);
|
||||
m_extension_tool = DevExtensionTool::Create(this);
|
||||
m_nozzle_system = new DevNozzleSystem(this);
|
||||
m_fila_system = new DevFilaSystem(this);
|
||||
m_fila_system = std::make_shared<DevFilaSystem>(this);
|
||||
m_fila_switch = new DevFilaSwitch(this);
|
||||
m_hms_system = new DevHMS(this);
|
||||
m_config = new DevConfig(this);
|
||||
@@ -617,8 +617,6 @@ MachineObject::~MachineObject()
|
||||
delete m_ctrl;
|
||||
m_ctrl = nullptr;
|
||||
|
||||
delete m_fila_system;
|
||||
m_fila_system = nullptr;
|
||||
|
||||
delete m_fila_switch;
|
||||
m_fila_switch = nullptr;
|
||||
@@ -3770,7 +3768,7 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
||||
update_printer_preset_name();
|
||||
update_filament_list();
|
||||
if (jj.contains("ams")) {
|
||||
DevFilaSystemParser::ParseV1_0(jj, this, m_fila_system, key_field_only);
|
||||
DevFilaSystemParser::ParseV1_0(jj, this, m_fila_system.get(), key_field_only);
|
||||
}
|
||||
|
||||
/* vitrual tray*/
|
||||
@@ -5095,6 +5093,7 @@ void MachineObject::parse_new_info(json print)
|
||||
// fun2 may have infinite length, use get_flag_bits_no_border
|
||||
if (!fun2.empty()) {
|
||||
is_support_print_with_emmc = get_flag_bits_no_border(fun2, 0) == 1;
|
||||
is_support_remote_dry = (get_flag_bits_no_border(fun2, 5) == 1);
|
||||
is_support_check_track_switch_match_slice_printer = get_flag_bits_no_border(fun2, 19) == 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
std::shared_ptr<DevExtensionTool> m_extension_tool;
|
||||
DevExtderSystem* m_extder_system;
|
||||
DevNozzleSystem* m_nozzle_system;
|
||||
DevFilaSystem* m_fila_system;
|
||||
std::shared_ptr<DevFilaSystem> m_fila_system;
|
||||
DevFilaSwitch* m_fila_switch;
|
||||
DevFan* m_fan;
|
||||
DevBed * m_bed;
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
std::shared_ptr<DevNozzleMappingCtrl> get_nozzle_mapping_result() const { return m_nozzle_mapping_ptr; }
|
||||
void clear_auto_nozzle_mapping();// defined in DevMappingNozzle.cpp
|
||||
|
||||
DevFilaSystem* GetFilaSystem() const { return m_fila_system;}
|
||||
std::shared_ptr<DevFilaSystem> GetFilaSystem() const { return m_fila_system;}
|
||||
DevFilaSwitch* GetFilaSwitch() const { return m_fila_switch;}
|
||||
bool HasAms() const;
|
||||
|
||||
@@ -635,6 +635,7 @@ public:
|
||||
|
||||
// fun2
|
||||
bool is_support_print_with_emmc{false};
|
||||
bool is_support_remote_dry = false;
|
||||
bool is_support_check_track_switch_match_slice_printer{false};
|
||||
|
||||
bool installed_upgrade_kit{false};
|
||||
|
||||
@@ -2338,11 +2338,6 @@ void GLCanvas3D::remove_curr_plate_all()
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_plate_thumbnails()
|
||||
{
|
||||
_update_imgui_select_plate_toolbar();
|
||||
}
|
||||
|
||||
void GLCanvas3D::select_all()
|
||||
{
|
||||
if (!m_gizmos.is_allow_select_all()) {
|
||||
@@ -3223,7 +3218,6 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
||||
// BBS
|
||||
//m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
|
||||
m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
|
||||
_update_imgui_select_plate_toolbar();
|
||||
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
|
||||
m_dirty |= mouse3d_controller_applied;
|
||||
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
|
||||
@@ -4833,11 +4827,6 @@ void GLCanvas3D::force_set_focus() {
|
||||
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_all_plate_thumbnails();
|
||||
_update_imgui_select_plate_toolbar();
|
||||
}
|
||||
_refresh_if_shown_on_screen();
|
||||
m_tooltip_enabled = true;
|
||||
m_is_touchpad_navigation = wxGetApp().app_config->get_bool("camera_navigation_style");
|
||||
@@ -6920,13 +6909,28 @@ void GLCanvas3D::_update_select_plate_toolbar_stats_item(bool force_selected) {
|
||||
bool GLCanvas3D::_update_imgui_select_plate_toolbar()
|
||||
{
|
||||
bool result = true;
|
||||
if (!m_sel_plate_toolbar.is_enabled() || m_sel_plate_toolbar.is_render_finish) return false;
|
||||
if (!m_sel_plate_toolbar.is_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& p_plater = wxGetApp().plater();
|
||||
if (!p_plater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p_plater->is_plate_toolbar_image_dirty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p_plater->is_gcode_3mf()) {
|
||||
p_plater->update_all_plate_thumbnails(true);
|
||||
}
|
||||
|
||||
_update_select_plate_toolbar_stats_item();
|
||||
|
||||
m_sel_plate_toolbar.del_all_item();
|
||||
|
||||
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
|
||||
PartPlateList& plate_list = p_plater->get_partplate_list();
|
||||
for (int i = 0; i < plate_list.get_plate_count(); i++) {
|
||||
IMToolbarItem* item = new IMToolbarItem();
|
||||
PartPlate* plate = plate_list.get_plate(i);
|
||||
@@ -6939,7 +6943,7 @@ bool GLCanvas3D::_update_imgui_select_plate_toolbar()
|
||||
}
|
||||
m_sel_plate_toolbar.m_items.push_back(item);
|
||||
}
|
||||
|
||||
p_plater->clear_plate_toolbar_image_dirty();
|
||||
m_sel_plate_toolbar.is_display_scrollbar = false;
|
||||
return result;
|
||||
}
|
||||
@@ -8797,6 +8801,8 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
|
||||
return;
|
||||
}
|
||||
|
||||
_update_imgui_select_plate_toolbar();
|
||||
|
||||
IMToolbarItem* all_plates_stats_item = m_sel_plate_toolbar.m_all_plates_stats_item;
|
||||
|
||||
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
|
||||
@@ -9213,7 +9219,6 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
|
||||
m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered;
|
||||
|
||||
imgui.end();
|
||||
m_sel_plate_toolbar.is_render_finish = true;
|
||||
}
|
||||
|
||||
//BBS: GUI refactor: GLToolbar adjust
|
||||
|
||||
@@ -997,7 +997,6 @@ public:
|
||||
void select_curr_plate_all();
|
||||
void select_object_from_idx(std::vector<int>& object_idxs);
|
||||
void remove_curr_plate_all();
|
||||
void update_plate_thumbnails();
|
||||
|
||||
void select_all();
|
||||
void deselect_all();
|
||||
|
||||
@@ -61,8 +61,6 @@ void IMToolbar::del_stats_item()
|
||||
void IMToolbar::set_enabled(bool enable)
|
||||
{
|
||||
m_enabled = enable;
|
||||
if (!m_enabled)
|
||||
is_render_finish = false;
|
||||
}
|
||||
|
||||
bool IMReturnToolbar::init()
|
||||
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
float icon_height;
|
||||
bool is_display_scrollbar;
|
||||
bool show_stats_item{ false };
|
||||
bool is_render_finish{false};
|
||||
IMToolbar() {
|
||||
icon_width = DEFAULT_TOOLBAR_BUTTON_WIDTH;
|
||||
icon_height = DEFAULT_TOOLBAR_BUTTON_HEIGHT;
|
||||
|
||||
@@ -3158,6 +3158,9 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
||||
shader->set_uniform("Texture", 0);
|
||||
shader->set_uniform("ProjMtx", ortho_projection);
|
||||
|
||||
const uint8_t stage = 0;
|
||||
shader->set_uniform("s_texture", stage);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
const ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
const ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
@@ -3222,6 +3225,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
|
||||
glsafe(::glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
|
||||
|
||||
// Bind texture, Draw
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0 + stage));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
|
||||
glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
|
||||
}
|
||||
|
||||
@@ -348,6 +348,8 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
}
|
||||
m_plater->update();
|
||||
}
|
||||
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -266,7 +266,12 @@ bool OpenGLManager::init_gl(bool popup_error)
|
||||
else
|
||||
s_compressed_textures_supported = false;
|
||||
|
||||
if (GLAD_GL_ARB_framebuffer_object) {
|
||||
if (s_gl_info.is_version_greater_or_equal_to(3, 0)) {
|
||||
// ARB framebuffer became a mandatory part of core OpenGL 3.0
|
||||
s_framebuffers_type = EFramebufferType::Arb;
|
||||
BOOST_LOG_TRIVIAL(info) << "Opengl version >= 30, FrameBuffer Type ARB." << std::endl;
|
||||
}
|
||||
else if (GLAD_GL_ARB_framebuffer_object) {
|
||||
s_framebuffers_type = EFramebufferType::Arb;
|
||||
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl;
|
||||
}
|
||||
|
||||
@@ -2433,6 +2433,9 @@ void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height
|
||||
m_depth = depth;
|
||||
m_height = height;
|
||||
|
||||
if (with_instance_move && m_plater)
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2780,6 +2783,8 @@ int PartPlate::add_instance(int obj_id, int instance_id, bool move_position, Bou
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1% , m_ready_for_slice changes to %2%") % m_plate_index %m_ready_for_slice;
|
||||
if (m_plater)
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5344,6 +5349,9 @@ int PartPlateList::notify_instance_removed(int obj_id, int instance_id)
|
||||
unprintable_plate.update_object_index(obj_id, m_model->objects.size());
|
||||
}
|
||||
|
||||
if (m_plater)
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6265,6 +6273,9 @@ int PartPlateList::rebuild_plates_after_arrangement(bool recycle_plates, bool ex
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_plater)
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":after rebuild, plates count %1%") % m_plate_list.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -277,6 +277,21 @@ void Plater::show_illegal_characters_warning(wxWindow* parent)
|
||||
show_error(parent, _L("Invalid name, the following characters are not allowed:") + " <>:/\\|?*\"");
|
||||
}
|
||||
|
||||
void Plater::mark_plate_toolbar_image_dirty()
|
||||
{
|
||||
m_b_plate_toolbar_image_dirty = true;
|
||||
}
|
||||
|
||||
bool Plater::is_plate_toolbar_image_dirty() const
|
||||
{
|
||||
return m_b_plate_toolbar_image_dirty;
|
||||
}
|
||||
|
||||
void Plater::clear_plate_toolbar_image_dirty()
|
||||
{
|
||||
m_b_plate_toolbar_image_dirty = false;
|
||||
}
|
||||
|
||||
static std::map<BedType, std::string> bed_type_thumbnails = {
|
||||
{BedType::btPC, "bed_cool" },
|
||||
{BedType::btEP, "bed_engineering" },
|
||||
@@ -6326,10 +6341,8 @@ void Plater::priv::update(unsigned int flags)
|
||||
//BBS assemble view
|
||||
this->assemble_view->reload_scene(false, flags);
|
||||
|
||||
if (current_panel && is_preview_shown()) {
|
||||
q->force_update_all_plate_thumbnails();
|
||||
//update_fff_scene_only_shells(true);
|
||||
}
|
||||
// todo: better to mark thumbnail dirty here
|
||||
q->mark_plate_toolbar_image_dirty();
|
||||
|
||||
if (force_background_processing_restart)
|
||||
this->restart_background_process(update_status);
|
||||
@@ -7884,6 +7897,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
}
|
||||
}
|
||||
q->schedule_background_process(true);
|
||||
q->mark_plate_toolbar_image_dirty();
|
||||
return obj_idxs;
|
||||
}
|
||||
|
||||
@@ -8263,6 +8277,8 @@ void Plater::priv::object_list_changed()
|
||||
main_frame->update_slice_print_status(MainFrame::eEventObjectUpdate, can_slice);
|
||||
|
||||
wxGetApp().params_panel()->notify_object_config_changed();
|
||||
|
||||
q->mark_plate_toolbar_image_dirty();
|
||||
}
|
||||
|
||||
void Plater::priv::select_curr_plate_all()
|
||||
@@ -9166,6 +9182,8 @@ void Plater::priv::update_fff_scene()
|
||||
view3D->reload_scene(true);
|
||||
//BBS: add assemble view related logic
|
||||
assemble_view->reload_scene(true);
|
||||
|
||||
q->mark_plate_toolbar_image_dirty();
|
||||
}
|
||||
|
||||
//BBS: add print project related logic
|
||||
@@ -10074,9 +10092,6 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
|
||||
preview->get_canvas3d()->enable_select_plate_toolbar(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
preview->get_canvas3d()->enable_select_plate_toolbar(false);
|
||||
}
|
||||
|
||||
if (current_panel == panel)
|
||||
{
|
||||
@@ -10935,6 +10950,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":finished, reload print soon");
|
||||
m_is_slicing = false;
|
||||
this->preview->reload_print(false);
|
||||
q->mark_plate_toolbar_image_dirty();
|
||||
/* BBS if in publishing progress */
|
||||
if (m_is_publishing) {
|
||||
if (m_publish_dlg && !m_publish_dlg->was_cancelled()) {
|
||||
@@ -13913,8 +13929,13 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
|
||||
_obj->config.set_key_value("seam_slope_type", new ConfigOptionEnum<SeamScarfType>(SeamScarfType::None));
|
||||
_obj->config.set_key_value("gap_fill_target", new ConfigOptionEnum<GapFillTarget>(GapFillTarget::gftNowhere));
|
||||
print_config->set_key_value("max_volumetric_extrusion_rate_slope", new ConfigOptionFloat(0));
|
||||
// ORCA: print the top surface spiral from the center outwards, so the tiles are comparable.
|
||||
_obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Outward));
|
||||
// ORCA: request the calibration's special toolpath order (chords first, center spiral
|
||||
// last and inside-out) so opposing directions collide into the tactile lip the test
|
||||
// reads. The special order only applies while the fill order is Default, so reset the
|
||||
// profile's fill order on the calibration objects; changing the setting on the object
|
||||
// afterwards deliberately overrides the special order.
|
||||
_obj->config.set_key_value("calib_flowrate_topinfill_special_order", new ConfigOptionBool(true));
|
||||
_obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Default));
|
||||
|
||||
// extract flowrate from name, filename format: flowrate_xxx
|
||||
std::string obj_name = _obj->name;
|
||||
@@ -14651,6 +14672,7 @@ void Plater::invalid_all_plate_thumbnails()
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
}
|
||||
mark_plate_toolbar_image_dirty();
|
||||
}
|
||||
|
||||
void Plater::force_update_all_plate_thumbnails()
|
||||
@@ -14661,7 +14683,6 @@ void Plater::force_update_all_plate_thumbnails()
|
||||
invalid_all_plate_thumbnails();
|
||||
update_all_plate_thumbnails(true);
|
||||
}
|
||||
get_preview_canvas3D()->update_plate_thumbnails();
|
||||
}
|
||||
|
||||
// BBS: backup
|
||||
|
||||
@@ -936,6 +936,10 @@ public:
|
||||
|
||||
bool is_loading_project() const { return m_loading_project; }
|
||||
|
||||
void mark_plate_toolbar_image_dirty();
|
||||
bool is_plate_toolbar_image_dirty() const;
|
||||
void clear_plate_toolbar_image_dirty();
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
@@ -956,6 +960,7 @@ private:
|
||||
std::string m_preview_only_filename;
|
||||
int m_valid_plates_count { 0 };
|
||||
int m_check_status = 0; // 0 not check, 1 check success, 2 check failed
|
||||
bool m_b_plate_toolbar_image_dirty{ true };
|
||||
|
||||
void suppress_snapshots();
|
||||
void allow_snapshots();
|
||||
|
||||
@@ -521,6 +521,14 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
//m_change_filament_times_sizer->Add(m_img_change_filament_times, 0, wxTOP, FromDIP(2));
|
||||
m_change_filament_times_sizer->Add(m_txt_change_filament_times, 0, wxTOP, 0);
|
||||
|
||||
m_warn_when_drying_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_txt_warn_when_drying = new Label(m_scroll_area, wxEmptyString);
|
||||
m_txt_warn_when_drying->SetFont(::Label::Body_13);
|
||||
m_txt_warn_when_drying->SetForegroundColour(wxColour("#F09A17"));
|
||||
m_txt_warn_when_drying->SetBackgroundColour(*wxWHITE);
|
||||
m_txt_warn_when_drying->SetLabel(_L("To ensure print quality, the drying temperature will be lowered during printing."));
|
||||
m_warn_when_drying_sizer->Add(m_txt_warn_when_drying, 0, wxTOP, FromDIP(2));
|
||||
|
||||
/*Advanced Options*/
|
||||
wxBoxSizer* sizer_split_options = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto m_split_options_line = new wxPanel(m_scroll_area, wxID_ANY);
|
||||
@@ -735,6 +743,8 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
m_scroll_sizer->Add(m_change_filament_times_sizer, 0,wxLEFT|wxRIGHT, FromDIP(15));
|
||||
// m_scroll_sizer->Add(m_link_edit_nozzle, 0, wxLEFT|wxRIGHT, FromDIP(15));
|
||||
m_scroll_sizer->Add(suggestion_sizer, 0, wxLEFT|wxRIGHT|wxEXPAND, FromDIP(15));
|
||||
m_scroll_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
|
||||
m_scroll_sizer->Add(m_warn_when_drying_sizer, 0, wxLEFT|wxRIGHT, FromDIP(15));
|
||||
m_scroll_sizer->Add(sizer_split_options, 1, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15));
|
||||
m_scroll_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
|
||||
m_scroll_sizer->Add(m_options_other, 0, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15));
|
||||
@@ -1734,6 +1744,47 @@ bool SelectMachineDialog::CheckErrorSyncNozzleMappingResultV0(MachineObject* obj
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SelectMachineDialog::is_ams_drying(MachineObject* obj)
|
||||
{
|
||||
const auto& ams_list = obj->GetFilaSystem()->GetAmsList();
|
||||
for (auto ams = ams_list.begin(); ams != ams_list.end(); ams++) {
|
||||
if (ams->second->AmsIsDrying()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SelectMachineDialog::is_selected_ams_drying(MachineObject* obj)
|
||||
{
|
||||
if (!obj) return false;
|
||||
|
||||
// If a UI material is selected, only when that material is mapped to an AMS
|
||||
// and that AMS is currently drying.
|
||||
for (const auto &kv : m_materialList) {
|
||||
Material *mat = kv.second;
|
||||
if (!mat || !mat->item) continue;
|
||||
if (!mat->item->m_selected) continue;
|
||||
|
||||
// find mapping entry for this material id
|
||||
for (const FilamentInfo &f : m_ams_mapping_result) {
|
||||
if (f.id != mat->id) continue;
|
||||
|
||||
if (f.ams_id.empty()) return false;
|
||||
|
||||
auto fila_system = obj->GetFilaSystem();
|
||||
if (!fila_system) return false;
|
||||
DevAms* dev_ams = fila_system->GetAmsById(f.ams_id);
|
||||
return (dev_ams && dev_ams->AmsIsDrying());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SelectMachineDialog::prepare(int print_plate_idx)
|
||||
{
|
||||
m_print_plate_idx = print_plate_idx;
|
||||
@@ -3888,6 +3939,16 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
m_check_ext_change_assist->Enable(false);
|
||||
}
|
||||
|
||||
{
|
||||
const bool show_warn_when_drying = is_selected_ams_drying(obj_);
|
||||
const bool is_currently_shown = (m_txt_warn_when_drying != nullptr) ? m_txt_warn_when_drying->IsShown() : false;
|
||||
if (is_currently_shown != show_warn_when_drying) {
|
||||
m_warn_when_drying_sizer->Show(show_warn_when_drying);
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
}
|
||||
|
||||
/*reading done*/
|
||||
if (wxGetApp().app_config) {
|
||||
if (obj_->upgrade_force_upgrade) {
|
||||
@@ -4404,6 +4465,7 @@ void SelectMachineDialog::set_default()
|
||||
m_mapping_sugs_sizer->Show(false);
|
||||
m_change_filament_times_sizer->Show(false);
|
||||
m_txt_change_filament_times->Show(false);
|
||||
m_warn_when_drying_sizer->Show(false);
|
||||
|
||||
// rset status bar
|
||||
m_status_bar->reset();
|
||||
@@ -4513,6 +4575,10 @@ void SelectMachineDialog::reset_and_sync_ams_list()
|
||||
m_filaments_map = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_real_filament_maps(project_config);
|
||||
}
|
||||
|
||||
bool selected_any = false;
|
||||
MaterialItem *first_enabled = nullptr;
|
||||
int first_enabled_id = -1;
|
||||
|
||||
for (auto i = 0; i < extruders.size(); i++) {
|
||||
auto extruder = extruders[i] - 1;
|
||||
auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int) extruder);
|
||||
@@ -4542,7 +4608,20 @@ void SelectMachineDialog::reset_and_sync_ams_list()
|
||||
item = new MaterialItem(m_filament_panel, colour_rgb, _L(display_materials[extruder]));
|
||||
m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5));
|
||||
}
|
||||
|
||||
if (!item) continue;
|
||||
|
||||
item->SetToolTip(m_ams_tooltip);
|
||||
|
||||
if (!selected_any && extruder == m_current_filament_id && item->m_enable) {
|
||||
item->on_selected();
|
||||
selected_any = true;
|
||||
}
|
||||
if (!first_enabled && item->m_enable) {
|
||||
first_enabled = item;
|
||||
first_enabled_id = extruder;
|
||||
}
|
||||
|
||||
item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {});
|
||||
item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent &e) {
|
||||
if (!item->m_enable) {return;}
|
||||
@@ -4621,6 +4700,11 @@ void SelectMachineDialog::reset_and_sync_ams_list()
|
||||
}
|
||||
}
|
||||
|
||||
if (!selected_any && first_enabled) {
|
||||
m_current_filament_id = first_enabled_id;
|
||||
first_enabled->on_selected();
|
||||
}
|
||||
|
||||
if (use_double_extruder)
|
||||
{
|
||||
m_filament_left_panel->Show();
|
||||
@@ -5031,6 +5115,10 @@ void SelectMachineDialog::set_default_from_sdcard()
|
||||
m_materialList.clear();
|
||||
m_filaments.clear();
|
||||
|
||||
bool selected_any = false;
|
||||
MaterialItem *first_enabled = nullptr;
|
||||
int first_enabled_id = -1;
|
||||
|
||||
for (auto i = 0; i < m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size(); i++) {
|
||||
FilamentInfo fo = m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info[i];
|
||||
|
||||
@@ -5053,6 +5141,17 @@ void SelectMachineDialog::set_default_from_sdcard()
|
||||
m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5));
|
||||
}
|
||||
|
||||
if (!item) continue;
|
||||
|
||||
if (!selected_any && fo.id == m_current_filament_id && item->m_enable) {
|
||||
item->on_selected();
|
||||
selected_any = true;
|
||||
}
|
||||
if (!first_enabled && item->m_enable) {
|
||||
first_enabled = item;
|
||||
first_enabled_id = fo.id;
|
||||
}
|
||||
|
||||
item->Bind(wxEVT_LEFT_UP, [this, item, materials](wxMouseEvent& e) {});
|
||||
item->Bind(wxEVT_LEFT_DOWN, [this, obj_, item, materials, diameters_count, fo](wxMouseEvent& e) {
|
||||
if (!item->m_enable) {return;}
|
||||
@@ -5129,6 +5228,11 @@ void SelectMachineDialog::set_default_from_sdcard()
|
||||
wxSize screenSize = wxGetDisplaySize();
|
||||
auto dialogSize = this->GetSize();
|
||||
|
||||
if (!selected_any && first_enabled) {
|
||||
m_current_filament_id = first_enabled_id;
|
||||
first_enabled->on_selected();
|
||||
}
|
||||
|
||||
reset_ams_material();
|
||||
|
||||
// basic info
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "boost/bimap/bimap.hpp"
|
||||
#include "AmsMappingPopup.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "ReleaseNote.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
@@ -354,6 +355,7 @@ protected:
|
||||
wxBoxSizer* m_sizer_autorefill{ nullptr };
|
||||
wxBoxSizer* m_mapping_sugs_sizer{ nullptr };
|
||||
wxBoxSizer* m_change_filament_times_sizer{ nullptr };
|
||||
wxBoxSizer* m_warn_when_drying_sizer{ nullptr };
|
||||
Button* m_button_ensure{ nullptr };
|
||||
wxStaticBitmap * m_rename_button{nullptr};
|
||||
wxStaticBitmap* m_staticbitmap{ nullptr };
|
||||
@@ -387,6 +389,8 @@ protected:
|
||||
CheckBox* m_check_ext_change_assist{ nullptr };
|
||||
Label* m_label_ext_change_assist{ nullptr };
|
||||
|
||||
Label* m_txt_warn_when_drying{ nullptr };
|
||||
|
||||
PrinterInfoBox* m_printer_box { nullptr};
|
||||
PrinterMsgPanel * m_text_printer_msg{nullptr};
|
||||
Label* m_text_printer_msg_tips{ nullptr };
|
||||
@@ -542,6 +546,9 @@ public:
|
||||
bool CheckErrorDynamicSwitchNozzle(MachineObject* obj_);
|
||||
void on_flow_cali_option_changed();
|
||||
|
||||
bool is_ams_drying(MachineObject* obj);
|
||||
bool is_selected_ams_drying(MachineObject* obj);
|
||||
|
||||
PrintFromType get_print_type() {return m_print_type;};
|
||||
wxString format_steel_name(NozzleType type);
|
||||
PrintDialogStatus get_status() { return m_print_status; }
|
||||
|
||||
@@ -3392,6 +3392,7 @@ void StatusPanel::update_ams(MachineObject *obj)
|
||||
|
||||
// must select a current can
|
||||
m_ams_control->UpdateAms(obj->get_printer_series_str(), obj->printer_type, ams_info, ext_info, *obj->GetExtderSystem(), obj->get_dev_id(), false);
|
||||
m_ams_control->UpdateAmsDryControl(obj);
|
||||
|
||||
last_tray_exist_bits = obj->tray_exist_bits;
|
||||
last_ams_exist_bits = obj->ams_exist_bits;
|
||||
|
||||
@@ -31,6 +31,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
||||
, m_Humidity_tip_popup(AmsHumidityTipPopup(this))
|
||||
, m_percent_humidity_dry_popup(new uiAmsPercentHumidityDryPopup(this))
|
||||
, m_ams_introduce_popup(AmsIntroducePopup(this))
|
||||
, m_ams_dry_ctr_win(new AMSDryCtrWin(this))
|
||||
{
|
||||
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (dev) {
|
||||
@@ -252,6 +253,12 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
||||
uiAmsHumidityInfo *info = (uiAmsHumidityInfo *) evt.GetClientData();
|
||||
if (info)
|
||||
{
|
||||
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
MachineObject *obj = nullptr;
|
||||
if (dev) {
|
||||
obj = dev->get_selected_machine();
|
||||
}
|
||||
|
||||
if (info->ams_type == AMSModel::GENERIC_AMS)
|
||||
{
|
||||
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
|
||||
@@ -261,9 +268,14 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
||||
int humidity_value = info->humidity_display_idx;
|
||||
if (humidity_value > 0 && humidity_value <= 5) { m_Humidity_tip_popup.set_humidity_level(humidity_value); }
|
||||
m_Humidity_tip_popup.Popup();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (obj && obj->is_support_remote_dry && (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS)){
|
||||
m_ams_dry_ctr_win->set_ams_id(info->ams_id);
|
||||
|
||||
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
|
||||
wxPoint popup_pos(img_pos.x - m_ams_dry_ctr_win->GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80));
|
||||
m_ams_dry_ctr_win->Move(popup_pos);
|
||||
m_ams_dry_ctr_win->ShowModal();
|
||||
} else {
|
||||
m_percent_humidity_dry_popup->Update(info);
|
||||
|
||||
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
|
||||
@@ -283,7 +295,12 @@ void AMSControl::on_retry()
|
||||
post_event(wxCommandEvent(EVT_AMS_RETRY));
|
||||
}
|
||||
|
||||
AMSControl::~AMSControl() {}
|
||||
AMSControl::~AMSControl()
|
||||
{
|
||||
if (m_ams_dry_ctr_win) {
|
||||
delete m_ams_dry_ctr_win;
|
||||
}
|
||||
}
|
||||
|
||||
std::string AMSControl::GetCurentAms() {
|
||||
return m_current_ams;
|
||||
@@ -501,6 +518,10 @@ void AMSControl::msw_rescale()
|
||||
m_percent_humidity_dry_popup->msw_rescale();
|
||||
}
|
||||
|
||||
if (m_ams_dry_ctr_win) {
|
||||
m_ams_dry_ctr_win->msw_rescale();
|
||||
}
|
||||
|
||||
m_Humidity_tip_popup.msw_rescale();
|
||||
|
||||
Layout();
|
||||
@@ -824,6 +845,27 @@ void AMSControl::show_vams_kn_value(bool show)
|
||||
//m_vams_lib->show_kn_value(show);
|
||||
}
|
||||
|
||||
void AMSControl::UpdateAmsDryControl(MachineObject* obj)
|
||||
{
|
||||
if (!m_ams_dry_ctr_win->IsShown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj || !obj->GetFilaSystem()) {
|
||||
m_ams_dry_ctr_win->Close();
|
||||
return;
|
||||
}
|
||||
|
||||
std::weak_ptr<DevFilaSystem> weak_fila_system = obj->GetFilaSystem();
|
||||
|
||||
if (auto locaked_fila_system = weak_fila_system.lock()) {
|
||||
m_ams_dry_ctr_win->update(locaked_fila_system, obj);
|
||||
} else {
|
||||
m_ams_dry_ctr_win->Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AMSinfo> AMSControl::GenerateSimulateData() {
|
||||
auto caninfo0_0 = Caninfo{ "0", (""), *wxRED, AMSCanType::AMS_CAN_TYPE_VIRTUAL };
|
||||
auto caninfo0_1 = Caninfo{ "1", (""), *wxGREEN, AMSCanType::AMS_CAN_TYPE_VIRTUAL };
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <tuple>
|
||||
|
||||
#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h"
|
||||
#include "slic3r/GUI/AMSDryControl.hpp"
|
||||
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
@@ -127,6 +128,7 @@ protected:
|
||||
|
||||
AmsHumidityTipPopup m_Humidity_tip_popup;
|
||||
uiAmsPercentHumidityDryPopup* m_percent_humidity_dry_popup;
|
||||
AMSDryCtrWin* m_ams_dry_ctr_win;
|
||||
|
||||
std::string m_last_ams_id = "";
|
||||
std::string m_last_tray_id = "";
|
||||
@@ -170,6 +172,7 @@ public:
|
||||
void CreateAmsDoubleNozzle(const std::string &series_name, const std::string& printer_type);
|
||||
void CreateAmsSingleNozzle(const std::string &series_name, const std::string &printer_type);
|
||||
void ClearAms();
|
||||
void UpdateAmsDryControl(MachineObject* obj);
|
||||
void UpdateAms(const std::string &series_name,
|
||||
const std::string &printer_type,
|
||||
std::vector<AMSinfo> ams_info,
|
||||
|
||||
@@ -536,7 +536,7 @@ void MoonrakerPrinterAgent::build_ams_payload(int ams_count, int max_lane_index,
|
||||
print_json["ams"] = ams_json;
|
||||
|
||||
// Call the parser to populate DevFilaSystem
|
||||
DevFilaSystemParser::ParseV1_0(print_json, obj, obj->GetFilaSystem(), false);
|
||||
DevFilaSystemParser::ParseV1_0(print_json, obj, obj->GetFilaSystem().get(), false);
|
||||
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::build_ams_payload: Parsed " << trays.size() << " trays";
|
||||
|
||||
// Set printer_type so update_sync_status() can match it against the preset's printer type.
|
||||
|
||||
@@ -210,13 +210,15 @@ inline FullEvalResult full_evaluate_map(const FilamentGroupContext& ctx,
|
||||
return result;
|
||||
}
|
||||
|
||||
inline TestResult run_and_evaluate(const FilamentGroupContext& ctx) {
|
||||
inline TestResult run_and_evaluate(const FilamentGroupContext& ctx,
|
||||
const ClusteringBudget& budget = {}) {
|
||||
TestResult result;
|
||||
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
int algo_cost = 0;
|
||||
|
||||
FilamentGroup fg(ctx);
|
||||
fg.set_clustering_budget(budget);
|
||||
result.filament_map = fg.calc_filament_group(&algo_cost);
|
||||
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -211,19 +211,23 @@ static std::vector<PropertySpec>& get_property_specs() {
|
||||
return specs;
|
||||
}
|
||||
|
||||
// Orca: a small number of config_c "stress" goldens run the nozzle-centric kmedoids clustering path,
|
||||
// which is bounded by a 3000 ms wall-clock budget (FilamentGroup.cpp calc_group_by_kmedoids). On
|
||||
// slower hardware the clustering explores fewer restarts and lands on a deterministically-worse-but-
|
||||
// valid grouping than the stored golden. We regression-lock those against Orca's own deterministic
|
||||
// score (bit-stable across runs on this machine — verified twice) so the gate stays green while the
|
||||
// divergence is documented; every other golden is a true parity gate at 3% tolerance.
|
||||
static std::optional<double> orca_locked_base_score(const std::string& stem) {
|
||||
if (stem == "stress_66") return 125103.0; // config_c 15-filament kmedoids case; golden 117843
|
||||
return std::nullopt;
|
||||
}
|
||||
// Under the default wall clock the result depends on how fast the machine is (see ClusteringBudget),
|
||||
// so the goldens are graded under a fixed budget instead. Two restarts is the fewest that reaches
|
||||
// parity with the reference on every golden, stress_79 being the last to get there. Four leaves
|
||||
// margin, since the search follows a different path on each standard library (see below).
|
||||
static constexpr ClusteringBudget FIXED_SEARCH_BUDGET{
|
||||
/*timeout_ms*/ 0, // no wall clock
|
||||
/*max_restarts*/ 4};
|
||||
|
||||
// ============ Layer 1: Golden Regression (all configs) ============
|
||||
|
||||
// Graded against the BambuStudio golden the harness was ported from, one-directional at 3%.
|
||||
//
|
||||
// The tolerance is a parity allowance, and it also covers a small spread across standard libraries.
|
||||
// The k-medoids search seeds each restart with std::shuffle, whose algorithm the C++ standard leaves
|
||||
// unspecified, so libstdc++, libc++ and the MSVC STL permute the same seed differently, start from
|
||||
// different medoids, and settle on slightly different groupings, about 3e-4 apart on either side of
|
||||
// the reference, and only on the goldens heavy enough to reach the k-medoids search.
|
||||
TEST_CASE("FilamentGroup golden regression", "[filament_group][golden]") {
|
||||
auto files = get_golden_files();
|
||||
if (files.empty()) {
|
||||
@@ -238,29 +242,49 @@ TEST_CASE("FilamentGroup golden regression", "[filament_group][golden]") {
|
||||
auto tc = load_test_case(file_path);
|
||||
REQUIRE(tc.base_result.has_value());
|
||||
|
||||
auto result = run_and_evaluate(tc.context);
|
||||
auto result = run_and_evaluate(tc.context, FIXED_SEARCH_BUDGET);
|
||||
auto eval = full_evaluate_map(tc.context, result.filament_map);
|
||||
|
||||
auto& base = *tc.base_result;
|
||||
|
||||
// Reference score: the stored golden by default; Orca's deterministic score for the
|
||||
// documented heuristic-divergent config_c stress golden (see orca_locked_base_score).
|
||||
std::string stem = fs::path(file_path).stem().string();
|
||||
double base_score = base.full_score;
|
||||
if (auto locked = orca_locked_base_score(stem))
|
||||
base_score = *locked;
|
||||
|
||||
INFO("Case: " << tc.metadata.id);
|
||||
INFO("Reference score: " << base_score << " (BBS golden " << base.full_score << ")");
|
||||
INFO("Golden score: " << base.full_score);
|
||||
INFO("Actual score: " << eval.full_score);
|
||||
INFO("Flush cost: " << eval.flush_cost << " (BBS golden " << base.flush_cost << ")");
|
||||
INFO("Flush cost: " << eval.flush_cost << " (golden " << base.flush_cost << ")");
|
||||
INFO("Elapsed: " << result.elapsed_ms << " ms");
|
||||
|
||||
int tolerance = std::max(50, (int)(base_score * 0.03));
|
||||
int tolerance = std::max(50, (int)(base.full_score * 0.03));
|
||||
|
||||
REQUIRE(result.constraints_ok);
|
||||
REQUIRE(eval.full_score <= base_score + tolerance);
|
||||
// RelWithDebInfo runaway guard; the Release-calibrated 20 s limit is raised for the slower build.
|
||||
REQUIRE(eval.full_score <= base.full_score + tolerance);
|
||||
|
||||
// A slower search still scores the same above, since it searches just as far, but in slicing
|
||||
// it would mean fewer restarts fit in the wall clock and so worse groupings. Loose on
|
||||
// purpose, so it never becomes a proxy for how loaded the runner is.
|
||||
const double throughput_ceiling_ms = 10.0 * ClusteringBudget{}.timeout_ms;
|
||||
REQUIRE(result.elapsed_ms < throughput_ceiling_ms);
|
||||
}
|
||||
}
|
||||
|
||||
// Covers the path real slicing takes, under the default wall clock. The score there depends on the
|
||||
// runner rather than on the code (see FIXED_SEARCH_BUDGET), so the only things worth asserting are
|
||||
// that the grouping comes back valid and that the search terminates.
|
||||
TEST_CASE("FilamentGroup returns a valid grouping under the default budget", "[filament_group][budget]") {
|
||||
auto files = get_golden_files();
|
||||
REQUIRE(!files.empty());
|
||||
|
||||
auto file_path = GENERATE_REF(from_range(files));
|
||||
|
||||
DYNAMIC_SECTION("Golden: " << fs::path(file_path).stem().string()) {
|
||||
auto tc = load_test_case(file_path);
|
||||
|
||||
auto result = run_and_evaluate(tc.context); // the default budget, as real slicing runs it
|
||||
|
||||
INFO("Case: " << tc.metadata.id);
|
||||
INFO("Elapsed: " << result.elapsed_ms << " ms");
|
||||
|
||||
REQUIRE(result.constraints_ok);
|
||||
// A hang guard. The clock is only checked between swaps, so a sweep can overshoot.
|
||||
REQUIRE(result.elapsed_ms < 40000.0);
|
||||
}
|
||||
}
|
||||
|
||||