From 5b64e49c53e3487694028b7de8f8aca5f0a93f30 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 11:12:00 +0800 Subject: [PATCH 001/130] docs: add AMS drying control design spec Port AMS filament drying control feature from BambuStudio. Covers data model changes, commands, UI dialog, and integration plan. --- .../2026-07-07-ams-drying-control-design.md | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-07-ams-drying-control-design.md diff --git a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md new file mode 100644 index 0000000000..940534a501 --- /dev/null +++ b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md @@ -0,0 +1,309 @@ +# AMS Drying Control — Design Spec + +**Date:** 2026-07-07 +**Source:** Port from BambuStudio `AMSDryControl` feature +**Branch:** `dev/ams-heat` + +## Overview + +Port the AMS filament drying control feature from BambuStudio into OrcaSlicer. This allows users to start, monitor, and stop AMS-based filament drying directly from the slicer UI. Currently OrcaSlicer can monitor drying state and stop drying, but cannot initiate it. This feature adds the missing start-drying command, the full drying control dialog, and the drying preset lookup infrastructure. + +**Target AMS models:** N3F (AMS 2 Pro, max 65°C) and N3S (AMS HT, max 85°C) — the only AMS units with heating hardware. + +## Architecture + +The feature spans three layers, matching the existing OrcaSlicer `DeviceCore/` pattern: + +``` +┌─────────────────────────────────────────────────────┐ +│ UI Layer │ +│ AMSDryControl.hpp/.cpp (new dialog) │ +│ AMSControl.cpp (hook: click → dialog) │ +│ DeviceErrorDialog.cpp (stop drying on error) │ +├─────────────────────────────────────────────────────┤ +│ Command/Control Layer │ +│ DevFilaSystemCtrl.cpp (start/stop drying) │ +│ DevUtilBackend.h/.cpp (preset lookup) │ +├─────────────────────────────────────────────────────┤ +│ Data Model Layer │ +│ DevFilaSystem.h/.cpp (enums, structs, parse) │ +│ DevDefs.h (DevAmsType enum) │ +└─────────────────────────────────────────────────────┘ +│ Communication Layer (already exists) │ +│ MachineObject::publish_json() → MQTT → printer │ +└─────────────────────────────────────────────────────┘ +``` + +### New files (4 source + headers) + +| File | Purpose | +|------|---------| +| `src/slic3r/GUI/AMSDryControl.hpp` | AMS drying control dialog class declarations | +| `src/slic3r/GUI/AMSDryControl.cpp` | Dialog implementation (~1800 lines) | +| `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp` | `CtrlAmsStartDryingHour()` and `CtrlAmsStopDrying()` | +| `src/slic3r/GUI/DeviceCore/DevUtilBackend.h` | Static utility class declaring `GetFilamentDryingPreset()` | +| `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp` | Reads filament drying presets from printer config | + +### Modified files + +| File | Changes | +|------|---------| +| `DevFilaSystem.h` | Add drying enums/structs to `DevAms`; add `DevFilamentDryingPreset` struct; add ctrl method declarations to `DevFilaSystem`; add `get_ams_drying_preset()` to `DevAmsTray` | +| `DevFilaSystem.cpp` | Parse dry status fields in `DevFilaSystemParser`; implement `IsSupportRemoteDry()`, `AmsIsDrying()`, `get_ams_drying_preset()` | +| `DevDefs.h` | Add `DevAmsType` as a global enum | +| `AMSControl.cpp` | Wire humidity indicator click to open `AMSDryCtrWin` for N3F/N3S AMS | +| `DeviceErrorDialog.cpp` | Update stop-drying to use `DevFilaSystem::CtrlAmsStopDrying()` | +| `DeviceCore/CMakeLists.txt` | Register new source files | + +### New image assets (~14) + +Humidity level icons (5), drying status per AMS type (8: heating/dehumidifying/error/cooling × N3F/N3S), heating icon, enable/disable indicators, guide image. + +## Data Model + +### `DevDefs.h` — Global `DevAmsType` enum + +Promoted from `DevAms::AmsType` (currently local to the class) to a global enum so `DevFilamentDryingPreset` and `DevUtilBackend` can reference it without depending on `DevAms`: + +```cpp +enum DevAmsType : int { + EXT_SPOOL = 0, + AMS = 1, + AMS_LITE = 2, + N3F = 3, // AMS 2 Pro + N3S = 4, // AMS HT +}; +``` + +### `DevAms` class additions (in `DevFilaSystem.h`) + +**New enums:** + +| Enum | Values | +|------|--------| +| `DryCtrlMode` | `Off=0, OnTime=1, OnHumidity=2` | +| `DryStatus` | `Off=0, Checking=1, Drying=2, Cooling=3, Stopping=4, Error=5, CannotStopHeatOutofControl=6, PrdTesting=7` | +| `DrySubStatus` | `Off=0, Heating=1, Dehumidify=2` | +| `DryFanStatus` | `Off=0, On=1` | +| `CannotDryReason` | `TaskOccupied=0, InsufficientPower=1, AmsBusy=2, ConsumableAtAmsOutlet=3, InitiatingAmsDrying=4, NotSupportedIn2dMode=5, DryingInProgress=6, Upgrading=7, InsufficientPowerNeedPluginPower=8, FilamentAtAmsOutletManualUnload=10` | + +**New struct:** + +```cpp +struct DrySettings { + std::string dry_filament; + int dry_temp = -1; // -1 means invalid + int dry_hour = -1; // hours +}; +``` + +**New getters on `DevAms`:** + +- `std::optional GetDryStatus() const` +- `std::optional GetDrySubStatus() const` +- `std::optional GetFan1Status() const` +- `std::optional GetFan2Status() const` +- `std::optional> GetCannotDryReason() const` +- `std::optional GetDrySettings() const` +- `bool IsSupportRemoteDry(const MachineObject* obj) const` +- `bool AmsIsDrying()` + +**New private members:** `m_dry_status`, `m_dry_sub_status`, `m_dry_fan1_status`, `m_dry_fan2_status`, `m_dry_cannot_reasons`, `m_dry_settings` — all `std::optional<>`. + +### `DevFilamentDryingPreset` struct (namespace scope in `DevFilaSystem.h`) + +```cpp +struct DevFilamentDryingPreset { + std::string filament_id; + std::unordered_set ams_limitations; + std::unordered_map filament_dev_ams_drying_time_on_idle; // hours + std::unordered_map filament_dev_ams_drying_temperature_on_idle; + std::unordered_map filament_dev_ams_drying_time_on_print; // hours + std::unordered_map filament_dev_ams_drying_temperature_on_print; + float filament_dev_drying_cooling_temperature; + float filament_dev_drying_softening_temperature; + float filament_dev_ams_drying_heat_distortion_temperature; +}; +``` + +Populated from filament preset config keys (`filament_dev_ams_drying_temperature`, `filament_dev_ams_drying_time`, `filament_dev_drying_softening_temperature`, etc.). + +### `DevAmsTray` addition + +```cpp +std::optional get_ams_drying_preset() const; +``` + +Delegates to `DevUtilBackend::GetFilamentDryingPreset(setting_id)`. + +### JSON parsing + +`DevFilaSystemParser::ParseV1_0()` extended to parse the following fields from the printer's AMS status JSON: + +| JSON field | DevAms member | +|------------|---------------| +| `dry_status` | `m_dry_status` (`DryStatus` enum) | +| `dry_sub_status` | `m_dry_sub_status` (`DrySubStatus` enum) | +| `dry_fan1_status` | `m_dry_fan1_status` | +| `dry_fan2_status` | `m_dry_fan2_status` | +| `dry_cannot_reasons` | `m_dry_cannot_reasons` (vector of `CannotDryReason`) | +| `dry_settings` | `m_dry_settings` (`DrySettings` struct) | + +## Commands + +### `DevFilaSystem::CtrlAmsStartDryingHour()` + +Publishes JSON command `"ams_filament_drying"` via `MachineObject::publish_json()`: + +```json +{ + "print": { + "command": "ams_filament_drying", + "sequence_id": "", + "ams_id": , + "mode": 1, + "filament": "", + "temp": , + "duration": , + "humidity": 0, + "rotate_tray": , + "cooling_temp": , + "close_power_conflict": false + } +} +``` + +### `DevFilaSystem::CtrlAmsStopDrying()` + +Same command with `mode: 0` (Off). + +### Existing `MachineObject::command_ams_drying_stop()` + +Kept for backward compatibility. The error dialog will be updated to call `CtrlAmsStopDrying()` instead, which is the preferred path. + +## Backend Utility + +### `DevUtilBackend` (new, `DeviceCore/DevUtilBackend.h/.cpp`) + +Static utility class. Only method needed for this feature: + +```cpp +static std::optional GetFilamentDryingPreset(const std::string& fila_id); +``` + +Iterates `wxGetApp().preset_bundle->filaments` to find the matching filament_id, then reads config keys into a `DevFilamentDryingPreset`. Uses a static map `{"0" → N3F, "1" → N3S}` for the `ams_limitations` string-to-enum conversion. + +## UI Dialog + +### `AMSDryCtrWin` (extends `DPIDialog`) + +Three pages in a `wxSimplebook`: + +#### Page 0: Main Page + +Split left/right layout: + +**Left panel — Status display:** +- Large humidity/drying state image: humidity level icon when idle; heating/dehumidifying/error animation when active +- Status label with animated heating icon ("Idle", "Drying-Heating", "Drying-Dehumidifying") +- Three stat labels: Humidity (%), Temperature (°C), Left Time (HH:MM). Left Time hidden when idle. + +**Right panel — Controls.** Three sub-panels shown/hidden based on `DryStatus` and `CannotDryReason`: + +| Sub-panel | When shown | Contents | +|-----------|------------|----------| +| Normal state | `DryStatus` is Off or Cooling | Filament type combobox → Temperature input (numeric, validated to AMS limits) → Time input (hours, 1–24) → Validation warning text → **Start** button | +| Cannot dry | `CannotDryReason` is non-empty (excluding only `DryingInProgress`) | Formatted reason text + **Unload** button (only for `ConsumableAtAmsOutlet` reason) | +| Drying error | `DryStatus` is Error | Error message + **Stop** button | +| Drying active | `DryStatus` is Checking/Drying/Stopping | Read-only temp/time display + **Stop** button | + +**Temperature validation rules:** +- Hardware limits: N3F 45–65°C, N3S 45–85°C +- Heat distortion check: temp must not exceed `filament_dev_ams_drying_heat_distortion_temperature` when filament is present +- Printing mode: temp must not exceed recommended drying temp when this AMS is actively feeding a print +- Time: 1–24 hours + +#### Page 1: Guide Page + +Shown after clicking Start on Page 0, before sending the command: +- Instructional text about removing heat-sensitive filament +- `AMSFilamentPanel` showing each tray's filament type with ✅/⚠ icons based on whether drying temp exceeds that filament's softening point +- "Rotate spool when drying" checkbox +- **Back** and **Start** buttons + +#### Page 2: Progress Page + +Shown while waiting for printer to confirm drying has started: +- Animated progress bar (cycles 0–99% until printer state changes) +- Cycling status messages +- Auto-transitions back to Page 0 when printer reports drying active + +### Helper classes (in `AMSDryControl.hpp`) + +- **`FilamentItemPanel`** — Renders a single filament item with icon and text, with custom rounded-rectangle border painting +- **`AMSFilamentPanel`** — Container for multiple `FilamentItemPanel` instances, labeled with AMS name +- **`DryingPreset` struct, `DryCtrState` enum, `DryCtrDev` enum** — Local types for tracking preset state + +### Dialog lifecycle + +- Created on first click of the AMS humidity indicator +- Updated on each `AMSControl::parse_object()` cycle via `update(fila_system, obj)` +- Auto-closes if: AMS is removed from the system, AMS no longer supports remote drying, or AMS ID becomes invalid +- Closed manually via close button or dialog destruction +- On close: stops progress timer, resets to main page, restores button states + +## Integration + +### Entry point: AMS humidity click → dialog + +In `AMSControl.cpp`, the `EVT_AMS_SHOW_HUMIDITY_TIPS` handler currently shows either `AmsHumidityTipPopup` or `uiAmsPercentHumidityDryPopup`. For N3F and N3S AMS types only, replace this with opening `AMSDryCtrWin`: + +1. Lazily create `AMSDryCtrWin*` member on `AMSControl` (like `m_percent_humidity_dry_popup` today) +2. Call `set_ams_id()` and `update(fila_system, obj)` before showing +3. Show the dialog modally or modelessly + +### Periodic updates + +`AMSControl::parse_object()` updates AMS state on a timer. Extend it to: +1. If `m_dry_ctr_win` is shown, call `update()` to refresh readings +2. Update the dialog's AMS ID if the user switches AMS view + +### Error dialog + +`DeviceErrorDialog.cpp` line 452 calls `m_obj->command_ams_drying_stop()`. Update to use `obj->GetFilaSystem()->CtrlAmsStopDrying(ams_id)` for the correct AMS ID. + +### CMakeLists + +- `src/slic3r/GUI/DeviceCore/CMakeLists.txt`: add `DevFilaSystemCtrl.cpp`, `DevUtilBackend.h`, `DevUtilBackend.cpp` +- GUI sources list: add `AMSDryControl.hpp`, `AMSDryControl.cpp` + +## Testing + +### Manual verification + +1. **Prerequisite:** Connect to a printer with N3F or N3S AMS hardware +2. Click AMS humidity indicator → verify dialog opens with correct humidity/temperature readings +3. Select a filament from the combobox → verify temp/time auto-fill from preset +4. Enter valid temp/time → verify Start button enables +5. Enter invalid temp (e.g., 100°C for N3F) → verify warning appears and button disables +6. Click Start → verify guide page shows filament tray status +7. Click Start on guide page → verify progress page appears, command is sent +8. Verify printer begins drying → dialog shows active drying state with countdown +9. Click Stop → verify drying stops +10. Test "cannot dry" states (e.g., during print, filament at outlet) + +### Code-level checks + +- Verify `CtrlAmsStartDryingHour` publishes correct JSON structure +- Verify `CtrlAmsStopDrying` publishes stop command +- Verify `GetFilamentDryingPreset` returns correct values for known filament IDs +- Verify dark mode rendering of all dialog pages + +## Constraints + +- **N3F/N3S only:** Standard AMS and AMS Lite do not have heating hardware; the dialog is not shown for them +- **Backward compatibility:** Existing `command_ams_drying_stop()` is preserved; new commands are additive +- **Cross-platform:** wxWidgets UI must work on Windows, macOS, Linux +- **Dark mode:** Dialog must support dark mode via `wxGetApp().dark_mode()` and `StateColor::darkModeColorFor()` +- **Profile compatibility:** Existing profiles with `filament_dev_ams_drying_*` keys (Qidi) continue to work; the feature reads the same keys +- **No printer-agent changes needed:** All commands go through existing `publish_json()` → `NetworkAgent` path, which already handles MQTT for connected printers From 885f14ed6533a472e394552d71b34ad55d6233c9 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 11:13:35 +0800 Subject: [PATCH 002/130] docs: fix spec self-review issues Clarify dialog modality, precise image asset list, DevAmsType naming consistency. --- .../2026-07-07-ams-drying-control-design.md | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md index 940534a501..114164a670 100644 --- a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md +++ b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md @@ -55,24 +55,38 @@ The feature spans three layers, matching the existing OrcaSlicer `DeviceCore/` p | `DeviceErrorDialog.cpp` | Update stop-drying to use `DevFilaSystem::CtrlAmsStopDrying()` | | `DeviceCore/CMakeLists.txt` | Register new source files | -### New image assets (~14) +### New image assets (14) -Humidity level icons (5), drying status per AMS type (8: heating/dehumidifying/error/cooling × N3F/N3S), heating icon, enable/disable indicators, guide image. +| Asset | Purpose | +|-------|---------| +| `hum_level1_no_num_light.svg` – `hum_level5_no_num_light.svg` | 5 humidity level icons | +| `dev_ams_dry_ctr_n3f_heating.png`, `_dehumidifying.png`, `_error.png`, `_cooling.png` | 4 N3F drying state images | +| `dev_ams_dry_ctr_n3s_heating.png`, `_dehumidifying.png`, `_error.png`, `_cooling.png` | 4 N3S drying state images | +| `dev_ams_dry_ctr_heating_icon.svg` | Animated heating indicator | +| `dev_ams_dry_ctr_filament_in_chamber.png` | Guide page illustration | +| `dev_ams_dry_ctr_enable.svg`, `dev_ams_dry_ctr_disable.svg` | Filament tray status icons | + +Additionally, OrcaSlicer already has `ams_drying.svg` and `ams_is_drying.svg`. ## Data Model ### `DevDefs.h` — Global `DevAmsType` enum -Promoted from `DevAms::AmsType` (currently local to the class) to a global enum so `DevFilamentDryingPreset` and `DevUtilBackend` can reference it without depending on `DevAms`: +Promoted from `DevAms::AmsType` (currently local to the class) to a global enum in `DevDefs.h` so `DevFilamentDryingPreset` and `DevUtilBackend` can reference it without depending on `DevAms`. `DevAms::AmsType` is updated to be a typedef for `DevAmsType`, and all existing references to `DevAms::AmsType` remain valid (it's the same type): ```cpp +// DevDefs.h — global enum using OrcaSlicer's existing names (same integer values as before) enum DevAmsType : int { - EXT_SPOOL = 0, + DUMMY = 0, AMS = 1, AMS_LITE = 2, N3F = 3, // AMS 2 Pro N3S = 4, // AMS HT }; + +// DevFilaSystem.h — DevAms class updated: +// Replace "enum AmsType { DUMMY=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }" +// with "using AmsType = DevAmsType;" (keeps existing code compiling) ``` ### `DevAms` class additions (in `DevFilaSystem.h`) @@ -260,7 +274,7 @@ In `AMSControl.cpp`, the `EVT_AMS_SHOW_HUMIDITY_TIPS` handler currently shows ei 1. Lazily create `AMSDryCtrWin*` member on `AMSControl` (like `m_percent_humidity_dry_popup` today) 2. Call `set_ams_id()` and `update(fila_system, obj)` before showing -3. Show the dialog modally or modelessly +3. Show the dialog modally via `ShowModal()` (matching BambuStudio behavior) ### Periodic updates From e0d80ee953920eda6f015953a5a43663c196e0c0 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 11:21:00 +0800 Subject: [PATCH 003/130] docs: add BambuStudio reference path to spec --- .../specs/2026-07-07-ams-drying-control-design.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md index 114164a670..cecbf7852f 100644 --- a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md +++ b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md @@ -2,6 +2,7 @@ **Date:** 2026-07-07 **Source:** Port from BambuStudio `AMSDryControl` feature +**Reference:** `D:\projects\BambuStudio` — match its behavior as much as possible; when in doubt, check the BambuStudio source **Branch:** `dev/ams-heat` ## Overview @@ -75,9 +76,9 @@ Additionally, OrcaSlicer already has `ams_drying.svg` and `ams_is_drying.svg`. Promoted from `DevAms::AmsType` (currently local to the class) to a global enum in `DevDefs.h` so `DevFilamentDryingPreset` and `DevUtilBackend` can reference it without depending on `DevAms`. `DevAms::AmsType` is updated to be a typedef for `DevAmsType`, and all existing references to `DevAms::AmsType` remain valid (it's the same type): ```cpp -// DevDefs.h — global enum using OrcaSlicer's existing names (same integer values as before) +// DevDefs.h — global enum matching BambuStudio's DevAmsType naming enum DevAmsType : int { - DUMMY = 0, + EXT_SPOOL = 0, AMS = 1, AMS_LITE = 2, N3F = 3, // AMS 2 Pro @@ -86,7 +87,8 @@ enum DevAmsType : int { // DevFilaSystem.h — DevAms class updated: // Replace "enum AmsType { DUMMY=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }" -// with "using AmsType = DevAmsType;" (keeps existing code compiling) +// with "using AmsType = DevAmsType;" +// Existing references to DevAms::DUMMY become DevAms::EXT_SPOOL (same value, different name). ``` ### `DevAms` class additions (in `DevFilaSystem.h`) From c983f60d00169a43bfb4f15b169b5e011c85ec80 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 11:26:38 +0800 Subject: [PATCH 004/130] docs: add AMS drying control implementation plan 12 tasks covering: data model changes, DevUtilBackend utility, drying commands, JSON parsing, UI dialog port, integration wiring, image assets, and verification. --- .../2026-07-07-ams-drying-control-plan.md | 1046 +++++++++++++++++ 1 file changed, 1046 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md diff --git a/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md b/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md new file mode 100644 index 0000000000..6cd673c5a6 --- /dev/null +++ b/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md @@ -0,0 +1,1046 @@ +# AMS Drying Control — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Port the AMS filament drying control feature from BambuStudio into OrcaSlicer, enabling users to start, monitor, and stop filament drying via the AMS unit from the slicer UI. + +**Architecture:** Add drying status enums/structs to the `DevAms` data model, extend the JSON parser to populate them, add `CtrlAmsStartDryingHour`/`CtrlAmsStopDrying` commands to `DevFilaSystem`, create a `DevUtilBackend` utility for filament drying preset lookup, and build the `AMSDryCtrWin` dialog. Wire the dialog to open when clicking the AMS humidity indicator for N3F/N3S AMS types. + +**Tech Stack:** C++17, wxWidgets, nlohmann/json, Boost + +## Global Constraints + +- **N3F/N3S only:** Standard AMS and AMS Lite do not have heating hardware; the dialog is not shown for them +- **Backward compatibility:** Existing `command_ams_drying_stop()` is preserved; new commands are additive +- **Cross-platform:** wxWidgets UI must work on Windows, macOS, Linux +- **Dark mode:** Dialog must support dark mode via `wxGetApp().dark_mode()` and `StateColor::darkModeColorFor()` +- **Profile compatibility:** Existing profiles with `filament_dev_ams_drying_*` keys (Qidi) continue to work; the feature reads the same keys +- **No printer-agent changes needed:** All commands go through existing `publish_json()` → `NetworkAgent` path +- **Reference:** `D:\projects\BambuStudio` — match its behavior as much as possible; when in doubt, check the BambuStudio source + +--- + +### Task 1: Global `DevAmsType` enum in `DevDefs.h` + +**Files:** +- Modify: `src/slic3r/GUI/DeviceCore/DevDefs.h` +- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` (replace local `AmsType` enum with typedef) +- Modify: `src/slic3r/GUI/DeviceCore/DevMapping.cpp` (rename `DevAms::DUMMY` → `DevAms::EXT_SPOOL`) + +**Interfaces:** +- Produces: Global `enum DevAmsType { EXT_SPOOL=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }` in `DevDefs.h` +- Produces: `using AmsType = DevAmsType;` inside `DevAms` class (replaces old local enum) +- Note: Old `DevAms::DUMMY` becomes `DevAms::EXT_SPOOL`; all existing references update accordingly + +- [ ] **Step 1: Add global `DevAmsType` enum to `DevDefs.h`** + +In `src/slic3r/GUI/DeviceCore/DevDefs.h`, add before the closing `namespace Slic3r` or after existing enums: + +```cpp +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 +}; +``` + +- [ ] **Step 2: Replace `DevAms::AmsType` local enum with typedef** + +In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, find the `DevAms` class and replace the local enum: + +```cpp +// Before (delete this): + enum AmsType : int + { + DUMMY = 0, + AMS = 1, // AMS + AMS_LITE = 2, // AMS-Lite + N3F = 3, // N3F + N3S = 4, // N3S + }; + +// After (replace with): + using AmsType = DevAmsType; +``` + +- [ ] **Step 3: Rename `DevAms::DUMMY` → `DevAms::EXT_SPOOL` in `DevMapping.cpp`** + +In `src/slic3r/GUI/DeviceCore/DevMapping.cpp` line 189: + +```cpp +// Before: +_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::DUMMY, tray, info); +// After: +_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::EXT_SPOOL, tray, info); +``` + +- [ ] **Step 4: Rename `DUMMY` → `EXT_SPOOL` in `DevFilaSystem.cpp`** + +In `src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp` line 114: + +```cpp +// Before: +assert(DUMMY < type && m_ams_type <= N3S); +// After: +assert(EXT_SPOOL < type && m_ams_type <= N3S); +``` + +- [ ] **Step 5: Verify the build compiles** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +Expected: build succeeds, no `DUMMY` or `AmsType` related compile errors. + +- [ ] **Step 6: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevDefs.h src/slic3r/GUI/DeviceCore/DevFilaSystem.h src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp src/slic3r/GUI/DeviceCore/DevMapping.cpp +git commit -m "refactor: promote DevAmsType to global enum, rename DUMMY to EXT_SPOOL + +Matches BambuStudio's DevAmsType naming convention." +``` + +--- + +### Task 2: Drying enums and structs in `DevAms` + +**Files:** +- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` + +**Interfaces:** +- Produces: `DevAms::DryCtrlMode`, `DevAms::DryStatus`, `DevAms::DrySubStatus`, `DevAms::DryFanStatus`, `DevAms::CannotDryReason` enums +- Produces: `DevAms::DrySettings` struct +- Produces: Getters: `GetDryStatus()`, `GetDrySubStatus()`, `GetFan1Status()`, `GetFan2Status()`, `GetCannotDryReason()`, `GetDrySettings()` +- Produces: `IsSupportRemoteDry(const MachineObject*)`, `AmsIsDrying()` +- Produces: `SupportDrying()` — already exists as `m_ams_type > AMS_LITE`; update to check N3F/N3S +- Produces: Members: `m_dry_status`, `m_dry_sub_status`, `m_dry_fan1_status`, `m_dry_fan2_status`, `m_dry_cannot_reasons`, `m_dry_settings` + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.h` lines 119–262 + +- [ ] **Step 1: Add enums inside `DevAms` class** + +In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, inside the `DevAms` class (after the `using AmsType = DevAmsType;` line, before the `public:` constructor section), add: + +```cpp +public: + + enum class DryCtrlMode : int + { + 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 + }; +``` + +- [ ] **Step 2: Add new getters to `DevAms`** + +After the existing `GetLeftDryTime()` getter, add: + +```cpp + // remote drying control + bool IsSupportRemoteDry(const MachineObject* obj) const; + std::optional GetDryStatus() const { return m_dry_status; }; + std::optional GetDrySubStatus() const { return m_dry_sub_status; } + std::optional GetFan1Status() const { return m_dry_fan1_status; } + std::optional GetFan2Status() const { return m_dry_fan2_status; } + std::optional> GetCannotDryReason() const { return m_dry_cannot_reasons; } + std::optional GetDrySettings() const { return m_dry_settings; }; + + bool AmsIsDrying(); +``` + +- [ ] **Step 3: Add new private members to `DevAms`** + +In the private section of `DevAms`, after `m_left_dry_time`, add: + +```cpp + // see is_support_remote_dry + std::optional m_dry_status; + std::optional m_dry_sub_status; + std::optional m_dry_fan1_status; + std::optional m_dry_fan2_status; + std::optional> m_dry_cannot_reasons; + std::optional m_dry_settings; +``` + +Note: In BambuStudio these members are `public:` (prefixed with `public:` before `m_dry_status`). Keep them private and use getters. The friends (`DevFilaSystemParser`) can access them. + +Also remove the duplicate `GetAmsType()` which currently returns `m_ams_type` — since `m_ams_type` is now `DevAmsType`, the getter still works. + +- [ ] **Step 4: Add forward declaration for `DevFilamentDryingPreset`** + +At the top of the file, after the existing forward declarations: + +```cpp +struct DevFilamentDryingPreset; +``` + +- [ ] **Step 5: Verify the header compiles** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +Expected: build succeeds. If there are compilation errors related to `GetAmsType()` return type, check that `AmsType` typedef resolves correctly. + +- [ ] **Step 6: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevFilaSystem.h +git commit -m "feat: add drying enums, structs, getters to DevAms + +Adds DryCtrlMode, DryStatus, DrySubStatus, DryFanStatus, +CannotDryReason enums and DrySettings struct for AMS drying control." +``` + +--- + +### Task 3: `DevFilamentDryingPreset` struct and `DevFilaSystem` ctrl declarations + +**Files:** +- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` + +**Interfaces:** +- Produces: `struct DevFilamentDryingPreset` at namespace scope +- Produces: `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 = false) const` +- Produces: `DevFilaSystem::CtrlAmsStopDrying(int ams_id) const` +- Produces: `DevAmsTray::get_ams_drying_preset()` method + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.h` lines 350–362 + +- [ ] **Step 1: Add `DevFilamentDryingPreset` struct at namespace scope** + +In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, add after the `DevFilaSystemParser` class (at the very end of the file, before `}// namespace Slic3r`): + +```cpp +struct DevFilamentDryingPreset +{ + std::string filament_id; + + std::unordered_set ams_limitations; // only use ams types in the set + std::unordered_map filament_dev_ams_drying_time_on_idle; // hour + std::unordered_map filament_dev_ams_drying_temperature_on_idle; + std::unordered_map filament_dev_ams_drying_time_on_print; // hour + std::unordered_map 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; +}; +``` + +- [ ] **Step 2: Add control method declarations to `DevFilaSystem`** + +In the `DevFilaSystem` class, after the existing `CtrlAmsReset()` declaration: + +```cpp + // 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; +``` + +- [ ] **Step 3: Add `get_ams_drying_preset()` to `DevAmsTray`** + +In the `DevAmsTray` class, add after the `get_filament_type()` method: + +```cpp + std::optional get_ams_drying_preset() const; +``` + +Also add `#include ` and `#include ` to the includes if not already present. +Add `#include ` if not already present. + +- [ ] **Step 4: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 5: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevFilaSystem.h +git commit -m "feat: add DevFilamentDryingPreset, ctrl method declarations, tray preset getter" +``` + +--- + +### Task 4: `DevUtilBackend` utility class + +**Files:** +- Create: `src/slic3r/GUI/DeviceCore/DevUtilBackend.h` +- Create: `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp` +- Modify: `src/slic3r/GUI/DeviceCore/CMakeLists.txt` + +**Interfaces:** +- Produces: `DevUtilBackend::GetFilamentDryingPreset(const std::string& fila_id)` → `std::optional` + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevUtilBackend.h`, `DevUtilBackend.cpp` + +- [ ] **Step 1: Create `DevUtilBackend.h`** + +Create `src/slic3r/GUI/DeviceCore/DevUtilBackend.h`: + +```cpp +/** + * @file DevUtilBackend.h + * @brief Provides common static utility methods for backend (preset/slicing). + */ + +#pragma once +#include "DevDefs.h" +#include "DevFilaSystem.h" + +#include +#include + +namespace Slic3r +{ + +class DevUtilBackend +{ +public: + DevUtilBackend() = delete; + +public: + // for filament preset + static std::optional GetFilamentDryingPreset(const std::string& fila_id); +}; + +}; // namespace Slic3r +``` + +- [ ] **Step 2: Create `DevUtilBackend.cpp`** + +Create `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp`: + +```cpp +#include "DevUtilBackend.h" + +#include "slic3r/GUI/GUI_App.hpp" + +#include "libslic3r/Preset.hpp" + +#include + +namespace Slic3r +{ + +static std::unordered_map s_ams_type_map = { + {"0", DevAmsType::N3F}, + {"1", DevAmsType::N3S}, +}; + +std::optional 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 types = config.option("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("filament_dev_ams_drying_temperature")->get_at(0); + info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_temperature")->get_at(1); + info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_temperature")->get_at(2); + info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3S] = config.option("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("filament_dev_ams_drying_time")->get_at(0); + info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(1); + info.filament_dev_ams_drying_time_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_time")->get_at(2); + info.filament_dev_ams_drying_time_on_print[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(3); + } + + if (config.has("filament_dev_drying_softening_temperature")) { + info.filament_dev_drying_softening_temperature = config.option("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("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("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 +``` + +- [ ] **Step 3: Register new files in CMakeLists.txt** + +In `src/slic3r/GUI/DeviceCore/CMakeLists.txt`, add the new files. After the existing `DevFilaSystemCtrl.cpp` line: + +```cmake + GUI/DeviceCore/DevUtilBackend.h + GUI/DeviceCore/DevUtilBackend.cpp +``` + +- [ ] **Step 4: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +Expected: build succeeds. If `ConfigOptionStrings` or `ConfigOptionFloats` are not found, check the includes — they're in `libslic3r/Preset.hpp` and `libslic3r/PrintConfig.hpp`. + +- [ ] **Step 5: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevUtilBackend.h src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp src/slic3r/GUI/DeviceCore/CMakeLists.txt +git commit -m "feat: add DevUtilBackend with GetFilamentDryingPreset + +Reads filament_dev_ams_drying_* config keys from filament presets +and returns structured DevFilamentDryingPreset data." +``` + +--- + +### Task 5: JSON parsing for drying status fields + +**Files:** +- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp` + +**Interfaces:** +- Consumes: `DevAms::DryStatus`, `DevAms::DrySubStatus`, `DevAms::DryFanStatus`, `DevAms::CannotDryReason`, `DevAms::DrySettings` +- Parses from JSON: `dry_time`, info flag bits (dry_status/fan1/fan2/sub_status), `dry_setting`, `dry_sf_reason` + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.cpp` lines 690–712 + +- [ ] **Step 1: Locate the AMS parsing section in `DevFilaSystemParser::ParseV1_0()`** + +First, read `DevFilaSystem.cpp` to find where `m_left_dry_time` is parsed (look for "dry_time") and where the AMS info section is. The parsing function is `DevFilaSystemParser::ParseV1_0`. + +- [ ] **Step 2: Add drying status field parsing** + +After the existing `m_left_dry_time` parsing line (which parses `"dry_time"` from JSON), add the drying status parsing. The exact location will be in the AMS loop where `curr_ams` is populated. + +After `DevJsonValParser::ParseVal(j_ams, "dry_time", curr_ams->m_left_dry_time);` (or the equivalent line), add: + +```cpp + // Drying status — only parse if printer supports remote drying + if (obj->is_support_remote_dry) { + if (j_ams.contains("info")) { + const std::string& info = j_ams["info"].get(); + 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); + } + + if (j_ams.contains("dry_setting")) { + const auto& j_dry_settings = j_ams["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 (j_ams.contains("dry_sf_reason")) { + curr_ams->m_dry_cannot_reasons = DevJsonValParser::GetVal>(j_ams, "dry_sf_reason"); + } + } +``` + +Note: Check if `DevUtil::get_flag_bits` and `DevJsonValParser` exist in OrcaSlicer. If not, these utilities must be added. Check BambuStudio's `DevUtil.h` for `get_flag_bits` and `DevJsonValParser` for the parsing helper. If these are missing, add minimal versions or inline the parsing. + +Check specifically whether `DevUtil.h` in OrcaSlicer has `get_flag_bits`. The `DevUtil.h` exists in the CMakeLists. Check its contents — it should have a static `get_flag_bits(std::string, int, int)` method. If not present, port it from BambuStudio. + +- [ ] **Step 3: Implement `IsSupportRemoteDry()` and `AmsIsDrying()`** + +In the same file, add the implementations after the existing `DevAms` methods: + +```cpp +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; +} +``` + +- [ ] **Step 4: Implement `DevAmsTray::get_ams_drying_preset()`** + +```cpp +std::optional DevAmsTray::get_ams_drying_preset() const +{ + return DevUtilBackend::GetFilamentDryingPreset(setting_id); +} +``` + +- [ ] **Step 5: Ensure `#include "DevUtilBackend.h"` is present in `DevFilaSystem.cpp`** + +Add at the top if not present. + +- [ ] **Step 6: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 7: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +git commit -m "feat: add drying status JSON parsing and DevAms helper methods + +Parse dry_status, dry_sub_status, dry_fan statuses, +dry_settings, and dry_cannot_reasons from printer JSON. +Implement IsSupportRemoteDry, AmsIsDrying, get_ams_drying_preset." +``` + +--- + +### Task 6: `is_support_remote_dry` flag on `MachineObject` + +**Files:** +- Modify: `src/slic3r/GUI/DeviceManager.hpp` (add field) +- Modify: `src/slic3r/GUI/DeviceManager.cpp` (parse the flag) + +**Interfaces:** +- Produces: `MachineObject::is_support_remote_dry` (bool) + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceManager.hpp` line 566, `DeviceManager.cpp` line 4403 + +- [ ] **Step 1: Add `is_support_remote_dry` field to `MachineObject`** + +In `src/slic3r/GUI/DeviceManager.hpp`, find the section with other `is_support_*` flags (near `is_support_ams_humidity`) and add: + +```cpp + bool is_support_remote_dry = false; +``` + +- [ ] **Step 2: Parse `is_support_remote_dry` from firmware flags** + +In `src/slic3r/GUI/DeviceManager.cpp`, find the `parse_version_func()` or `parse_new_info()` method where other `is_support_*` flags are set. Look for the `is_support_ams_humidity` parsing pattern. + +Add parsing for `is_support_remote_dry` from the `fun2` field. Check the BambuStudio reference: it uses `get_flag_bits_no_border(fun2, 5) == 1` for bit 5. The exact location depends on how OrcaSlicer parses firmware capability bits. + +If a `fun2` parsing block exists, add: +```cpp + is_support_remote_dry = (get_flag_bits_no_border(fun2, 5) == 1); +``` + +If `fun2` parsing or `get_flag_bits_no_border` don't exist yet in OrcaSlicer, check how similar flags like `is_support_ams_humidity` are parsed and follow the same pattern. If the needed helper methods are missing, port them from BambuStudio's `DeviceManager.cpp`. + +- [ ] **Step 3: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 4: Commit** + +```bash +git add src/slic3r/GUI/DeviceManager.hpp src/slic3r/GUI/DeviceManager.cpp +git commit -m "feat: add is_support_remote_dry flag to MachineObject + +Parsed from firmware fun2 bit 5. Controls whether drying +status fields are parsed and drying commands are available." +``` + +--- + +### Task 7: Start/Stop drying commands in `DevFilaSystemCtrl.cpp` + +**Files:** +- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp` + +**Interfaces:** +- Consumes: `MachineObject::m_sequence_id`, `MachineObject::publish_json()` +- Produces: `DevFilaSystem::CtrlAmsStartDryingHour(...)`, `DevFilaSystem::CtrlAmsStopDrying(int)` + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystemCtrl.cpp` + +- [ ] **Step 1: Add `CtrlAmsStartDryingHour` and `CtrlAmsStopDrying`** + +In `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp`, add after the existing `CtrlAmsReset()` method: + +```cpp +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"] = 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"] = 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); +} +``` + +Note: The `DevAms::DryCtrlMode` enum class uses `DevAms::DryCtrlMode::OnTime` in C++. When serialized to JSON (`jj_command["print"]["mode"] = DevAms::DryCtrlMode::OnTime`), nlohmann/json will convert the enum class to its underlying int (1). This matches the BambuStudio behavior. If the implicit conversion doesn't compile, add a `static_cast()` wrapper. + +- [ ] **Step 2: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 3: Commit** + +```bash +git add src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp +git commit -m "feat: add CtrlAmsStartDryingHour and CtrlAmsStopDrying commands + +Publish 'ams_filament_drying' JSON commands via MQTT for +starting and stopping AMS filament drying." +``` + +--- + +### Task 8: Copy image assets from BambuStudio + +**Files:** +- Copy 14 image files from `D:\projects\BambuStudio\resources\images\` to `resources\images\` + +**Assets to copy:** + +```powershell +Copy-Item "D:\projects\BambuStudio\resources\images\hum_level1_no_num_light.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\hum_level2_no_num_light.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\hum_level3_no_num_light.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\hum_level4_no_num_light.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\hum_level5_no_num_light.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_heating.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_dehumidifying.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_error.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_cooling.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_heating.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_dehumidifying.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_error.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_cooling.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_heating_icon.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_filament_in_chamber.png" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_enable.svg" -Destination "resources\images\" +Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_disable.svg" -Destination "resources\images\" +``` + +- [ ] **Step 1: Copy each asset** + +Run each Copy-Item command. If any file is missing from the source, note it — the dialog will degrade gracefully with null bitmaps. + +- [ ] **Step 2: Verify files exist** + +```powershell +Get-ChildItem resources\images\dev_ams_dry_ctr_*, resources\images\hum_level* | Select Name +``` + +Expected: all 17 files listed. + +- [ ] **Step 3: Commit** + +```bash +git add resources/images/dev_ams_dry_ctr_* resources/images/hum_level* +git commit -m "assets: add AMS drying control images from BambuStudio + +14 images: humidity level icons, drying state images per AMS type, +heating icon, guide illustration, tray status icons." +``` + +--- + +### Task 9: `AMSDryControl` UI dialog + +**Files:** +- Create: `src/slic3r/GUI/AMSDryControl.hpp` +- Create: `src/slic3r/GUI/AMSDryControl.cpp` + +**Interfaces:** +- Produces: `AMSDryCtrWin` dialog class extending `DPIDialog` +- Produces: `FilamentItemPanel`, `AMSFilamentPanel` helper widget classes +- Consumes: `DevFilaSystem`, `MachineObject`, `DevAms`, `DevUtilBackend::GetFilamentDryingPreset()` + +**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.hpp` and `AMSDryControl.cpp` + +- [ ] **Step 1: Create `AMSDryControl.hpp`** + +Create `src/slic3r/GUI/AMSDryControl.hpp`. Port the full header from BambuStudio `AMSDryControl.hpp`, adapting includes for OrcaSlicer paths: + +Key adaptations: +- Change `#include "GUI_ObjectLayers.hpp"` to appropriate OrcaSlicer equivalent (check if it exists; if not, it may not be needed or can be replaced with `wx/wx.h`) +- Keep includes for `slic3r/GUI/Widgets/AMSItem.hpp`, `Widgets/Label.hpp`, `Widgets/PopupWindow.hpp`, `wxExtensions.hpp`, `DeviceCore/DevFilaSystem.h` +- Keep the full class declarations for `FilamentItemPanel`, `AMSFilamentPanel`, `AMSDryCtrWin` + +The complete header from `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.hpp` (lines 1–252) should be ported with path adjustments. Due to the file's length (~250 lines), copy the full content from the reference and adapt. + +- [ ] **Step 2: Create `AMSDryControl.cpp`** + +Create `src/slic3r/GUI/AMSDryControl.cpp`. Port from `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.cpp` (lines 1–1860). Key adaptations: + +Replace these BambuStudio includes: +```cpp +#include "AMSDryControl.hpp" +#include "DeviceCore/DevFilaSystem.h" +#include "GUI_App.hpp" +#include "I18N.hpp" +#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h" +#include "slic3r/GUI/DeviceCore/DevUpgrade.h" +#include "slic3r/GUI/DeviceCore/DevManager.h" +#include "slic3r/GUI/MsgDialog.hpp" +#include "slic3r/GUI/Widgets/AnimaController.hpp" +#include "slic3r/GUI/Widgets/Label.hpp" +#include "slic3r/GUI/Widgets/ComboBox.hpp" +#include "slic3r/GUI/Widgets/ProgressBar.hpp" +#include "DeviceCore/DevUtilBackend.h" +``` + +Adapt includes for OrcaSlicer paths. Check which of these already exist: +- `GUI_App.hpp` → existing +- `I18N.hpp` → existing +- `DeviceCore/DevFilaSystem.h` → existing +- `Widgets/Label.hpp`, `Widgets/ComboBox.hpp`, `Widgets/ProgressBar.hpp` → check existence in OrcaSlicer + +Since this file is ~1860 lines, port it in full from the BambuStudio reference, adapting only the include paths and namespace references as needed for OrcaSlicer. The implementation logic should be identical to BambuStudio. + +Key parts to verify during port: +- `AMS_ITEMS_PANEL_SIZE`, `AMS_CONTROL_DEF_BLOCK_BK_COLOUR`, `AMS_CONTROL_BRAND_COLOUR`, `AMS_CONTROL_DISABLE_COLOUR`, `AMS_CONTROL_WHITE_COLOUR` — these constants are defined in `AMSItem.hpp`. Verify they exist in OrcaSlicer's version. +- `_L()` and `_CTX_utf8()` — I18N macros; verify they work the same in OrcaSlicer +- `StateColor` — widget state color class; verify it exists in OrcaSlicer +- `ScalableBitmap` — verify it exists in OrcaSlicer +- `ComboBox` — OrcaSlicer custom combobox; verify path +- `ProgressBar` — OrcaSlicer custom progress bar; verify path +- `FromDIP()` — DPI scaling helper; should exist in OrcaSlicer +- `encode_path()` — path encoding utility; should exist +- `resources_dir()` — resources directory getter; verify it exists +- `bool is_support_user_preset` on `MachineObject` — verify this field exists + +- [ ] **Step 3: Register `AMSDryControl` in CMakeLists** + +In `src/slic3r/CMakeLists.txt`, add after the `AMSSetting` entries (around line 30): + +```cmake + GUI/AMSDryControl.cpp + GUI/AMSDryControl.hpp +``` + +- [ ] **Step 4: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +Fix any compilation errors from missing includes or type mismatches between OrcaSlicer and BambuStudio APIs. + +- [ ] **Step 5: Commit** + +```bash +git add src/slic3r/GUI/AMSDryControl.hpp src/slic3r/GUI/AMSDryControl.cpp +git commit -m "feat: add AMSDryControl dialog for AMS filament drying + +Three-page wizard: main status/control page, guide page with +filament tray status, and progress page. Supports N3F and N3S AMS types." +``` + +--- + +### Task 10: Wire humidity click to open `AMSDryCtrWin` + +**Files:** +- Modify: `src/slic3r/GUI/Widgets/AMSControl.hpp` +- Modify: `src/slic3r/GUI/Widgets/AMSControl.cpp` + +**Interfaces:** +- Consumes: `AMSDryCtrWin` dialog class +- Modifies: `EVT_AMS_SHOW_HUMIDITY_TIPS` handler — for N3F/N3S AMS types, opens `AMSDryCtrWin` instead of the popup + +- [ ] **Step 1: Add member and include to `AMSControl.hpp`** + +In `src/slic3r/GUI/Widgets/AMSControl.hpp`: + +Add forward declaration: +```cpp +class AMSDryCtrWin; +``` + +Add member variable near the existing `m_percent_humidity_dry_popup`: +```cpp + AMSDryCtrWin* m_dry_ctr_win{nullptr}; +``` + +- [ ] **Step 2: Add include to `AMSControl.cpp`** + +```cpp +#include "slic3r/GUI/AMSDryControl.hpp" +``` + +- [ ] **Step 3: Modify the `EVT_AMS_SHOW_HUMIDITY_TIPS` handler** + +In the handler at around line 243, modify the `else` branch (for non-GENERIC_AMS types) to check if the AMS type is N3F/N3S and open the `AMSDryCtrWin` instead of the popup: + +```cpp + Bind(EVT_AMS_SHOW_HUMIDITY_TIPS, [this](wxCommandEvent& evt) { + uiAmsHumidityInfo *info = (uiAmsHumidityInfo *) evt.GetClientData(); + if (info) + { + if (info->ams_type == AMSModel::GENERIC_AMS) + { + wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x - m_Humidity_tip_popup.GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); + m_Humidity_tip_popup.Position(popup_pos, wxSize(0, 0)); + + 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 if (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS) + { + // Open full drying control dialog for N3F/N3S AMS + if (!m_dry_ctr_win) { + m_dry_ctr_win = new AMSDryCtrWin(this); + } + m_dry_ctr_win->set_ams_id(info->ams_id); + // Get fila system and machine object via the parent chain + // The dialog will be updated in parse_object() + m_dry_ctr_win->ShowModal(); + } + else + { + m_percent_humidity_dry_popup->Update(info); + + wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); + wxPoint popup_pos(img_pos.x - m_percent_humidity_dry_popup->GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); + m_percent_humidity_dry_popup->Move(popup_pos); + m_percent_humidity_dry_popup->ShowModal(); + } + } + + delete info; + }); +``` + +Note: The `AMSDryCtrWin` needs `DevFilaSystem` and `MachineObject` references for its `update()` method. The dialog's `update()` should be called before `ShowModal()`. The `MachineObject*` can be obtained from the parent widget chain or stored as a member of `AMSControl`. Check how `AMSControl` currently accesses `MachineObject` (likely through `m_obj` or similar). Pass it to the dialog's `update()` call. + +- [ ] **Step 4: Add periodic update for the dialog in `parse_object()`** + +In the `parse_object()` method (around line 954), find the existing humidity popup update block and extend it to also update the dry control dialog: + +```cpp + /*update AMS dry control dialog*/ + if (m_dry_ctr_win && m_dry_ctr_win->IsShown()) + { + // Get the MachineObject and DevFilaSystem from the current device + // m_dry_ctr_win->update(obj->GetFilaSystem_ptr(), obj); + } +``` + +Note: The exact code depends on how `AMSControl` accesses `MachineObject*`. Check existing patterns — it likely has access through `m_obj` or a similar member. The update will need both the `DevFilaSystem` (as `shared_ptr`) and `MachineObject*`. + +- [ ] **Step 5: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 6: Commit** + +```bash +git add src/slic3r/GUI/Widgets/AMSControl.hpp src/slic3r/GUI/Widgets/AMSControl.cpp +git commit -m "feat: wire AMS humidity click to open AMSDryControl dialog + +For N3F and N3S AMS types, clicking the humidity indicator +now opens the full drying control dialog instead of the popup." +``` + +--- + +### Task 11: Update error dialog stop-drying call + +**Files:** +- Modify: `src/slic3r/GUI/DeviceErrorDialog.cpp` + +**Interfaces:** +- Consumes: `DevFilaSystem::CtrlAmsStopDrying(int)` + +- [ ] **Step 1: Update `STOP_DRYING` case in `DeviceErrorDialog.cpp`** + +In `src/slic3r/GUI/DeviceErrorDialog.cpp` around line 452, update the stop drying action: + +```cpp + case DeviceErrorDialog::STOP_DRYING: { + // Use the canonical CtrlAmsStopDrying path + if (m_obj && m_obj->GetFilaSystem()) { + // Get the AMS ID — check how the dialog knows which AMS is involved + // For now, stop all AMS units or use the first one + m_obj->GetFilaSystem()->CtrlAmsStopDrying(0); + } + // Fallback to the old command for backward compatibility + m_obj->command_ams_drying_stop(); + break; + } +``` + +Note: The exact AMS ID to pass depends on the error context. Check how BambuStudio handles this — it may use a specific AMS ID from the error data, or stop all drying. The fallback to `command_ams_drying_stop()` ensures backward compatibility if `CtrlAmsStopDrying` fails or the fila system isn't available. + +- [ ] **Step 2: Verify build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +- [ ] **Step 3: Commit** + +```bash +git add src/slic3r/GUI/DeviceErrorDialog.cpp +git commit -m "feat: update error dialog stop-drying to use CtrlAmsStopDrying + +Keeps command_ams_drying_stop() fallback for backward compatibility." +``` + +--- + +### Task 12: Build, verify, and final integration test + +**Files:** All modified files + +- [ ] **Step 1: Full clean build** + +```powershell +cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m +``` + +Expected: Zero errors, zero warnings related to the new code. + +- [ ] **Step 2: Verify no regressions in existing AMS features** + +- Confirm the app launches +- Confirm AMS panel renders correctly for printers without N3F/N3S +- Confirm humidity popup still works for standard AMS and AMS Lite +- Confirm existing `command_ams_drying_stop()` still functions + +- [ ] **Step 3: Manual UI smoke test (requires N3F/N3S printer)** + +If a printer with N3F or N3S AMS is available: +1. Connect to the printer +2. Click AMS humidity indicator → verify `AMSDryCtrWin` opens +3. Verify humidity/temperature readings match printer data +4. Verify filament combobox is populated +5. Verify temp/time auto-fill when selecting a filament +6. Verify validation warnings for invalid temperatures +7. Verify the dialog closes cleanly + +- [ ] **Step 4: Commit any final fixes** + +```bash +git add -A +git commit -m "fix: final integration fixes for AMS drying control" +``` From 272e88a3379f3e8f537d34dc1f2a1137cb566b61 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 11:49:55 +0800 Subject: [PATCH 005/130] refactor: promote DevAmsType to global enum, rename DUMMY to EXT_SPOOL Matches BambuStudio's DevAmsType naming convention. --- src/slic3r/GUI/DeviceCore/DevDefs.h | 9 +++++++++ src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp | 2 +- src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 14 ++++++-------- src/slic3r/GUI/DeviceCore/DevMapping.cpp | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevDefs.h b/src/slic3r/GUI/DeviceCore/DevDefs.h index 468ed0184a..7cbf4d26c4 100644 --- a/src/slic3r/GUI/DeviceCore/DevDefs.h +++ b/src/slic3r/GUI/DeviceCore/DevDefs.h @@ -40,6 +40,15 @@ 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 +}; + // Slots and Tray #define VIRTUAL_TRAY_MAIN_ID 255 #define VIRTUAL_TRAY_DEPUTY_ID 254 diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp index 8f35ccf454..100e4c30e9 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp @@ -111,7 +111,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 <= N3S); + assert(EXT_SPOOL < type && m_ams_type <= N3S); } DevAms::~DevAms() diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index 37a93729c8..9d5e2f748c 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -130,14 +130,12 @@ class DevAms { friend class DevFilaSystemParser; public: - enum AmsType : int - { - DUMMY = 0, - AMS = 1, // AMS - AMS_LITE = 2, // AMS-Lite - N3F = 3, // N3F - N3S = 4, // N3S - }; + 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; public: DevAms(const std::string& ams_id, int extruder_id, AmsType type); diff --git a/src/slic3r/GUI/DeviceCore/DevMapping.cpp b/src/slic3r/GUI/DeviceCore/DevMapping.cpp index af3539f372..a98b6402e8 100644 --- a/src/slic3r/GUI/DeviceCore/DevMapping.cpp +++ b/src/slic3r/GUI/DeviceCore/DevMapping.cpp @@ -186,7 +186,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)); } } From c88535ce9eb8388a1ce8b0287f5e6350168089bc Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 12:00:53 +0800 Subject: [PATCH 006/130] feat: add drying enums, structs, getters to DevAms Adds DryCtrlMode, DryStatus, DrySubStatus, DryFanStatus, CannotDryReason enums and DrySettings struct for AMS drying control. --- src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 80 ++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index 9d5e2f748c..c507b61900 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include #include @@ -17,6 +20,7 @@ namespace Slic3r { class MachineObject; +struct DevFilamentDryingPreset; /** * DevAmsTray - Represents a single filament tray/slot in an AMS unit or virtual tray. @@ -137,6 +141,61 @@ public: static constexpr AmsType N3F = DevAmsType::N3F; static constexpr AmsType N3S = DevAmsType::N3S; +public: + + enum class DryCtrlMode : int + { + 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: DevAms(const std::string& ams_id, int extruder_id, AmsType type); DevAms(const std::string& ams_id, int nozzle_id, int type); @@ -168,9 +227,20 @@ public: int GetHumidityLevel() const { return m_humidity_level; } int GetHumidityPercent() const { return m_humidity_percent; } - bool SupportDrying() const { return m_ams_type > AMS_LITE; } + bool SupportDrying() const { return m_ams_type == N3F || m_ams_type == N3S; } int GetLeftDryTime() const { return m_left_dry_time; } + // remote drying control + bool IsSupportRemoteDry(const MachineObject* obj) const; + std::optional GetDryStatus() const { return m_dry_status; }; + std::optional GetDrySubStatus() const { return m_dry_sub_status; } + std::optional GetFan1Status() const { return m_dry_fan1_status; } + std::optional GetFan2Status() const { return m_dry_fan2_status; } + std::optional> GetCannotDryReason() const { return m_dry_cannot_reasons; } + std::optional GetDrySettings() const { return m_dry_settings; }; + + bool AmsIsDrying(); + private: AmsType m_ams_type = AmsType::AMS; std::string m_ams_id; @@ -185,6 +255,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 m_dry_status; + std::optional m_dry_sub_status; + std::optional m_dry_fan1_status; + std::optional m_dry_fan2_status; + std::optional> m_dry_cannot_reasons; + std::optional m_dry_settings; }; /** From 1adfb5f242aaa8cec07ef18b7735b95b48f81dff Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 12:13:26 +0800 Subject: [PATCH 007/130] feat: add DevFilamentDryingPreset, ctrl method declarations, tray preset getter --- src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index c507b61900..283de146db 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -104,6 +104,7 @@ public: std::string get_display_filament_type() const; std::string get_filament_type(); + std::optional get_ams_drying_preset() const; // static static wxColour decode_color(const std::string& color); @@ -332,7 +333,9 @@ public: public: // ctrls int CtrlAmsReset() const; - + 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); @@ -367,4 +370,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 ams_limitations; // only use ams types in the set + std::unordered_map filament_dev_ams_drying_time_on_idle; // hour + std::unordered_map filament_dev_ams_drying_temperature_on_idle; + std::unordered_map filament_dev_ams_drying_time_on_print; // hour + std::unordered_map 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 \ No newline at end of file From 9ee7e9aba40c0f96ff3397b89dcda42578f7c9e6 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 12:51:12 +0800 Subject: [PATCH 008/130] feat: add DevUtilBackend with GetFilamentDryingPreset Reads filament_dev_ams_drying_* config keys from filament presets and returns structured DevFilamentDryingPreset data. --- src/slic3r/GUI/DeviceCore/CMakeLists.txt | 2 + src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp | 76 ++++++++++++++++++++ src/slic3r/GUI/DeviceCore/DevUtilBackend.h | 26 +++++++ 3 files changed, 104 insertions(+) create mode 100644 src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp create mode 100644 src/slic3r/GUI/DeviceCore/DevUtilBackend.h diff --git a/src/slic3r/GUI/DeviceCore/CMakeLists.txt b/src/slic3r/GUI/DeviceCore/CMakeLists.txt index 57fd747228..67e7f1dc8c 100644 --- a/src/slic3r/GUI/DeviceCore/CMakeLists.txt +++ b/src/slic3r/GUI/DeviceCore/CMakeLists.txt @@ -28,6 +28,8 @@ list(APPEND SLIC3R_GUI_SOURCES GUI/DeviceCore/DevFilaSystem.h GUI/DeviceCore/DevFilaSystem.cpp GUI/DeviceCore/DevFilaSystemCtrl.cpp + GUI/DeviceCore/DevUtilBackend.h + GUI/DeviceCore/DevUtilBackend.cpp GUI/DeviceCore/DevFirmware.h GUI/DeviceCore/DevFirmware.cpp GUI/DeviceCore/DevPrintOptions.h diff --git a/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp b/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp new file mode 100644 index 0000000000..c3cd5fd850 --- /dev/null +++ b/src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp @@ -0,0 +1,76 @@ +#include "DevUtilBackend.h" + +#include "slic3r/GUI/GUI_App.hpp" + +#include "libslic3r/Preset.hpp" + +#include + +namespace Slic3r +{ + +static std::unordered_map s_ams_type_map = { + {"0", DevAmsType::N3F}, + {"1", DevAmsType::N3S}, +}; + +std::optional 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 types = config.option("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("filament_dev_ams_drying_temperature")->get_at(0); + info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_temperature")->get_at(1); + info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_temperature")->get_at(2); + info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3S] = config.option("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("filament_dev_ams_drying_time")->get_at(0); + info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(1); + info.filament_dev_ams_drying_time_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_time")->get_at(2); + info.filament_dev_ams_drying_time_on_print[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(3); + } + + if (config.has("filament_dev_drying_softening_temperature")) { + info.filament_dev_drying_softening_temperature = config.option("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("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("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 diff --git a/src/slic3r/GUI/DeviceCore/DevUtilBackend.h b/src/slic3r/GUI/DeviceCore/DevUtilBackend.h new file mode 100644 index 0000000000..ccaa12d056 --- /dev/null +++ b/src/slic3r/GUI/DeviceCore/DevUtilBackend.h @@ -0,0 +1,26 @@ +/** + * @file DevUtilBackend.h + * @brief Provides common static utility methods for backend (preset/slicing). + */ + +#pragma once +#include "DevDefs.h" +#include "DevFilaSystem.h" + +#include +#include + +namespace Slic3r +{ + +class DevUtilBackend +{ +public: + DevUtilBackend() = delete; + +public: + // for filament preset + static std::optional GetFilamentDryingPreset(const std::string& fila_id); +}; + +}; // namespace Slic3r From dd5b755f6023a0130f7971b52453409da8a99f7f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 13:09:32 +0800 Subject: [PATCH 009/130] feat: add drying status JSON parsing and DevAms helper methods Parse dry_status, dry_sub_status, dry_fan statuses, dry_settings, and dry_cannot_reasons from printer JSON. Implement IsSupportRemoteDry, AmsIsDrying, get_ams_drying_preset. Co-Authored-By: Claude --- src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp | 52 +++++++++++++++++++++ src/slic3r/GUI/DeviceManager.hpp | 1 + 2 files changed, 53 insertions(+) diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp index 100e4c30e9..a2787577fd 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/I18N.hpp" #include "DevUtil.h" +#include "DevUtilBackend.h" using namespace nlohmann; @@ -99,6 +100,12 @@ std::string DevAmsTray::get_filament_type() } +std::optional DevAmsTray::get_ams_drying_preset() const +{ + return DevUtilBackend::GetFilamentDryingPreset(setting_id); +} + + DevAms::DevAms(const std::string& ams_id, int extruder_id, AmsType type) { m_ams_id = ams_id; @@ -189,6 +196,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++) @@ -431,6 +459,30 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS curr_ams->m_left_dry_time = (*it)["dry_time"].get(); } + // 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(); + 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); + } + + 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>((*it), "dry_sf_reason"); + } + } + if (it->contains("humidity")) { try diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 0a31c18502..6e4007a62b 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -254,6 +254,7 @@ public: bool is_tunnel_mqtt = false; //AmsTray vt_tray; // virtual tray + bool is_support_remote_dry = false; long ams_exist_bits = 0; long tray_exist_bits = 0; long tray_is_bbl_bits = 0; From 22d9765348ea17e140c40ebeb439f39af9824940 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 13:19:11 +0800 Subject: [PATCH 010/130] feat: add CtrlAmsStartDryingHour and CtrlAmsStopDrying commands Publish 'ams_filament_drying' JSON commands via MQTT for starting and stopping AMS filament drying. Co-Authored-By: Claude --- .../GUI/DeviceCore/DevFilaSystemCtrl.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp index f81d6a2835..acdc81dd8c 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp @@ -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(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(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); +} + } \ No newline at end of file From ec913eaf302d80b4270602de76b6f1a691b1608c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 13:27:39 +0800 Subject: [PATCH 011/130] feat: add is_support_remote_dry flag parsing from firmware Parses fun2 bit 5 from printer firmware to enable remote drying support. --- src/slic3r/GUI/DeviceManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 9d7afd13b9..2562d73b22 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -5031,6 +5031,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); } /*aux*/ From b2298855b02e01c0d9c868990af900e3161fd888 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 13:35:16 +0800 Subject: [PATCH 012/130] assets: add AMS drying control images from BambuStudio 14 images: humidity level icons, drying state images per AMS type, heating icon, guide illustration, tray status icons. --- resources/images/dev_ams_dry_ctr_disable.svg | 5 +++++ resources/images/dev_ams_dry_ctr_enable.svg | 4 ++++ .../dev_ams_dry_ctr_filament_in_chamber.png | Bin 0 -> 105573 bytes .../images/dev_ams_dry_ctr_heating_icon.svg | 3 +++ .../images/dev_ams_dry_ctr_n3f_cooling.png | Bin 0 -> 21003 bytes .../dev_ams_dry_ctr_n3f_dehumidifying.png | Bin 0 -> 22353 bytes resources/images/dev_ams_dry_ctr_n3f_error.png | Bin 0 -> 17987 bytes .../images/dev_ams_dry_ctr_n3f_heating.png | Bin 0 -> 20210 bytes .../images/dev_ams_dry_ctr_n3s_cooling.png | Bin 0 -> 10325 bytes .../dev_ams_dry_ctr_n3s_dehumidifying.png | Bin 0 -> 10546 bytes resources/images/dev_ams_dry_ctr_n3s_error.png | Bin 0 -> 7305 bytes .../images/dev_ams_dry_ctr_n3s_heating.png | Bin 0 -> 10872 bytes 12 files changed, 12 insertions(+) create mode 100644 resources/images/dev_ams_dry_ctr_disable.svg create mode 100644 resources/images/dev_ams_dry_ctr_enable.svg create mode 100644 resources/images/dev_ams_dry_ctr_filament_in_chamber.png create mode 100644 resources/images/dev_ams_dry_ctr_heating_icon.svg create mode 100644 resources/images/dev_ams_dry_ctr_n3f_cooling.png create mode 100644 resources/images/dev_ams_dry_ctr_n3f_dehumidifying.png create mode 100644 resources/images/dev_ams_dry_ctr_n3f_error.png create mode 100644 resources/images/dev_ams_dry_ctr_n3f_heating.png create mode 100644 resources/images/dev_ams_dry_ctr_n3s_cooling.png create mode 100644 resources/images/dev_ams_dry_ctr_n3s_dehumidifying.png create mode 100644 resources/images/dev_ams_dry_ctr_n3s_error.png create mode 100644 resources/images/dev_ams_dry_ctr_n3s_heating.png diff --git a/resources/images/dev_ams_dry_ctr_disable.svg b/resources/images/dev_ams_dry_ctr_disable.svg new file mode 100644 index 0000000000..f2212204e9 --- /dev/null +++ b/resources/images/dev_ams_dry_ctr_disable.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/images/dev_ams_dry_ctr_enable.svg b/resources/images/dev_ams_dry_ctr_enable.svg new file mode 100644 index 0000000000..0c8d4ca146 --- /dev/null +++ b/resources/images/dev_ams_dry_ctr_enable.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resources/images/dev_ams_dry_ctr_filament_in_chamber.png b/resources/images/dev_ams_dry_ctr_filament_in_chamber.png new file mode 100644 index 0000000000000000000000000000000000000000..1b36643c42cd12c4fe71f574df2a490c4229fab2 GIT binary patch literal 105573 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 {gfEi zlBF}tdg)B~G0IX@S5f5jpcFly&ued9M+@VoJ|~7I|LGi37u|8kUa)P3ls@`=}OH7y7GGA zvQ#j|mFtiAc1>iY-1D%mMSDE`W$`1K#Kg00gy4DJifvHe#(EnpO+nlk?0j0qGjAaHGL*&jAP^s!*m4-5L~qWJGKd3Z>eRW@uZt=mjF!1f zh8EQ@;{{H9?0_85L|x@sg|XLpgZf;MNd;Ppf+>Z#RS1&|p#ta|J6!~&)lt*Zpkbi< znh&UDjr(cj0fZ9xd~zxDUo9J7RQHZxW)cu$AAi68yORi6`QCXrX*rk4j>6)bY336^ z1Jh(`PiP)}y=*f5{!et27zgFrODP|bA{f<4o7efXdWh>jGRh8U&c|NOOKA6J){oHg zcZtb@Ewa75ZP8=9w}@1FD0f_IS4)OGyoJ#59?2?4$1jG)08$ei^=FDH4>2k8F;X3U zJj{N){-bF7yAKz^1;9~UUEMZLK8VOb_8{j*t6RnBJ-}r+^A5fQ&*EWK)f71 zz%9ax#{+%67%tAUm#?GO-oqgIe0cipaCbcaez(V3!$7VXDG~Uzj*g!@Emj`m0xc2W zGYPz;p!wDL439A#}HFG1P4)aPYmEt=V`lRuj_bf+h23 zbSU^))WU#4xB(GT>BHJ~o)$J)U>`N2W~D3poIqQjMd)1nme8O;(+Vs_qMfG#cSO=r zQ!*n*I4-#243)V?H7&~c_1=lGmv%k;)tGm6K%1pNQY3%EB1F~F__zfd?N;GFdT`^J z-O9(ad)Ll;WPv&1RgcHM`&dzz^8=W7q$Z;OR`Aw4oC&WVK62>o6;HcD7#?*y145Uu zs4kpdlkCdpA&TqOwX(7FvnL!~R#erg5u|eaJycfcb4QsZ{aWH$o-HCTTHB=_1@Z`a z<7lxIJ~s|eo(oC!PSVl&3z>XLVd2SMSOn1cb4HNM z6b{`uMqf(CrZ24QFQq<0iSY32iqxw&*36RaA-1@_$q^C2N==SP*`(>!!7B8^jU_ zsl;67W)~5ri3Ap_Y%hF(@D})(JFfi6vypf;`Efq@KW6m0`wz4v;DJs!h7GnqvM(mx|G5%TU=n#~} z?zT;vB`zt1u|y-jKwzq!wkhOF&@i6O&ND#>$TLBU%MC3;R1JzSg!h1ou;{?K&NSN$ zYkEDgf4>wo1RQJr`lFA-3SVDb+4;M7u@;V|UcNkwhlf@7d#oV-dx<`6(HB>Sjg1tI zXCN9Z@?c5P8(o4O;MtsM<9D`*4UED8d{ul6y@zmM7LgPZ0v$rO&rK^xrJ%rj@34q{ zgSTC$uLL;>RVidE^amiiGO;%BC0yOuWU#ukDj986DwTw7h0F3pP%`7yx$z?8AW%dc ziV1UVV96o4`ixqo+z8jY#CM_r5lO0()xm8F!TowFXDG%2b-k84{5PgjVwy#_S%A+v@dae&t{lOVatu%m^xIAAa$p$f5M3$P zI2$($k&+p;KZFtA2}w0$2{_LH{n>Wl#?X3(LN83UWVT@gtWD;eu3XIoCMELpx!-Bb zechQDrTuWC%tOAU!QF}S8MBpUSSgsF!Q@WB_}a0#G-BQ>+gMUAeiTI7(V*s zdvUV==fD5cF5Z0;is9<&y}f$%GRQG64~^!EYe7}nZo%|fPPG(2*SQv&q>6srxG(WG zyJVCThoc`8f}xCMI+9yUPC2ZFhc&fQPh2XZOKX^!EQF<*nrD`hC3vkjP2by+v<4ij zWQkJ>H&&L(AZ1$Ys&m4$%ILOeW=dpHzb71;Z9TKB!c<`H6vw|6;kzbF+YyR@rI8Xa zX4QGZMYV~)xb*VD%qE;8|Bwr0gjS|S5HJMf^n?m;N#w#DBUR%WR!ns$Qf25Qc{`Z! z4?cJm@AiZ0O#RA%@s|6bkPk7^V-ND|5N&LG6e*w|RmsNi(JcS|4(vNOYoZFTRX#!g zww_NS1~i|YQbG%38)byD!z51GFfk9Z6+-I*q*!M-P$jRW_e39o3d3^OwAwB(j&6K5 zvWMNg*SHk15TifuF8o|D%D%DtW3=jx;ej`|ac_^05m*~%W3{(my@}8EFy6BKrG5DE z_oGhRKM#!*AMEn#dW0TNGle>0$qk7(;eynKNn1T!mFySCt|nT~jic&32b!nxabp2A zblo*aS4226Qk1Pl=x0-C7wlks=#!v$F{b?)5(3!CL|rU%qp4BjcOh|YbJiNQZ{NVI z=^A9}T%HYSWE~voYTD2)h=l6~ktYq)=abD0HV9#-@VX%A+2y12CAfc^_Y|L1*$jZb z4vNnO>2Y1+BtQ zRLtYrF+_A|jqB4f{nH!sm4~p-4~}kz4;_N&8GAdlzJ2lh#O}U(Yi~zf{)eBu8u#|n z-hFpr7lZTg9_a1#H1^IJZ=;}>vL>pFICL)7Jh#&b@@#MqcPj2~Oe~MMab5W0K81z{ z2{Hm}lXIG=Aw(ARRQhcbtt!bLvqr$w1yP5(NU*rYVQmTqq#Lh+27A!_WfN-lSF9-o z{Jr9}6z0&JrB1S~vkguL{`<80g>88|Ejj(|DxZw^5i_C4w&UP-OSetQ6MD^p7;+Yh zn5BNTR1df|0U-9IYzpiR>mG6c1(wMtEojbF-ikh(THOEUJ+w;C0G_E2*!Dg;r#WJc zYpkpsmzcs4gqjQc67c;bDw;|#sR293XLu8Thq5v9hW@W@^3l_e-K=9g>PqX|+a`g= z;HxVSzFI~{bdWmZRUz;P6j-=Wh44NAS@?92Q0BGd`qqlFOozzP20DffpuLa3ca0%< zkDI+r4T~P&-KH;Z=w0^M@9gaPk-Z&+mcQrZ=-Q5lfJW<}@t&Xkb8c57 z?DT3Nra~VpNW(*CMi^wLZ|Wdqk1-RxMR?A+38B?pFO%k>M?tcS(9v*kRv&t{$ZFw{ z8ZC@b_?}p)6eB1Kv9#UFrZ7VURY`4Rw3yN6$2Oq?9^y%6NxVy1AP61rrcXar`k!YT zG+du?$J(cWLax~ypv?DyKw-#;G7scm({kcvtOVn;Wf*~#HxlHi(o$BCo|EoM;fHsw zXDCQ&$+CffQ4hiR?8~#^Loc@+5sIO8ez>A+@NsI_0qSY2|nj=l59YmU^?ZlZM=su%_-K zx0e2CBf%PB(@I~N2%@pUy@!Pyt~z@j@1>6!XSiaDhCB_TBKK!`)S?sm^ngR8sNrF!|5eBd%d*cg`5|(pW%P*gB|4aEfgi z#8gh(pJ}zyzZHa~Rf~^pT8EB8aawvECS6OAh#9r;ZEU87E`*TQ2;vGp`$l!Tr(5*A-FqpeL#?yxTtEgE_~ zhc$=}p0@!Fug}NlFNJNUsH7SbJ^VN9(JlXWl1N-rt_7^LTe`kkYq~=V(?7Wl|%F(Xd-~Zj;+Asd$U+mkr7xwv=Z|!gX`loh1+?y|c_twsb;5wRmxV*62 z+k4+pWQU0*FW{QiqOK&ybH&(tr+b=QM~{2h>Ci?J{|bvy8B^>BE>n%EB^775qn0j3>=pcURH-UFrS zq>&ok0#Hn1>B&59erVNxFmp}5o}RUoxo3_HaBf?`W$)`9VXnrclEz3tl@NN5GSosJ z9q$7kyYGI8kQn0L4+msmr4OQAD3!Scg5cPI5^Ggbu;jbvbIGkSL+?BnzK-OfH{ZM+ z&%Lvs|NPJG-~Ro-?3cg(?NF#E_WtexG51Hr&SQSw`1ylZXEsODV!UplfGT%j_UfjA zlOXGN=B1)p@q|f=VXhYrhg8~P!DiK>4d^)jNj%Mm#v2goT1aZBA=yyvCV0N|tu`nb z%F0@3YHv8hEwxi11yihd20D~lIR!@L>RA86Ux;`igg zd9_kA4jKX$!bXH*_T+HS-1Rb3Pf0TA{as^GsC1N;s6A+m&${obHm_1fy8(s0aKc;v z#Jr+$U@q_94LEodJ*d4dIT{Yq2iBq1YEHCaRH|E)L*c9wWn|AQ1qFpnQeE)7Hm!4) zqHwe&CAB^xgDMJ3IzpBH`AbbJi6#aEg`6D689Cm80QAT3Hb&9uBnPmU=+DikiPuF* z?_o8yIY!~b?kUeec%{ONM)D4SDQTFb?A4S*XY%&`(f;Y5{{uPJK7GT}F}?cBXOE57 zd85GSvQjMiu3dTKz{5Hfs;-?OPZWqK#Wh_u5^^f^LBx<*TY`$mKA(2ScB*>FCd)}p zyn!3?=?cM9SLPVMS}>8IUrX;BzKKGtuoVwu;ek)4j*_!Qp(#Zs_Ppj|ZjO~n3v~TW z3t=q@ytr%OdLxud!bsntt$?@}OA{dr7 zx`1}vr&0NBa0I|eH~DXol(IXrxx_t{zqklrs$l-*4>!R12x)oqK@SbF@t|iu0c|bx ziP1|t3QM93<}PZN{l1-HHil>#t&=0mMa3<;%Yt^jsK>Xc!t(du-`vGotx2@y25y9! z_B%7HOZp7G4qN%GSH7 z$^b!bSQ2R~_gg!wFs3EM)iUqMJOW_vD@h@tqo$VyW8`)fO_m0G?u>L|DM0hJU} zE+D-mC?*3eH4q!sO)ZnOy_E-2N~4p+LJA^wH;F1iG-D{wi8A7_zVT7!EtG`j;g|bi zGmS{mJzE@h9YP2Z3LrZ7P=Xh*Yw?7Ai}5x0p6h#e6HKocR@`3Q+0E5?luIt|R~~um z*rUkAs%;KnTb7!KxH7jmfD4Q9LrBB7Lv;{HP?Y>BCK`?XykY#~J-db;W;{JuXzyZj zlI?6O+t?OXPa(Oa1blw*@i<3@JY*;Tq?m0Ip2kV0;d=PIK0{r0EdMyar)MX2;Y07r z3~$EkH)l);Og+4EZ%R#pc3th2OF}n^s>~wvhs4G@K zR|!`UCs!{5yLe4!TWqUd$%@I%BC&aD8);X;nM% zWmxt;<+yAVLD@id#j%A7l!Kbqx|6N$8{47PO7&;PE&vcR-e+_)l-i*6Dbqai`cy15 ze~A#daNXuVUC$w_pRl!<7-wB0I3gY(wTSKdyA*`vT-V}ZqV|l#P#L4wI(E|D@a3h! z;z5H9^Y7hX_WI?!+nX4Z)a%NxTN$gwZE`nC;&jG zk`_e zPyfh%`Kw<>%aUkIGT!uP2Od_DQSc3CowA^-;)`Uuc`%{ZcafRYQ)r|_Iya{f#&CJd z%vmll**s7wQnUzMRDaJR0mN6uCJUiiNn!`D3GiAAJ8-fhtk6x6#WVWUHifBYvb%)U zCb{FTg?HSb@`$xIW;@9jEjTJ`ItEgjveXdDc@+q2hVHtOB5+#)9#*V#K*hq^*a$0D zd$xF8>FRx3bw|RcMG6K+({m?o31-kcc1;HU)+p z7BlXZdFip7IyV*fXoUJxQOexl_kJH9-wqbIw{&k5)sZg=1p*;na}c80yYnj`JKvx5 zBhhPYx3s8VxBU?O6$wHppyO#}xGYbeo~8Fl$5bu4zr?$udI5{qXqPgL*TP!GXzH+I zC)RP5oA)itCp(X({N;%FbL~45kc3WSuKHO2{{yE;$yjuCW%&RA002ovPDHLkV1k#> B*+&2X literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_heating_icon.svg b/resources/images/dev_ams_dry_ctr_heating_icon.svg new file mode 100644 index 0000000000..9084670fb7 --- /dev/null +++ b/resources/images/dev_ams_dry_ctr_heating_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/resources/images/dev_ams_dry_ctr_n3f_cooling.png b/resources/images/dev_ams_dry_ctr_n3f_cooling.png new file mode 100644 index 0000000000000000000000000000000000000000..6a43425da5d2c5e828c8a5cc72f851fb4d4bdc9b GIT binary patch literal 21003 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 literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_n3f_dehumidifying.png b/resources/images/dev_ams_dry_ctr_n3f_dehumidifying.png new file mode 100644 index 0000000000000000000000000000000000000000..92064da370318fc95a1f4523f9f5ee046e334a43 GIT binary patch literal 22353 zcma%CRa+cgvz@`67n0zX;KAM92^QR)K?Zkca0{N`t|7R)yF&;t=-}?|9KL^WF81C} z_r>n+>guXmwN^)}D9K==5upJ908BYqN!9oD@qL7%AidAdsXO%V3#y~6jtc;Q{^5TE z2uRN)cs~hrQI!z~R8Eo{ydNM~iYbZ#05x&w&nAcffab28q?o!V@T3E^*+RpOw)3{- z%J0hO#wMGVPCZN(<#*(EbbdZ+u5olK0`78`-E|IBOt)Z_o@NCO&r#`dQ44Ctt2)!7G!B@8Tm#wx#KLc zXnQ*;6^*z0@~g^s=S}4cOFEUP@-`xRa2rp~)SG*YzCTa!;|(Px6sT8pv&Z6f=> zO_D@?ki{J7!TV*}!CkQp?g*Iv`_p+};RVfOFsaIrkee@dw+yIz`4OLk5Ya(|*EwA` z^LkzKkt7~+knCZ$$l0|Nw)lYX1`ihS>34^uVJhO^esKe&#&#(!Z3|x6lz1Co9Jv9ya^un&jF{lwOR>ng(KMkZ$9l6`jh>S%z`xtwj z1IjU$!tz!|{(2sslPhT$PbDfcvNLA%dg+A$^o_F%Z?AmSs9x-E`*Obm=dWucpYXTDF%u-7;GggqwIX=U-i zTae3>Gt!-pw$B?81oMrUrge5b!E7q8H*$n+?r(4Qm2iU1m3ZFtEr~Er2_PIv3n1~c z9e!UAcsf5;R#nB~H%edfyyxJ5m9e1mW$GJlZjR(;>Qyv>YkmjeI!bipEl5p&-1#{i z0Uy~_jJq4778BABi%8nyP`Fi~;n;i71;*k-j=+xP3sbSGGxxw$_%2en(5=4W<$vo^sTfNdeP)yOG~6>%8GXlL z(nB?bzIGGt$Jl_aBHa$^>-l=Dv5zYhx2}L5*nK&PsIs!M{bH?!mj5nC&ckQw%S^!CCu7!WvqOHA?%VC*wnr0 zTPSΠ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 literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_n3s_cooling.png b/resources/images/dev_ams_dry_ctr_n3s_cooling.png new file mode 100644 index 0000000000000000000000000000000000000000..f663c57c5fa01f340eb6fe6191c0e9feb02cec98 GIT binary patch literal 10325 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 IOBx0KAH8yGZvX%Q literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_n3s_dehumidifying.png b/resources/images/dev_ams_dry_ctr_n3s_dehumidifying.png new file mode 100644 index 0000000000000000000000000000000000000000..5926a6cb5421f9600822db6438ee31013c9eac19 GIT binary patch literal 10546 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 B@E8C9 literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_n3s_error.png b/resources/images/dev_ams_dry_ctr_n3s_error.png new file mode 100644 index 0000000000000000000000000000000000000000..0b3df1c3fe1af439195f2fcadf660b3497c0a036 GIT binary patch literal 7305 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 literal 0 HcmV?d00001 diff --git a/resources/images/dev_ams_dry_ctr_n3s_heating.png b/resources/images/dev_ams_dry_ctr_n3s_heating.png new file mode 100644 index 0000000000000000000000000000000000000000..3613a3aefc251adb2b04c3ab40cffbf988f77f80 GIT binary patch literal 10872 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 Date: Tue, 7 Jul 2026 14:16:04 +0800 Subject: [PATCH 013/130] feat: add AMSDryControl dialog for AMS filament drying Three-page wizard: main status/control page, guide page with filament tray status, and progress page. Supports N3F and N3S AMS types. Co-Authored-By: Claude --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/AMSDryControl.cpp | 1864 ++++++++++++++++++++++++++++++ src/slic3r/GUI/AMSDryControl.hpp | 253 ++++ 3 files changed, 2119 insertions(+) create mode 100644 src/slic3r/GUI/AMSDryControl.cpp create mode 100644 src/slic3r/GUI/AMSDryControl.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 969dcb693a..463d98315e 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -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 diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp new file mode 100644 index 0000000000..f88e46f65c --- /dev/null +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -0,0 +1,1864 @@ +#include "AMSDryControl.hpp" +#include "slic3r/GUI/DeviceCore/DevFilaSystem.h" +#include "GUI_App.hpp" +#include "I18N.hpp" + +#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h" + +#include "slic3r/GUI/DeviceCore/DevManager.h" + +#include "slic3r/GUI/MsgDialog.hpp" + +#include "slic3r/GUI/Widgets/AnimaController.hpp" +#include "slic3r/GUI/Widgets/Label.hpp" +#include "slic3r/GUI/Widgets/ComboBox.hpp" +#include "slic3r/GUI/Widgets/ProgressBar.hpp" +#include "slic3r/GUI/DeviceCore/DevUtilBackend.h" + +#include "libslic3r/PresetBundle.hpp" +#include "libslic3r/Preset.hpp" + +#include + +namespace Slic3r { namespace GUI { + +const int AMS_DRY_STATUS_IMAGE_SIZE = 96; + +static std::string get_humidity_level_img_path(int humidity_percent) +{ + const int num_levels = 5; + int hum_level; + + if (humidity_percent <= 100 / num_levels) { + hum_level = 5; + } else if (humidity_percent <= 100 / num_levels * 2) { + hum_level = 4; + } else if (humidity_percent <= 100 / num_levels * 3) { + hum_level = 3; + } else if (humidity_percent <= 100 / num_levels * 4) { + hum_level = 2; + } else { + hum_level = 1; + } + + if (wxGetApp().dark_mode()) { + return "hum_level" + std::to_string(hum_level) + "_no_num_light"; + } else { + return "hum_level" + std::to_string(hum_level) + "_no_num_light"; + } + +} + +static std::string get_dry_status_img_path(DevAmsType type, DevAms::DryStatus status, DevAms::DrySubStatus sub_status) +{ + std::string img_name = "dev_ams_dry_ctr_"; + switch (type) { + case DevAmsType::N3S: + img_name += "n3s"; + break; + case DevAmsType::N3F: + img_name += "n3f"; + break; + default: + return ""; + } + + img_name += "_"; + switch (status) { + case DevAms::DryStatus::Error: + img_name += "error"; + return img_name; + } + + switch (sub_status) { + case DevAms::DrySubStatus::Heating: + img_name += "heating"; + return img_name; + case DevAms::DrySubStatus::Dehumidify: + img_name += "dehumidifying"; + return img_name; + } + + return ""; +} + +FilamentItemPanel::FilamentItemPanel(wxWindow* parent, const wxString& text, const std::string& icon_name, wxWindowID id) + : wxPanel(parent, id) + , m_icon_name(icon_name) +{ + SetBackgroundColour(wxColour("#F7F7F7")); // Light gray background + SetMinSize(wxSize(FromDIP(64), FromDIP(106))); // Width: 64, Height: 106 + SetSize(wxSize(FromDIP(64), FromDIP(106))); // Fixed size + + // Create sizer for vertical layout + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + + // Top section with text - moved to be closer to center + wxBoxSizer* top_sizer = new wxBoxSizer(wxVERTICAL); + top_sizer->AddStretchSpacer(5); + + m_text_label = new Label(this, text); + m_text_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour(*wxBLACK))); + m_text_label->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F7F7F7"))); + m_text_label->SetFont(Label::Body_12); + m_text_label->Wrap(FromDIP(40)); + top_sizer->Add(m_text_label, 0, wxALIGN_CENTER_HORIZONTAL); + + top_sizer->AddStretchSpacer(1); // Increased bottom spacer to push text down + sizer->Add(top_sizer, 1, wxEXPAND); + + // Bottom section with icon - vertically centered in bottom half + wxBoxSizer* bottom_sizer = new wxBoxSizer(wxVERTICAL); + bottom_sizer->AddStretchSpacer(1); + + m_icon_bitmap = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap); + m_icon_bitmap->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F7F7F7"))); + m_icon_bitmap->SetMinSize(wxSize(FromDIP(24), FromDIP(24))); + m_icon_bitmap->SetMaxSize(wxSize(FromDIP(24), FromDIP(24))); + bottom_sizer->Add(m_icon_bitmap, 0, wxALIGN_CENTER_HORIZONTAL); + + bottom_sizer->AddStretchSpacer(1); + sizer->Add(bottom_sizer, 1, wxEXPAND); + + SetSizer(sizer); + + // Bind events + Bind(wxEVT_PAINT, &FilamentItemPanel::OnPaint, this); + Bind(wxEVT_SIZE, &FilamentItemPanel::OnSize, this); + + SetIcon(icon_name); + wxGetApp().UpdateDarkUI(this); +} + +void FilamentItemPanel::SetText(const wxString& text) +{ + m_text_label->SetLabel(text); + Layout(); +} + +void FilamentItemPanel::SetIcon(const std::string& icon_name) +{ + m_icon_name = icon_name; + if (!icon_name.empty()) { + try { + m_icon = ScalableBitmap(this, icon_name, 20); + m_icon.msw_rescale(); + m_icon_bitmap->SetBitmap(m_icon.bmp()); + } catch (Exception&) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": failed to load filament icon"; + m_icon_bitmap->SetBitmap(wxNullBitmap); + } + } else { + m_icon_bitmap->SetBitmap(wxNullBitmap); + } + m_icon_bitmap->Refresh(); +} + +void FilamentItemPanel::msw_rescale() +{ + if (m_icon_bitmap && !m_icon_name.empty()) { + m_icon.msw_rescale(); + m_icon_bitmap->SetBitmap(m_icon.bmp()); + m_icon_bitmap->Refresh(); + } + Layout(); +} + +void FilamentItemPanel::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this); + wxSize size = GetSize(); + + // bool is_dark_mode = wxGetApp().dark_mode(); + wxColour backgroundColor = StateColor::darkModeColorFor(wxColour("#F7F7F7")); + wxColour borderColor = StateColor::darkModeColorFor(wxColour("#DBDBDB")); + + // Draw white background rectangle with rounded corners inside the thick vertical lines + dc.SetBrush(wxBrush(backgroundColor)); + dc.SetPen(wxPen(backgroundColor)); + dc.DrawRectangle(FromDIP(6), FromDIP(12), size.GetWidth() - FromDIP(12), size.GetHeight() - 2 * FromDIP(12)); + + // Draw much thicker vertical rounded rectangles on left and right (3 times thicker) + dc.SetBrush(wxBrush(wxColour(borderColor))); + dc.SetPen(wxPen(wxColour(borderColor))); + dc.DrawRoundedRectangle(FromDIP(0), FromDIP(0), FromDIP(6), size.GetHeight(), FromDIP(6)); // Left rounded rectangle + dc.DrawRoundedRectangle(size.GetWidth() - FromDIP(6), FromDIP(0), FromDIP(6), size.GetHeight(), FromDIP(6)); // Right rounded rectangle + + // Draw thin horizontal rounded rectangles on top and bottom (moved closer to center by half the distance) + dc.SetBrush(wxBrush(wxColour(borderColor))); + dc.SetPen(wxPen(wxColour(borderColor))); + dc.DrawRoundedRectangle(FromDIP(6), FromDIP(12), size.GetWidth() - FromDIP(12), FromDIP(3), FromDIP(1)); // Top rounded rectangle + dc.DrawRoundedRectangle(FromDIP(6), size.GetHeight() - FromDIP(13), size.GetWidth() - FromDIP(12), FromDIP(3), FromDIP(1)); // Bottom rounded rectangle +} + +void FilamentItemPanel::OnSize(wxSizeEvent& event) +{ + Refresh(); + event.Skip(); +} + +// class AMSFilamentPanel + +AMSFilamentPanel::AMSFilamentPanel(wxWindow* parent, const wxString& ams_name, wxWindowID id) + : wxPanel(parent, id) +{ + SetBackgroundColour(wxColour("#DBDBDB")); + + wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); + + // Filament items section + m_filament_container = new wxPanel(this); + m_filament_container->SetBackgroundColour(wxColour("#F7F7F7")); + m_filament_sizer = new wxBoxSizer(wxHORIZONTAL); + m_filament_container->SetSizer(m_filament_sizer); + + // AMS name section + m_ams_name_label = new Label(this, ams_name); + m_ams_name_label->SetForegroundColour(wxColour("#858585")); + m_ams_name_label->SetFont(Label::Body_14); + m_ams_name_label->SetBackgroundColour(wxColour("#DBDBDB")); + + main_sizer->Add(m_filament_container, 1, wxEXPAND | wxALL, 0); + main_sizer->Add(m_ams_name_label, 0, wxALIGN_LEFT | wxALL, FromDIP(5)); + + SetSizer(main_sizer); + wxGetApp().UpdateDarkUI(this); +} + +void AMSFilamentPanel::AddFilamentItem(FilamentItemPanel* panel) +{ + if (panel) { + panel->Reparent(m_filament_container); + m_filament_sizer->Add(panel, 0, wxALL, FromDIP(5)); + m_filament_items.push_back(panel); + Layout(); + } +} + +void AMSFilamentPanel::AddFilamentItem(const wxString& text, const std::string& icon_name) +{ + FilamentItemPanel* item = new FilamentItemPanel(m_filament_container, text, icon_name); + m_filament_items.push_back(item); + m_filament_sizer->Add(item, 0, wxALL, FromDIP(5)); + Layout(); +} + +void AMSFilamentPanel::SetAmsName(const wxString& ams_name) +{ + m_ams_name_label->SetLabel(ams_name); + Layout(); +} + +void AMSFilamentPanel::Clear() +{ + m_filament_sizer->Clear(true); + m_filament_items.clear(); +} + +void AMSFilamentPanel::msw_rescale() +{ + for (auto item : m_filament_items) { + item->msw_rescale(); + } + Layout(); +} + + +AMSDryCtrWin::AMSDryCtrWin(wxWindow *parent) + :DPIDialog(parent, wxID_ANY, _L("AMS Dryness Control"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + create(); +} + +AMSDryCtrWin::~AMSDryCtrWin() +{ + if (m_progress_timer) { + delete m_progress_timer; + } +} + + +wxScrolledWindow* AMSDryCtrWin::create_preview_scrolled_window(wxWindow* parent) +{ + wxScrolledWindow* panel = new wxScrolledWindow(parent, wxID_ANY); + panel->SetScrollRate(10, 0); + panel->SetSize(AMS_ITEMS_PANEL_SIZE); + panel->SetMinSize(AMS_ITEMS_PANEL_SIZE); + panel->SetBackgroundColour(AMS_CONTROL_DEF_BLOCK_BK_COLOUR); + + return panel; +} + +wxBoxSizer* AMSDryCtrWin::create_humidity_status_section(wxPanel* parent) +{ + wxBoxSizer* image_sizer = new wxBoxSizer(wxVERTICAL); + + m_humidity_img = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); + image_sizer->Add(m_humidity_img, 1, wxALIGN_CENTER_HORIZONTAL, 0); + + m_humidity_img->SetBitmap(wxNullBitmap); + + // Create a horizontal sizer for description and icon + wxBoxSizer* desc_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_image_description_icon = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); + m_image_description_icon->SetBackgroundColour(*wxWHITE); + m_image_description_icon->SetMinSize(wxSize(FromDIP(20), FromDIP(20))); + m_image_description_icon->SetMaxSize(wxSize(FromDIP(20), FromDIP(20))); + m_image_description_icon->Show(false); + desc_sizer->Add(m_image_description_icon, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(5)); + + m_image_description = new Label(parent, _L("Idle")); + m_image_description->SetFont(Label::Head_14); + m_image_description->SetForegroundColour(*wxBLACK); + m_image_description->SetBackgroundColour(*wxWHITE); + desc_sizer->Add(m_image_description, 0, wxALIGN_CENTER_VERTICAL); + + image_sizer->Add(desc_sizer, 0, wxALIGN_CENTER | wxALL, FromDIP(5)); + + return image_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_description_item(wxPanel* parent, const wxString& title, Label*& dataLabel) +{ + wxBoxSizer* item_sizer = new wxBoxSizer(wxVERTICAL); + + Label* titleLabel = new Label(parent, title); + titleLabel->SetForegroundColour(*wxBLACK); + titleLabel->SetFont(Label::Body_16); + + dataLabel = new Label(parent, wxT("--")); + dataLabel->SetForegroundColour(*wxBLACK); + dataLabel->SetFont(Label::Body_14); + + item_sizer->AddStretchSpacer(); + item_sizer->Add(titleLabel, 0, wxALIGN_CENTER | wxALL, FromDIP(2)); + item_sizer->Add(dataLabel, 0, wxALIGN_CENTER | wxALL, FromDIP(2)); + item_sizer->AddStretchSpacer(); + + return item_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_status_descriptions_section(wxPanel* parent) +{ + wxBoxSizer* desc_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer* hum_desc_sizer = create_description_item(parent, _L("Humidity"), m_humidity_data_label); + desc_sizer->Add(hum_desc_sizer, 1, wxEXPAND, FromDIP(1)); + + wxStaticLine* vert_separator = new wxStaticLine(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + desc_sizer->Add(vert_separator, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(5)); + + wxBoxSizer* temp_desc_sizer = create_description_item(parent, _L("Temperature"), m_temperature_data_label); + desc_sizer->Add(temp_desc_sizer, 1, wxEXPAND, FromDIP(1)); + + m_time_descrition_container = new wxBoxSizer(wxHORIZONTAL); + wxStaticLine* vert_separator2 = new wxStaticLine(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL); + m_time_descrition_container->Add(vert_separator2, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(5)); + + wxBoxSizer* time_desc_sizer = create_description_item(parent, _L("Left Time"), m_time_data_label); + m_time_descrition_container->Add(time_desc_sizer, 1, wxEXPAND, FromDIP(1)); + + desc_sizer->Add(m_time_descrition_container, 1, wxEXPAND, 0); + // m_time_descrition_container->Show(false); + + return desc_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_left_panel(wxPanel* parent) +{ + wxBoxSizer* left_sizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* image_section = create_humidity_status_section(parent); + left_sizer->Add(image_section, 1, wxEXPAND | wxALL, FromDIP(5)); + + wxBoxSizer* descriptions_section = create_status_descriptions_section(parent); + left_sizer->Add(descriptions_section, 0, wxEXPAND | wxALL, FromDIP(20)); + + return left_sizer; +} + +Button* AMSDryCtrWin::create_button(wxPanel* parent, const wxString& title, + const wxColour& background_color, const wxColour& border_color, const wxColour& text_color) +{ + Button* button = new Button(parent, title); + + // Create state colors for background + StateColor bg_color( + std::pair(AMS_CONTROL_DISABLE_COLOUR, StateColor::Disabled), + std::pair(background_color.ChangeLightness(80), StateColor::Pressed), + std::pair(background_color.ChangeLightness(120), StateColor::Hovered), + std::pair(background_color, StateColor::Normal) + ); + + // Create state colors for border + StateColor bd_color( + std::pair(AMS_CONTROL_WHITE_COLOUR, StateColor::Disabled), + std::pair(border_color, StateColor::Enabled) + ); + + button->SetBackgroundColor(bg_color); + button->SetBorderColor(bd_color); + button->SetTextColor(text_color); + button->SetFont(Label::Body_14); + + // Auto-size button based on text content with padding + wxSize best_size = button->GetBestSize(); + int padding_width = FromDIP(4); + int padding_height = FromDIP(2); + wxSize final_size(best_size.GetWidth() + padding_width, best_size.GetHeight() + padding_height); + button->SetMinSize(final_size); + + return button; +} + +wxBoxSizer* AMSDryCtrWin::create_normal_state_panel(wxPanel* parent) +{ + wxBoxSizer* normal_state_sizer = new wxBoxSizer(wxVERTICAL); + + Label* description_label = new Label(parent, _L("Filament Drying Settings")); + description_label->SetForegroundColour(*wxBLACK); + description_label->SetFont(Label::Head_14); + normal_state_sizer->Add(description_label, 0, wxALL, FromDIP(5)); + + // Part 2: ComboBox for material selection + wxBoxSizer* combo_sizer = new wxBoxSizer(wxHORIZONTAL); + m_trays_combo = new ComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, FromDIP(26)), 0, nullptr, wxCB_READONLY); + m_trays_combo->SetFont(Label::Body_14); + + combo_sizer->Add(m_trays_combo, 1, wxEXPAND); + normal_state_sizer->Add(combo_sizer, 0, wxEXPAND | wxALL, FromDIP(5)); + + m_trays_combo->Bind(wxEVT_COMBOBOX, &AMSDryCtrWin::OnFilamentSelectionChanged, this); + + // part 3 time and temperature + // Temperature part + wxBoxSizer* temp_sizer = new wxBoxSizer(wxHORIZONTAL); + m_temperature_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(80), -1)); + m_temperature_input->SetMaxLength(3); // Limit to 3 digits + + m_temperature_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { + int keycode = event.GetKeyCode(); + if (keycode >= '0' && keycode <= '9') { + event.Skip(); + } else if (keycode == WXK_BACK || keycode == WXK_DELETE || keycode == WXK_LEFT || keycode == WXK_RIGHT) { + event.Skip(); + } + }); + + m_temperature_input->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { + m_next_button->Disable(); + m_start_button->Disable(); + }); + + m_temperature_input->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); + m_temperature_input->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK)); + + Label* temp_unit_label = new Label(parent, wxString::FromUTF8("℃")); + temp_unit_label->SetForegroundColour(*wxBLACK); + temp_sizer->Add(m_temperature_input, 1, wxRIGHT, FromDIP(1)); + temp_sizer->Add(temp_unit_label, 0, wxALIGN_CENTER_VERTICAL); + + // Time part + wxBoxSizer* time_sizer = new wxBoxSizer(wxHORIZONTAL); + m_time_input = new wxTextCtrl(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(100), -1)); + m_time_input->SetMaxLength(3); // Limit to 3 digits + + m_time_input->Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { + int keycode = event.GetKeyCode(); + if (keycode >= '0' && keycode <= '9') { + event.Skip(); + } else if (keycode == WXK_BACK || keycode == WXK_DELETE || keycode == WXK_LEFT || keycode == WXK_RIGHT) { + event.Skip(); + } + }); + + m_time_input->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { + m_next_button->Disable(); + m_start_button->Disable(); + }); + + m_time_input->SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); + m_time_input->SetForegroundColour(StateColor::darkModeColorFor(*wxBLACK)); + + Label* time_unit_label = new Label(parent, "H"); + time_unit_label->SetForegroundColour(*wxBLACK); + time_sizer->Add(m_time_input, 1, wxRIGHT, FromDIP(1)); + time_sizer->Add(time_unit_label, 0, wxALIGN_CENTER_VERTICAL); + + wxBoxSizer* input_sizer = new wxBoxSizer(wxHORIZONTAL); + input_sizer->Add(temp_sizer, 1, wxRIGHT, FromDIP(10)); + input_sizer->Add(time_sizer, 1, 0); + normal_state_sizer->Add(input_sizer, 0, wxEXPAND | wxALL, FromDIP(5)); + + // Part 4: Abnormal description/message area + m_normal_description = new Label(parent, ""); + m_normal_description->SetForegroundColour(wxColour("#F09A17")); + m_normal_description->SetFont(Label::Body_12); + normal_state_sizer->Add(m_normal_description, 0, wxALL, FromDIP(5)); + + // Part 5: Start button + m_next_button = create_button( + parent, + _L("Start"), + AMS_CONTROL_BRAND_COLOUR, // Background color - green + AMS_CONTROL_BRAND_COLOUR, // Border color - green + wxColour("#FFFFFE") // Text color - white + ); + + m_next_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event) { + m_main_simplebook->SetSelection(1); + }); + + normal_state_sizer->Add(m_next_button, 0, wxALL, FromDIP(5)); + m_next_button->Disable(); + + m_stop_button = create_button( + parent, + _L("Stop"), + wxColour(255, 0, 0), // Background color - red + wxColour(255, 0, 0), // Border color - red + wxColour("#FFFFFE") // Text color - white + ); + + m_stop_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event) { + auto fila_system = get_fila_system(); + if (!fila_system) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::start_sending_drying_command: Invalid FilaSystem Pointer"; + return; + } + + fila_system->CtrlAmsStopDrying(std::stoi(m_ams_info.m_ams_id)); + // Temporarily show stopping state, then restore after 2 seconds + if (m_stop_button) { + m_stop_button->SetLabel(_L("Stopping")); + update_button_size(m_stop_button); // Adjust button size for longer text + m_stop_button->Disable(); + m_stop_button->Layout(); + m_stop_button->GetParent()->Layout(); // Relayout parent container + m_stop_button->Refresh(); + + m_stop_button_restore_deadline.reset(); + m_stop_button_restore_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(2); + } + }); + + m_stop_button->Show(false); + normal_state_sizer->Add(m_stop_button, 0, wxALL, FromDIP(5)); + + return normal_state_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_cannot_dry_panel(wxPanel* parent) +{ + wxBoxSizer* abnormal_sizer = new wxBoxSizer(wxVERTICAL); + + Label* description_label = new Label(parent, _L("Unable to dry temporarily due to ...")); + description_label->SetForegroundColour(*wxBLACK); + description_label->SetFont(Label::Head_16); + description_label->Wrap(FromDIP(300)); + abnormal_sizer->Add(description_label, 0, wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + // Add a description label for the abnormal state + m_cannot_dry_description_label = new Label(parent, ("")); + m_cannot_dry_description_label->SetForegroundColour(*wxBLACK); + m_cannot_dry_description_label->SetFont(Label::Body_14); + m_cannot_dry_description_label->Wrap(FromDIP(250)); // Wrap text to fit within panel + + abnormal_sizer->Add(m_cannot_dry_description_label, 0, wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + // Unload button shown only when ConsumableAtAmsOutlet reason is active + m_unload_button = create_button( + parent, + _L("Unload"), + AMS_CONTROL_BRAND_COLOUR, // Background color - light gray + AMS_CONTROL_BRAND_COLOUR, // Border color - gray + *wxWHITE // Text color - white + ); + + m_unload_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event) { + auto fila_system = get_fila_system(); + if (!fila_system) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::unload_button: Invalid FilaSystem Pointer"; + return; + } + + MachineObject* obj = fila_system->GetOwner(); + if (!obj) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::unload_button: Invalid MachineObject Pointer"; + return; + } + + obj->command_ams_change_filament(false, m_ams_info.m_ams_id, "255"); + + m_unload_button->Disable(); + m_unload_button_restore_deadline.reset(); + m_unload_button_restore_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); + }); + + m_unload_button->Show(false); + abnormal_sizer->Add(m_unload_button, 0, wxALL, FromDIP(5)); + + return abnormal_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_drying_error_panel(wxPanel* parent) +{ + wxBoxSizer* err_sizer = new wxBoxSizer(wxVERTICAL); + Label* description_label = new Label(parent, _L("Drying Error")); + description_label->SetForegroundColour(*wxRED); + description_label->SetFont(Label::Body_14); // Wrap text to fit within panel + err_sizer->Add(description_label, 0, wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + Label* additional_description_label = new Label(parent, _L("Please check the Assistant for troubleshooting")); + additional_description_label->SetForegroundColour(*wxBLACK); + additional_description_label->SetFont(Label::Body_14); // Wrap text to fit within panel + err_sizer->Add(additional_description_label, 0, wxALIGN_CENTER_VERTICAL, FromDIP(10)); + + return err_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_right_panel(wxPanel* parent) +{ + wxBoxSizer* right_sizer = new wxBoxSizer(wxHORIZONTAL); + + m_normal_state_sizer = create_normal_state_panel(parent); + m_cannot_dry_sizer = create_cannot_dry_panel(parent); + m_dry_error_sizer = create_drying_error_panel(parent); + + right_sizer->Add(m_normal_state_sizer, 1, wxEXPAND); + right_sizer->Add(m_cannot_dry_sizer, 1, wxEXPAND); + + m_cannot_dry_sizer->Show(false); + m_dry_error_sizer->Show(false); + + return right_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_main_content_section(wxPanel* parent) +{ + wxBoxSizer* content_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer* left_panel = create_left_panel(parent); + content_sizer->Add(left_panel, 2, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + left_panel->SetMinSize(wxSize(FromDIP(250), -1)); + + wxBoxSizer* right_panel = create_right_panel(parent); + content_sizer->Add(right_panel, 1, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(5)); + right_panel->SetMinSize(wxSize(FromDIP(250), -1)); + + return content_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_main_page_sizer(wxPanel* parent) +{ + wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); + + wxBoxSizer* content_section = create_main_content_section(parent); + main_sizer->Add(content_section, 1, wxEXPAND | wxALL, FromDIP(5)); + + return main_sizer; +} + +wxBoxSizer* AMSDryCtrWin::create_guide_info_filament(wxPanel* parent) +{ + wxBoxSizer* filament_section = new wxBoxSizer(wxHORIZONTAL); + + m_ams_filament_panel = new AMSFilamentPanel(parent, ""); + + filament_section->Add(m_ams_filament_panel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_HORIZONTAL, FromDIP(5)); + + return filament_section; +} + +wxBoxSizer* AMSDryCtrWin::create_guide_info_section(wxPanel* parent) +{ + wxBoxSizer* info_section = new wxBoxSizer(wxVERTICAL); + + // Part 1: Title + m_guide_title_label = new Label(parent, _L("Please remove and store the filament (as shown).")); + m_guide_title_label->SetForegroundColour(*wxBLACK); + m_guide_title_label->SetFont(Label::Head_18); + info_section->Add(m_guide_title_label, 0, wxEXPAND | wxALL, FromDIP(5)); + + // Part 2: Description + m_guide_description_label = new Label(parent, _L("The AMS can rotate the filament which is properly stored, providing better drying results.")); + m_guide_description_label->SetForegroundColour(*wxBLACK); + m_guide_description_label->SetFont(Label::Body_14); + m_guide_description_label->Wrap(FromDIP(300)); // Wrap text to fit within panel + info_section->Add(m_guide_description_label, 0, wxEXPAND | wxALL, FromDIP(5)); + + // Part 3: filament panel + wxBoxSizer* fila_section = create_guide_info_filament(parent); + info_section->Add(fila_section, 0, wxEXPAND | wxALL, FromDIP(5)); + + // Part 4: Circular toggle with description + wxBoxSizer* toggle_section = new wxBoxSizer(wxHORIZONTAL); + + m_rotate_spool_toggle = new wxCheckBox(parent, wxID_ANY, ""); + m_rotate_spool_toggle->SetValue(false); + + m_rotate_spool_toggle->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& event) { + bool is_checked = event.IsChecked(); + // Add toggle behavior logic here + }); + + toggle_section->Add(m_rotate_spool_toggle, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(10)); + + // Toggle description + Label* toggle_description = new Label(parent, _L("Rotate spool when drying"), LB_AUTO_WRAP); + toggle_description->SetForegroundColour(*wxBLACK); + toggle_description->SetFont(Label::Body_12); + toggle_section->Add(toggle_description, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND, 0); + + info_section->Add(toggle_section, 0, wxEXPAND | wxALL, FromDIP(5)); + + return info_section; +} + +wxBoxSizer* AMSDryCtrWin::create_guide_right_section(wxPanel* parent) +{ + wxBoxSizer* right_section = new wxBoxSizer(wxVERTICAL); + + // Upper part: Image section + m_image_placeholder = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); + m_guide_image = ScalableBitmap(parent, "dev_ams_dry_ctr_filament_in_chamber", 256); + m_image_placeholder->SetBitmap(m_guide_image.bmp()); + + wxBoxSizer* image_container = new wxBoxSizer(wxHORIZONTAL); + image_container->AddStretchSpacer(1); + image_container->Add(m_image_placeholder, 0, wxALL, FromDIP(5)); + + right_section->Add(image_container, 0, wxEXPAND | wxALL, FromDIP(5)); + + wxBoxSizer* buttons_container = new wxBoxSizer(wxHORIZONTAL); + buttons_container->AddStretchSpacer(1); + + m_back_button = create_button( + parent, + wxString::FromUTF8(_CTX_utf8(L_CONTEXT("Back", "amsdrying"), "amsdrying")), + wxColour("#F8F8F8"), // Background color - light gray + wxColour("#D0D0D0"), // Border color - gray + *wxBLACK // Text color - black + ); + + m_back_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event) { + m_main_simplebook->SetSelection(0); + }); + + buttons_container->Add(m_back_button, 0, wxALL, FromDIP(5)); + + m_start_button = create_button( + parent, + _L("Start"), + AMS_CONTROL_BRAND_COLOUR, // Background color - green + AMS_CONTROL_BRAND_COLOUR, // Border color - green + wxColour("#FFFFFE") // Text color - white + ); + + m_start_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event) { + m_main_simplebook->SetSelection(2); + m_progress_gauge->SetValue(0); + + m_progress_timer->Start(70); + m_progress_value = 0; + start_sending_drying_command(); + }); + + buttons_container->Add(m_start_button, 0, wxALL, FromDIP(5)); + + right_section->Add(buttons_container, 0, wxEXPAND | wxALL, FromDIP(5)); + + return right_section; +} + +wxBoxSizer* AMSDryCtrWin::create_guide_page_sizer(wxPanel* parent) +{ + wxBoxSizer* guide_sizer = new wxBoxSizer(wxHORIZONTAL); + + wxBoxSizer* info_section = create_guide_info_section(parent); + guide_sizer->Add(info_section, 1, wxEXPAND | wxALL, FromDIP(10)); + + wxBoxSizer* right_section = create_guide_right_section(parent); + guide_sizer->Add(right_section, 0, wxEXPAND | wxALL, FromDIP(10)); + + return guide_sizer; +} + +void AMSDryCtrWin::start_sending_drying_command() +{ + auto fila_system = get_fila_system(); + if (!fila_system) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::start_sending_drying_command: Invalid FilaSystem Pointer"; + return; + } + + if (m_temperature_input->GetValue().IsEmpty() || m_time_input->GetValue().IsEmpty()) { + // Show error message to user + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::start_sending_drying_command: Time or temperature is empty"; + return; + } + + long temperature, time; + if (!m_temperature_input->GetValue().ToLong(&temperature) || + !m_time_input->GetValue().ToLong(&time)) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::start_sending_drying_command: Failed to convert temperature or time"; + return; + } + + int tray_index; + tray_index = m_trays_combo->GetSelection(); + if (m_tray_ids.empty() || tray_index < 0 || tray_index >= m_tray_ids.size()) { + BOOST_LOG_TRIVIAL(warning) << "AMSDryCtrWin::start_sending_drying_command: Invalid tray_index " << tray_index + << ", m_tray_ids.size=" << m_tray_ids.size(); + return; + } + + int cooling_temp = 50; + std::optional preset = DevUtilBackend::GetFilamentDryingPreset(m_tray_ids[tray_index].filament_id); + if (preset.has_value()) { + cooling_temp = static_cast(preset.value().filament_dev_drying_softening_temperature); + } + + fila_system->CtrlAmsStartDryingHour(std::stoi(m_ams_info.m_ams_id), m_tray_ids[tray_index].filament_type, + temperature, time, m_rotate_spool_toggle->GetValue(), cooling_temp, false); + + m_dry_setting.m_filament_names[m_ams_info.m_ams_id] = m_tray_ids[tray_index].filament_name; + m_dry_setting.m_filament_type[m_ams_info.m_ams_id] = m_tray_ids[tray_index].filament_type; + m_dry_setting.m_dry_temp[m_ams_info.m_ams_id] = temperature; + m_dry_setting.m_dry_time[m_ams_info.m_ams_id] = time; +} + +void AMSDryCtrWin::OnProgressTimer(wxTimerEvent& event) +{ + m_progress_value += 1; + + if (m_progress_value <= 100) + m_progress_gauge->SetValue(m_progress_value); + + if (m_progress_value == 1) { // First tick, reset message index + m_progress_message_index = 0; + if (!m_progress_text.empty()) { + m_progress_title->SetLabel(m_progress_text[0]); + } + } + else if (m_progress_value % 15 == 0) { // Approximately every second + m_progress_message_index++; + if (m_progress_message_index < m_progress_text.size()) { + m_progress_title->SetLabel(m_progress_text[m_progress_message_index]); + m_progress_title->Refresh(); + } + } + + if (m_progress_value >= 100 && !is_dry_ctr_idle()) { + m_progress_value = 0; + m_progress_timer->Stop(); + m_main_simplebook->SetSelection(0); + } +} + +void AMSDryCtrWin::restore_stop_button_if_deadline_passed() +{ + if (m_stop_button_restore_deadline.has_value()) { + if (std::chrono::steady_clock::now() >= m_stop_button_restore_deadline.value()) { + if (m_stop_button) { + m_stop_button->SetLabel(_L("Stop")); + update_button_size(m_stop_button); // Adjust button size back to original + m_stop_button->Enable(); + m_stop_button->Layout(); + m_stop_button->GetParent()->Layout(); + m_stop_button->Refresh(); + } + m_stop_button_restore_deadline.reset(); + } + } +} + +void AMSDryCtrWin::restore_unload_button_if_deadline_passed() +{ + if (m_unload_button_restore_deadline.has_value()) { + if (std::chrono::steady_clock::now() >= m_unload_button_restore_deadline.value()) { + if (m_unload_button) { + m_unload_button->Enable(); + } + m_unload_button_restore_deadline.reset(); + } + } +} + +void AMSDryCtrWin::update_button_size(Button* button) +{ + if (!button) return; + + // Reset MinSize first to avoid accumulation of size + button->SetMinSize(wxSize(-1, -1)); + + // Recalculate button size based on current text and DPI settings + wxSize best_size = button->GetBestSize(); + int padding_width = FromDIP(4); + int padding_height = FromDIP(2); + wxSize final_size(best_size.GetWidth() + padding_width, best_size.GetHeight() + padding_height); + button->SetMinSize(final_size); +} + +void AMSDryCtrWin::OnShow(wxShowEvent& event) +{ + if (event.IsShown()) { + wxGetApp().UpdateDlgDarkUI(this); + msw_rescale(); + } + event.Skip(); +} + +void AMSDryCtrWin::OnClose(wxCloseEvent& event) +{ + if (m_progress_timer && m_progress_timer->IsRunning()) { + m_progress_timer->Stop(); + } + + if (m_progress_gauge) { + m_progress_gauge->SetValue(0); + } + + m_progress_value = 0; + m_progress_message_index = 0; + + if (m_main_simplebook) { + m_main_simplebook->SetSelection(0); + } + + if (m_progress_title && !m_progress_text.empty()) { + m_progress_title->SetLabel(m_progress_text[0]); + } + + // Clean up and restore stop button state + if (m_stop_button) { + m_stop_button->SetLabel(_L("Stop")); + update_button_size(m_stop_button); // Adjust button size back to original + m_stop_button->Enable(); + m_stop_button->Layout(); + m_stop_button->GetParent()->Layout(); + m_stop_button->Refresh(); + } + m_stop_button_restore_deadline.reset(); + + // Clean up unload button state + if (m_unload_button) { + m_unload_button->Enable(); + } + m_unload_button_restore_deadline.reset(); + + event.Skip(); +} + +wxBoxSizer* AMSDryCtrWin::create_progress_page_sizer(wxPanel* parent) +{ + wxBoxSizer* progress_sizer = new wxBoxSizer(wxVERTICAL); + + m_progress_title = new Label(parent, m_progress_text[0]); + m_progress_title->SetForegroundColour(*wxBLACK); + m_progress_title->SetFont(Label::Body_16); + + progress_sizer->Add(0, 0, 1, wxEXPAND, 0); // Spacer + progress_sizer->Add(m_progress_title, 0, wxALIGN_CENTER | wxALL, FromDIP(30)); + + m_progress_gauge = new ProgressBar(parent, wxID_ANY, 100, wxDefaultPosition, wxSize(FromDIP(300), FromDIP(8))); + m_progress_gauge->SetValue(0); + m_progress_gauge->SetHeight(FromDIP(8)); + + progress_sizer->Add(m_progress_gauge, 0, wxALIGN_CENTER | wxALL, FromDIP(10)); + progress_sizer->Add(0, 0, 1, wxEXPAND, 0); + + return progress_sizer; +} + +void AMSDryCtrWin::create() +{ + // set title icon + SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); + this->SetDoubleBuffered(true); + std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetSize(wxSize(FromDIP(700), FromDIP(500))); + SetMinSize(wxSize(FromDIP(700), FromDIP(500))); + SetMaxSize(wxSize(FromDIP(700), FromDIP(500))); + + m_main_simplebook = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); + + // Create main page + m_original_page = new wxPanel(m_main_simplebook, wxID_ANY); + m_original_page->SetBackgroundColour(*wxWHITE); + wxBoxSizer* main_sizer = create_main_page_sizer(m_original_page); + m_original_page->SetSizer(main_sizer); + + m_main_simplebook->AddPage(m_original_page, "Main Page"); + + m_guide_page = new wxPanel(m_main_simplebook, wxID_ANY); + m_guide_page->SetBackgroundColour(*wxWHITE); + wxBoxSizer* guide_sizer = create_guide_page_sizer(m_guide_page); + m_guide_page->SetSizer(guide_sizer); + m_main_simplebook->AddPage(m_guide_page, "Guide Page"); + + // Create progress page + m_progress_page = new wxPanel(m_main_simplebook, wxID_ANY); + m_progress_page->SetBackgroundColour(*wxWHITE); + wxBoxSizer* progress_sizer = create_progress_page_sizer(m_progress_page); + m_progress_page->SetSizer(progress_sizer); + m_main_simplebook->AddPage(m_progress_page, "Progress Page"); + + m_progress_timer = new wxTimer(this, wxID_ANY); + Bind(wxEVT_TIMER, &AMSDryCtrWin::OnProgressTimer, this, m_progress_timer->GetId()); + + Bind(wxEVT_CLOSE_WINDOW, &AMSDryCtrWin::OnClose, this); + + wxBoxSizer* top_level_sizer = new wxBoxSizer(wxVERTICAL); + top_level_sizer->Add(m_main_simplebook, 1, wxEXPAND | wxALL, FromDIP(10)); + + Bind(wxEVT_SHOW, &AMSDryCtrWin::OnShow, this); + + SetSizer(top_level_sizer); + Layout(); + Refresh(); + wxGetApp().UpdateDlgDarkUI(this); +} + +void AMSDryCtrWin::on_dpi_changed(const wxRect &suggested_rect) +{ + msw_rescale(); +} + +void AMSDryCtrWin::msw_rescale() +{ + if (!IsShown()) { + return; + } + + if (m_ams_filament_panel) {m_ams_filament_panel->msw_rescale();} + if (m_trays_combo) {m_trays_combo->Rescale(); m_trays_combo->Layout(); m_trays_combo->SetFont(Label::Body_14), m_trays_combo->Refresh();} + if (m_humidity_img && m_humidity_image.bmp().IsOk()) {m_humidity_image.msw_rescale(); m_humidity_img->SetBitmap(m_humidity_image.bmp());} + if (m_image_placeholder && m_guide_image.bmp().IsOk()) {m_guide_image.msw_rescale();m_image_placeholder->SetBitmap(m_guide_image.bmp());} + if (m_image_description_icon && m_description_icon_bitmap.bmp().IsOk()) {m_description_icon_bitmap.msw_rescale(); m_image_description_icon->SetBitmap(m_description_icon_bitmap.bmp());} + + // Rescale and update button sizes based on text content + if (m_next_button) { + m_next_button->Rescale(); + update_button_size(m_next_button); + m_next_button->Layout(); + m_next_button->Refresh(); + } + if (m_stop_button) { + m_stop_button->Rescale(); + update_button_size(m_stop_button); + m_stop_button->Layout(); + m_stop_button->Refresh(); + } + if (m_start_button) { + m_start_button->Rescale(); + update_button_size(m_start_button); + m_start_button->Layout(); + m_start_button->Refresh(); + } + if (m_back_button) { + m_back_button->Rescale(); + update_button_size(m_back_button); + m_back_button->Layout(); + m_back_button->Refresh(); + } + if (m_unload_button) { + m_unload_button->Rescale(); + update_button_size(m_unload_button); + m_unload_button->Layout(); + m_unload_button->Refresh(); + } + + if (m_guide_page) {m_guide_page->Layout();} + if (m_original_page) {m_original_page->Layout();} + + Fit(); + Layout(); + Refresh(); +} + +void AMSDryCtrWin::set_ams_id(const std::string& ams_id) +{ + m_ams_info.m_ams_id = ams_id; + m_is_ams_changed = true; +} + +void AMSDryCtrWin::update_img_description(DevAms::DryStatus status, DevAms::DrySubStatus sub_status) +{ + if (status == DevAms::DryStatus::Off || status == DevAms::DryStatus::Cooling) { + m_image_description->SetLabel(_L("Idle")); + m_image_description_icon->Show(false); + return; + } + + // Determine label text for non-idle states + wxString label_text; + if (status == DevAms::DryStatus::Error) { + label_text = _L("Drying"); + } else if (sub_status == DevAms::DrySubStatus::Heating) { + label_text = _L("Drying-Heating"); + } else if (sub_status == DevAms::DrySubStatus::Dehumidify) { + label_text = _L("Drying-Dehumidifying"); + } else { + m_image_description_icon->Show(false); + return; + } + + m_image_description->SetLabel(label_text); + + try { + m_description_icon_bitmap = ScalableBitmap(this, "dev_ams_dry_ctr_heating_icon", 20); + m_description_icon_bitmap.msw_rescale(); + m_image_description_icon->SetBitmap(m_description_icon_bitmap.bmp()); + m_image_description_icon->Show(true); + } catch (Exception&) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Error loading drying icon"; + m_image_description_icon->Show(false); + } +} + +int AMSDryCtrWin::update_image(DevAmsType model, DevAms::DryStatus status, DevAms::DrySubStatus sub_status, int humidity_percent) +{ + if (model == m_ams_info.m_model && status == m_ams_info.m_dry_status + && sub_status == m_ams_info.m_dry_sub_status && humidity_percent == m_ams_info.m_humidity_percent) { + return 0; + } + + std::string img_path; + + if (status == DevAms::DryStatus::Off && sub_status == DevAms::DrySubStatus::Off) { + img_path = get_humidity_level_img_path(humidity_percent); + } else { + img_path = get_dry_status_img_path(model, status, sub_status); + } + + if (img_path.empty()) { + return 0; + } + + m_humidity_image = ScalableBitmap(this, img_path, AMS_DRY_STATUS_IMAGE_SIZE); + m_humidity_img->SetBitmap(m_humidity_image.bmp()); + + update_img_description(status, sub_status); + + return 1; +} + +bool AMSDryCtrWin::check_values_changed(DevAms* dev_ams) +{ + bool changed = false; + + if (m_ams_info.m_model != dev_ams->GetAmsType()) { + m_ams_info.m_model = dev_ams->GetAmsType(); + changed = true; + } + + if (dev_ams->GetDryStatus().has_value() && m_ams_info.m_dry_status != dev_ams->GetDryStatus()) { + m_ams_info.m_dry_status = dev_ams->GetDryStatus().value(); + changed = true; + } + + if (dev_ams->GetDrySubStatus().has_value() && m_ams_info.m_dry_sub_status != dev_ams->GetDrySubStatus()) { + m_ams_info.m_dry_sub_status = dev_ams->GetDrySubStatus().value(); + changed = true; + } + + if (m_ams_info.m_humidity_percent != dev_ams->GetHumidityPercent()) { + m_ams_info.m_humidity_percent = dev_ams->GetHumidityPercent(); + changed = true; + } + + return changed; +} + +void AMSDryCtrWin::update_normal_description(DevAms* dev_ams) +{ + if (m_tray_ids.empty() || m_trays_combo->GetSelection() >= m_tray_ids.size()) { return; } + + FilamentBaseInfo info = m_tray_ids[m_trays_combo->GetSelection()]; + wxString warning_text; + bool can_enable_button = true; + long temp_val = 0, time_val = 0; + m_temperature_input->GetValue().ToLong(&temp_val); + m_time_input->GetValue().ToLong(&time_val); + std::optional preset = DevUtilBackend::GetFilamentDryingPreset(info.filament_id); + auto total_dry = preset.has_value() ? preset.value().ams_limitations : std::unordered_set(); + + struct AmsTempLimit { DevAmsType type; int min_temp; int max_temp; const char* name; }; + static const AmsTempLimit ams_limits[] = { + { DevAmsType::N3F, 45, 65, "AMS2" }, + { DevAmsType::N3S, 45, 85, "AMS-S" } + }; + + for (const auto& lim : ams_limits) { + if (dev_ams->GetAmsType() == lim.type) { + if (temp_val > lim.max_temp) { + wxString msg = wxString(lim.name) + _L(" maximum drying temperature is ") + wxString::Format(wxT("%d"), lim.max_temp) + wxString::FromUTF8("°C."); + warning_text += msg + "\n"; + can_enable_button = false; + } else if (temp_val < lim.min_temp) { + wxString msg = wxString(lim.name) + _L(" minimum drying temperature is ") + wxString::Format(wxT("%d"), lim.min_temp) + wxString::FromUTF8("°C."); + warning_text += msg + "\n"; + can_enable_button = false; + } + if (total_dry.find(lim.type) == total_dry.end()) { + warning_text += _L("This filament may not be completely dried.") + "\n\n"; + } + break; + } + } + + if (m_printer_status.m_is_printing && temp_val > m_ams_info.m_recommand_dry_temp) { + warning_text += _L("This AMS is currently printing. To ensure print quality, the drying temperature cannot exceed the recommended drying temperature.") + "\n"; + can_enable_button = false; + } else if (preset.has_value()) { + // Only check heat distortion temperature when AMS has filament inserted; + // empty AMS only needs to respect the device hardware temperature limit. + bool has_filament_inserted = false; + for (const auto& tray_pair : dev_ams->GetTrays()) { + if (tray_pair.second && tray_pair.second->is_exists) { + has_filament_inserted = true; + break; + } + } + if (has_filament_inserted) { + auto limit_temperature = preset.value().filament_dev_ams_drying_heat_distortion_temperature; + if (temp_val > limit_temperature) { + warning_text += _L("The temperature shall not exceed the filament's heat distortion temperature") + "(" + + wxString::Format(wxT("%d"), static_cast(limit_temperature)) + wxString::FromUTF8("°C)\n"); + can_enable_button = false; + } + } + } + + if (time_val < 1) { + warning_text += _L("Minimum time value cannot be less than 1.") + "\n"; + can_enable_button = false; + } else if (time_val > 24) { + warning_text += _L("Maximum time value cannot be greater than 24.") + "\n"; + can_enable_button = false; + } + + m_next_button->Enable(can_enable_button); + m_normal_description->SetLabel(warning_text); + m_normal_description->Wrap(FromDIP(250)); + m_normal_description->GetParent()->Layout(); +} + +void AMSDryCtrWin::update_normal_state(DevAms* dev_ams) +{ + if (is_dry_ctr_idle(dev_ams)) { + m_next_button->Show(true); + m_normal_description->Show(true); + m_trays_combo->Enable(); + m_temperature_input->SetEditable(true); + m_time_input->SetEditable(true); + + m_stop_button->Hide(); + m_dry_error_sizer->Show(false); + } else if (is_dry_ctr_err(dev_ams)) { + m_dry_error_sizer->Show(true); + m_next_button->Hide(); + m_normal_description->Hide(); + + m_trays_combo->Hide(); + m_temperature_input->Hide(); + m_time_input->Hide(); + m_stop_button->Show(true); + } else { + m_next_button->Hide(); + m_normal_description->Hide(); + + m_trays_combo->Disable(); + m_temperature_input->SetEditable(false); + m_time_input->SetEditable(false); + m_stop_button->Show(true); + m_dry_error_sizer->Show(false); + } + + if (m_temperature_input->GetValue().IsEmpty() || m_time_input->GetValue().IsEmpty()) { + m_next_button->Disable(); + m_start_button->Disable(); + } else { + m_next_button->Enable(); + } + + update_normal_description(dev_ams); +} + +void AMSDryCtrWin::OnFilamentSelectionChanged(wxCommandEvent& event) +{ + int selectionIndex = event.GetSelection(); + wxString selectedFilament = event.GetString(); + + auto fila_system = get_fila_system(); + if (!fila_system) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::OnFilamentSelectionChanged: Invalid FilaSystem Pointer"; + return; + } + + DevAms* dev_ams = fila_system->GetAmsById(m_ams_info.m_ams_id); + if (!dev_ams) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::OnFilamentSelectionChanged: Invalid AMS id"; + return; + } + + std::optional preset = DevUtilBackend::GetFilamentDryingPreset(m_tray_ids[selectionIndex].filament_id); + if (preset.has_value()) { + DevFilamentDryingPreset info = preset.value(); + if (m_printer_status.m_is_printing) { + m_temperature_input->SetValue(std::to_string(static_cast(info.filament_dev_ams_drying_temperature_on_print[dev_ams->GetAmsType()]))); + m_time_input->SetValue(std::to_string(static_cast(info.filament_dev_ams_drying_time_on_print[dev_ams->GetAmsType()]))); + } else { + m_temperature_input->SetValue(std::to_string(static_cast(info.filament_dev_ams_drying_temperature_on_idle[dev_ams->GetAmsType()]))); + m_time_input->SetValue(std::to_string(static_cast(info.filament_dev_ams_drying_time_on_idle[dev_ams->GetAmsType()]))); + } + } + + update_filament_guide_info(dev_ams); +} + +wxString get_cannot_reason_text(DevAms::CannotDryReason reason) +{ + wxString cannot_reason_text; + switch (reason) + { + case DevAms::CannotDryReason::InsufficientPower: + cannot_reason_text = "*" + _L("Insufficient power") + "\n"; + cannot_reason_text += _L(" Too many AMS drying simultaneously. Please plug in the power or stop other drying processes before starting.") + "\n"; + break; + case DevAms::CannotDryReason::AmsBusy: + cannot_reason_text = "*" + _L("AMS is busy") + "\n"; + cannot_reason_text += _L(" AMS is calibrating | reading RFID | loading/unloading material, please wait.") + "\n"; + break; + case DevAms::CannotDryReason::ConsumableAtAmsOutlet: + cannot_reason_text = "*" + _L("Filament in AMS outlet") + "\n"; + cannot_reason_text += _L(" The high drying temperature may cause AMS blockage, please unload first."); + break; + case DevAms::CannotDryReason::InitiatingAmsDrying: + cannot_reason_text = "*" + _L("Initiating AMS drying") + "\n"; + break; + case DevAms::CannotDryReason::NotSupportedIn2dMode: + cannot_reason_text = "*" + _L("Not supported in 2D mode") + "\n"; + break; + case DevAms::CannotDryReason::DryingInProgress: + cannot_reason_text = "*" + _L("Task in progress") + "\n"; + cannot_reason_text += _L(" The AMS might be in use during Task.") + "\n"; + break; + case DevAms::CannotDryReason::Upgrading: + cannot_reason_text = "*" + _L("Upgrading") + "\n"; + cannot_reason_text += _L(" Firmware update in progress, please wait...") + "\n"; + break; + case DevAms::CannotDryReason::InsufficientPowerNeedPluginPower: + cannot_reason_text = "*" + _L("Insufficient power") + "\n"; + cannot_reason_text += _L(" Please plug in the power and then use the drying function.") + "\n"; + break; + case DevAms::CannotDryReason::FilamentAtAmsOutletManualUnload: + cannot_reason_text = "*" + _L("Filament in AMS outlet") + "\n"; + cannot_reason_text += _L(" The high drying temperature may cause AMS blockage. Please unload the filament manually before proceeding.") + "\n"; + break; + default: + cannot_reason_text = "*" + _L("System is busy") + "\n"; + cannot_reason_text += _L(" Initiating other drying processes, please wait a few seconds...") + "\n"; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": unknown cannot dry reason"; + break; + } + return cannot_reason_text; +} + +wxString organize_cannot_reasons_text(std::vector& reasons) +{ + wxString cannot_reasons_text; + if (std::find(reasons.begin(), reasons.end(), DevAms::CannotDryReason::DryingInProgress) != reasons.end()) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::DryingInProgress); + } else if (std::find(reasons.begin(), reasons.end(), DevAms::CannotDryReason::AmsBusy) != reasons.end()) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::AmsBusy); + } else if (std::find(reasons.begin(), reasons.end(), DevAms::CannotDryReason::ConsumableAtAmsOutlet) != reasons.end()) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::ConsumableAtAmsOutlet); + } else if (std::find(reasons.begin(), reasons.end(), DevAms::CannotDryReason::FilamentAtAmsOutletManualUnload) != reasons.end()) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::FilamentAtAmsOutletManualUnload); + } + + if (std::find(reasons.begin(), reasons.end(), DevAms::CannotDryReason::InsufficientPower) != reasons.end()) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::InsufficientPower); + } + + for (auto reason : reasons) { + if (reason == DevAms::CannotDryReason::InsufficientPowerNeedPluginPower) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::InsufficientPowerNeedPluginPower); + } else if (reason == DevAms::CannotDryReason::NotSupportedIn2dMode) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::NotSupportedIn2dMode); + } else if (reason == DevAms::CannotDryReason::InitiatingAmsDrying) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::InitiatingAmsDrying); + } else if (reason == DevAms::CannotDryReason::Upgrading) { + cannot_reasons_text += get_cannot_reason_text(DevAms::CannotDryReason::Upgrading); + } + } + + if (cannot_reasons_text.empty()) { + cannot_reasons_text += "*" + _L("System is busy") + "\n"; + cannot_reasons_text += _L(" Initiating other drying processes, please wait a few seconds...") + "\n"; + } + + return cannot_reasons_text; +} + +int AMSDryCtrWin::update_state(DevAms* dev_ams) +{ + std::vector cannot_reasons = dev_ams->GetCannotDryReason().has_value()? + dev_ams->GetCannotDryReason().value(): std::vector(); + + if (cannot_reasons.size() == 0 || + (cannot_reasons.size() == 1 && cannot_reasons[0] == DevAms::CannotDryReason::DryingInProgress)) { + m_normal_state_sizer->Show(true); + m_cannot_dry_sizer->Show(false); + m_unload_button->Show(false); + update_normal_state(dev_ams); + } else if (cannot_reasons.size() > 0) { + m_normal_state_sizer->Show(false); + m_cannot_dry_sizer->Show(true); + + m_cannot_dry_description_label->SetLabel(organize_cannot_reasons_text(cannot_reasons)); + m_cannot_dry_description_label->Wrap(FromDIP(300)); + + // Show unload button when ConsumableAtAmsOutlet reason is present + bool has_consumable_at_outlet = std::find(cannot_reasons.begin(), cannot_reasons.end(), + DevAms::CannotDryReason::ConsumableAtAmsOutlet) != cannot_reasons.end(); + m_unload_button->Show(has_consumable_at_outlet); + } + + restore_stop_button_if_deadline_passed(); + restore_unload_button_if_deadline_passed(); + + return 1; +} + +int AMSDryCtrWin::update_ams_change(DevAms* dev_ams) +{ + if (!is_ams_changed(dev_ams)) { + return 0; + } + + m_ams_info.m_ams_id = dev_ams->GetAmsId(); + if (dev_ams->GetAmsType() == DevAmsType::N3F) { + m_temperature_input->SetHint("45-65" + wxString::FromUTF8("°C")); + } else if (dev_ams->GetAmsType() == DevAmsType::N3S) { + m_temperature_input->SetHint("45-85" + wxString::FromUTF8("°C")); + } + + m_time_input->SetHint("1-24 h"); + + return 0; +} + +int AMSDryCtrWin::update_dryness_status(DevAms* dev_ams) +{ + int updated = 0; + + if (m_ams_info.m_humidity_percent != dev_ams->GetHumidityPercent()) { + updated += 1; + m_ams_info.m_humidity_percent = dev_ams->GetHumidityPercent(); + m_humidity_data_label->SetLabel(std::to_string(m_ams_info.m_humidity_percent) + "%"); + } + + if (m_ams_info.m_temperature != dev_ams->GetCurrentTemperature()) { + updated += 1; + m_ams_info.m_temperature = dev_ams->GetCurrentTemperature(); + m_temperature_data_label->SetLabel(std::to_string(m_ams_info.m_temperature) + wxString::FromUTF8("°C")); + } + + if (is_dry_ctr_idle(dev_ams)) { + m_time_descrition_container->Show(false); + m_original_page->Layout(); + } else { + if (is_dry_status_changed(dev_ams)) { + m_time_descrition_container->Show(true); + m_original_page->Layout(); + } + + if (m_ams_info.m_left_dry_time != dev_ams->GetLeftDryTime()) { + updated += 1; + m_ams_info.m_left_dry_time = dev_ams->GetLeftDryTime(); + m_time_data_label->SetLabel(wxString::Format("%02d : %02d", + m_ams_info.m_left_dry_time / 60, m_ams_info.m_left_dry_time % 60)); + } + } + + return updated; +} + +bool AMSDryCtrWin::is_tray_changed(DevAms* dev_ams) +{ + return false; +} + +void AMSDryCtrWin::update_filament_guide_info(DevAms* dev_ams) +{ + if (!IsShown()) { + return; + } + + m_guide_page->Freeze(); + m_ams_filament_panel->Clear(); + m_ams_filament_panel->SetAmsName(dev_ams->GetDisplayName()); + + // Get the temperature input value + long input_temp = 0; + bool valid_temp = !m_temperature_input->GetValue().IsEmpty() && + m_temperature_input->GetValue().ToLong(&input_temp); + bool can_start = true; + + int slot_count = 0, empty_count = 0; + for (auto& tray_pair : dev_ams->GetTrays()) { + if (!tray_pair.second) { + continue; + } + ++slot_count; + if (!tray_pair.second->is_exists) { + m_ams_filament_panel->AddFilamentItem("/", "dev_ams_dry_ctr_enable"); + ++empty_count; + continue; + } + auto preset_opt = tray_pair.second->get_ams_drying_preset(); + wxString filament_type = tray_pair.second->get_display_filament_type(); + DevFilamentDryingPreset preset; + if (filament_type.IsEmpty()) { + auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00"); + preset = fallback_preset.value(); + filament_type = "?"; + } else if (preset_opt.has_value()) { + preset = preset_opt.value(); + } else { + auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00"); + preset = fallback_preset.value(); + } + std::string icon_path = "dev_ams_dry_ctr_enable"; + int distortion_temp = static_cast(preset.filament_dev_ams_drying_heat_distortion_temperature); + if (valid_temp && distortion_temp < input_temp) { + icon_path = "dev_ams_dry_ctr_disable"; + can_start = false; + } + m_ams_filament_panel->AddFilamentItem(filament_type, icon_path); + } + if (slot_count == 0) { + can_start = false; + } + + if (can_start) { + m_guide_title_label->SetLabel(_L("For better drying results, remove the filament and allow it to rotate.")); + m_guide_description_label->SetLabel(_L("The AMS will automatically rotate the stored filament slots to enhance the drying performance.") + + "\n" + _L("Alternatively, you can dry the filament without removing it.") + + "\n" + "*" + _L("Unknown filaments will be treated as PLA.")); + m_guide_description_label->Wrap(FromDIP(300)); + } else { + m_guide_title_label->SetLabel(_L("Please store the filament marked with an exclamation mark.")); + m_guide_description_label->SetLabel(_L("Filament left in the feeder during drying may soften because the drying temperature exceeds the softening point of materials like PLA and TPU.") + + "\n" + "*" + _L("Unknown filaments will be treated as PLA.")); + m_guide_description_label->Wrap(FromDIP(300)); + } + + m_start_button->Enable(can_start); + m_guide_page->Layout(); + m_guide_page->Thaw(); +} + +int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj) +{ + const bool ams_changed = is_ams_changed(dev_ams); + bool rebuilt_filament_list = false; + + // Build `m_tray_ids` and the combobox items from the preset bundle. + // This list is also used as a lookup table in non-idle state (type -> name), + // so it must be available even when the combobox is disabled. + auto rebuild_filament_list = [&]() -> bool { + m_trays_combo->Clear(); + m_tray_ids.clear(); + + PresetBundle *preset_bundle = wxGetApp().preset_bundle; + if (!preset_bundle || !obj) { + return false; + } + + std::set filament_id_set; + auto & filaments = preset_bundle->filaments; + + // Get nozzle diameter using the same method as AMSMaterialsSetting::Popup + std::ostringstream stream; + int extruder_id = obj->GetFilaSystem()->GetExtruderIdByAmsId(m_ams_info.m_ams_id); + if (!obj->GetExtderSystem()->GetExtderById(extruder_id)) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " get extruder id failed"; + extruder_id = 0; + } + stream << std::fixed << std::setprecision(1) << obj->GetExtderSystem()->GetNozzleDiameter(extruder_id); + std::string nozzle_diameter_str = stream.str(); + std::set printer_names = preset_bundle->get_printer_names_by_printer_type_and_nozzle( + DevPrinterConfigUtil::get_printer_display_name(obj->printer_type), nozzle_diameter_str); + + for (auto filament_it = filaments.begin(); filament_it != filaments.end(); ++filament_it) { + Preset& preset = *filament_it; + // Filter by system preset: root preset and (system preset or user preset is supported) + if (filaments.get_preset_base(*filament_it) != &preset || (!filament_it->is_system && !obj->is_support_user_preset)) { + continue; + } + + ConfigOption * printer_opt = filament_it->config.option("compatible_printers"); + ConfigOptionStrings *printer_strs = dynamic_cast(printer_opt); + if (!printer_strs) continue; + + for (auto printer_str : printer_strs->values) { + if (printer_names.find(printer_str) != printer_names.end()) { + if (filament_id_set.find(filament_it->filament_id) != filament_id_set.end()) { + continue; + } + + filament_id_set.insert(filament_it->filament_id); + auto filament_alias = filament_it->alias; + if (!filament_alias.empty()) { + auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id); + if (opt_info.has_value()) { + auto real_info = opt_info.value(); + real_info.filament_name = filament_alias; + m_tray_ids.push_back(std::move(real_info)); + m_trays_combo->Append(wxString::FromUTF8(filament_alias)); + } + } + } + } + } + + if (m_tray_ids.empty()) { + BOOST_LOG_TRIVIAL(warning) << "AMSDryCtrWin::update_filament_list: No valid filaments found"; + return false; + } + + return true; + }; + + if (ams_changed || m_tray_ids.empty() || m_trays_combo->GetCount() == 0) { + // Disable start button during rebuild + if (m_start_button) { + m_start_button->Disable(); + } + + rebuilt_filament_list = rebuild_filament_list(); + } + + if (!is_dry_ctr_idle(dev_ams)) { + const std::string& ams_id = dev_ams->GetAmsId(); + const auto settings_opt = dev_ams->GetDrySettings(); + + // Set the combobox display label by the filament "type" string. + // Priority: last saved selection for this AMS (if the type matches) -> fallback to current `m_tray_ids`. + auto set_filament_label_by_type = [&](const std::string& filament_type) { + if (filament_type.empty()) { + return; + } + + auto it_name = m_dry_setting.m_filament_names.find(ams_id); + auto it_type = m_dry_setting.m_filament_type.find(ams_id); + if (it_name != m_dry_setting.m_filament_names.end() && it_type != m_dry_setting.m_filament_type.end() + && it_type->second == filament_type) { + m_trays_combo->SetLabel(wxString::FromUTF8(it_name->second)); + return; + } + + const auto it = std::find_if(m_tray_ids.begin(), m_tray_ids.end(), [&](const FilamentBaseInfo& tray) { + return tray.filament_type == filament_type; + }); + if (it != m_tray_ids.end()) { + m_trays_combo->SetLabel(wxString::FromUTF8(it->filament_name)); + } + }; + + if (settings_opt.has_value()) { + const auto& settings = settings_opt.value(); + m_temperature_input->SetValue(std::to_string(settings.dry_temp)); + m_time_input->SetValue(std::to_string(settings.dry_hour)); + set_filament_label_by_type(settings.dry_filament); + } else { + auto it_name = m_dry_setting.m_filament_names.find(ams_id); + if (it_name != m_dry_setting.m_filament_names.end()) { + m_trays_combo->SetLabel(wxString::FromUTF8(it_name->second)); + m_temperature_input->SetValue(std::to_string(m_dry_setting.m_dry_temp[ams_id])); + m_time_input->SetValue(std::to_string(m_dry_setting.m_dry_time[ams_id])); + } + } + + return 0; + } + + // Idle state: avoid re-selecting / firing selection change unless the list was rebuilt. + if (!rebuilt_filament_list && !ams_changed && is_dry_ctr_idle()) { + return 0; + } + + if (m_tray_ids.empty()) { + return 0; + } + + // Select recommended drying temperature and default filament + float min_dry_temp = std::numeric_limits::max(); + std::string default_filament_id = "GFA00"; + bool has_ready = false; + const auto fallback_preset = DevUtilBackend::GetFilamentDryingPreset("GFA00"); + for (const auto& tray_pair : dev_ams->GetTrays()) { + if (!tray_pair.second || !tray_pair.second->is_tray_info_ready()) continue; + has_ready = true; + wxString filament_type = tray_pair.second->get_display_filament_type(); + Slic3r::DevFilamentDryingPreset preset; + if (filament_type.IsEmpty()) { + // no filament type, is PLA + if (!fallback_preset) continue; + preset = fallback_preset.value(); + } else { + auto preset_opt = tray_pair.second->get_ams_drying_preset(); + if (preset_opt.has_value()) { + preset = preset_opt.value(); + } else { + // no preset,is PLA + if (!fallback_preset) continue; + preset = fallback_preset.value(); + } + } + float cur_temp = m_printer_status.m_is_printing + ? std::min({preset.filament_dev_ams_drying_temperature_on_print[dev_ams->GetAmsType()], + preset.filament_dev_drying_softening_temperature, preset.filament_dev_ams_drying_heat_distortion_temperature}) + : preset.filament_dev_ams_drying_temperature_on_idle[dev_ams->GetAmsType()]; + if (cur_temp < min_dry_temp) { + min_dry_temp = cur_temp; + default_filament_id = preset.filament_id; + } + } + // if no tray is ready, use PLA as default + if (!has_ready) { + if (fallback_preset.has_value()) { + Slic3r::DevFilamentDryingPreset preset = fallback_preset.value(); + float cur_temp = m_printer_status.m_is_printing + ? std::min({preset.filament_dev_ams_drying_temperature_on_print[dev_ams->GetAmsType()], + preset.filament_dev_drying_softening_temperature, preset.filament_dev_ams_drying_heat_distortion_temperature}) + : preset.filament_dev_ams_drying_temperature_on_idle[dev_ams->GetAmsType()]; + min_dry_temp = cur_temp; + default_filament_id = preset.filament_id; + } + } + m_ams_info.m_recommand_dry_temp = min_dry_temp; + + // Set default selection + unsigned int default_index = 0; + for (unsigned int i = 0; i < m_tray_ids.size(); i++) { + if (m_tray_ids[i].filament_id == default_filament_id) { + default_index = i; + break; + } + } + m_trays_combo->SetSelection(default_index); + wxCommandEvent evt(wxEVT_COMBOBOX, m_trays_combo->GetId()); + evt.SetInt(default_index); + OnFilamentSelectionChanged(evt); + return 1; +} + +std::shared_ptr AMSDryCtrWin::get_fila_system() const +{ + std::shared_ptr fila_system = m_fila_system.lock(); + if (!fila_system) { + const_cast(this)->Close(); + } + return fila_system; +} + +void AMSDryCtrWin::update_printer_state(MachineObject* obj) +{ + m_printer_status.m_is_printing = obj->is_in_printing() + && obj->GetExtderSystem()->GetCurrentAmsId() == m_ams_info.m_ams_id; +} + +void AMSDryCtrWin::update(std::shared_ptr fila_system, MachineObject* obj) +{ + if (!fila_system || !obj) { + return; + } + + update_printer_state(obj); + m_fila_system = fila_system; + + DevAms* dev_ams = fila_system->GetAmsById(m_ams_info.m_ams_id); + if (!dev_ams) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::update: Invalid AMS id"; + m_ams_info.m_ams_id = ""; + Close(); + return; + } + + if (!dev_ams->IsSupportRemoteDry(fila_system->GetOwner())) { + BOOST_LOG_TRIVIAL(info) << "AMSDryCtrWin::update: Selected AMS does not support remote drying"; + Close(); + return; + } + + + update_ams_change(dev_ams); + + update_image(dev_ams->GetAmsType(), + dev_ams->GetDryStatus().has_value()? dev_ams->GetDryStatus().value(): DevAms::DryStatus::Off, + dev_ams->GetDrySubStatus().has_value()? dev_ams->GetDrySubStatus().value(): DevAms::DrySubStatus::Off, + dev_ams->GetHumidityPercent()); + + update_state(dev_ams); + update_dryness_status(dev_ams); + + update_filament_list(dev_ams, obj); + update_filament_guide_info(dev_ams); + + m_is_ams_changed = false; + + check_values_changed(dev_ams); + + Layout(); + Refresh(); +} + +bool AMSDryCtrWin::is_ams_changed(DevAms* dev_ams) +{ + return m_ams_info.m_ams_id != dev_ams->GetAmsId() || m_is_ams_changed; +} + +bool AMSDryCtrWin::is_dry_status_changed(DevAms* dev_ams) +{ + if (!dev_ams->GetDryStatus().has_value() || !dev_ams->GetDrySubStatus().has_value()) { + return true; + } + + return dev_ams->GetDryStatus().value() != m_ams_info.m_dry_status + || dev_ams->GetDrySubStatus().value() != m_ams_info.m_dry_sub_status; +} + +bool AMSDryCtrWin::is_dry_ctr_idle(DevAms* dev_ams) +{ + if (!dev_ams->GetDryStatus().has_value() || !dev_ams->GetDrySubStatus().has_value()) { + return true; + } + + return dev_ams->GetDryStatus().value() == DevAms::DryStatus::Off + || dev_ams->GetDryStatus().value() == DevAms::DryStatus::Cooling; +} + +bool AMSDryCtrWin::is_dry_ctr_idle() +{ + return m_ams_info.m_dry_status == DevAms::DryStatus::Off || m_ams_info.m_dry_status == DevAms::DryStatus::Cooling; +} + +bool AMSDryCtrWin::is_dry_ctr_err(DevAms* dev_ams) +{ + if (!dev_ams->GetDryStatus().has_value() || !dev_ams->GetDrySubStatus().has_value()) { + return false; + } + + return dev_ams->GetDryStatus().value() == DevAms::DryStatus::Error; +} + +} // GUI +} // Slic3r diff --git a/src/slic3r/GUI/AMSDryControl.hpp b/src/slic3r/GUI/AMSDryControl.hpp new file mode 100644 index 0000000000..43e177eeb1 --- /dev/null +++ b/src/slic3r/GUI/AMSDryControl.hpp @@ -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 +#include + + +//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 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 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 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 m_stop_button_restore_deadline; + std::optional m_unload_button_restore_deadline; + + Label* m_progress_title; + int m_progress_value; + int m_progress_message_index; + std::vector 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 m_filament_items; + wxStaticBitmap* m_image_placeholder{nullptr}; + ScalableBitmap m_guide_image; + + + bool m_is_ams_changed = false; + std::weak_ptr 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 m_filament_names; + std::unordered_map m_filament_type; + std::unordered_map m_dry_temp; + std::unordered_map 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 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 From 08b08e09fc55ee3c4a8921707d88827691368d1e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 14:23:05 +0800 Subject: [PATCH 014/130] fix: use OrcaSlicerTitle.ico instead of BambuStudioTitle.ico --- src/slic3r/GUI/AMSDryControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index f88e46f65c..f8ced3ea39 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -977,7 +977,7 @@ void AMSDryCtrWin::create() // set title icon SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); this->SetDoubleBuffered(true); - std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); SetSize(wxSize(FromDIP(700), FromDIP(500))); From b2827cb9fa21dff9904525d53ce4ed7926c1b5d1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 14:36:52 +0800 Subject: [PATCH 015/130] feat: wire AMS humidity click to open AMSDryControl dialog For N3F and N3S AMS types, clicking the humidity indicator now opens the full drying control dialog instead of the popup. --- src/slic3r/GUI/Widgets/AMSControl.cpp | 36 +++++++++++++++++++++++++++ src/slic3r/GUI/Widgets/AMSControl.hpp | 2 ++ 2 files changed, 38 insertions(+) diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index a3913dc4e4..ea62d18d92 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/MsgDialog.hpp" #include "slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h" +#include "slic3r/GUI/AMSDryControl.hpp" #include "slic3r/GUI/DeviceCore/DevManager.h" #include "slic3r/GUI/DeviceCore/DevFilaSystem.h" @@ -254,6 +255,24 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons if (humidity_value > 0 && humidity_value <= 5) { m_Humidity_tip_popup.set_humidity_level(humidity_value); } m_Humidity_tip_popup.Popup(); } + else if (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS) + { + // Open full drying control dialog for N3F/N3S AMS + if (!m_dry_ctr_win) { + m_dry_ctr_win = new AMSDryCtrWin(this); + } + m_dry_ctr_win->set_ams_id(info->ams_id); + + Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (dev) { + MachineObject *obj = dev->get_selected_machine(); + if (obj && obj->GetFilaSystem()) { + std::shared_ptr fila_ptr(obj->GetFilaSystem(), [](DevFilaSystem*){}); + m_dry_ctr_win->update(fila_ptr, obj); + } + } + m_dry_ctr_win->ShowModal(); + } else { m_percent_humidity_dry_popup->Update(info); @@ -493,6 +512,10 @@ void AMSControl::msw_rescale() m_percent_humidity_dry_popup->msw_rescale(); } + if (m_dry_ctr_win){ + m_dry_ctr_win->msw_rescale(); + } + m_Humidity_tip_popup.msw_rescale(); Layout(); @@ -970,6 +993,19 @@ void AMSControl::UpdateAms(const std::string &series_name, } } + /*update AMS dry control dialog*/ + if (m_dry_ctr_win && m_dry_ctr_win->IsShown()) + { + Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); + if (dev) { + MachineObject *obj = dev->get_selected_machine(); + if (obj && obj->GetFilaSystem()) { + std::shared_ptr fila_ptr(obj->GetFilaSystem(), [](DevFilaSystem*){}); + m_dry_ctr_win->update(fila_ptr, obj); + } + } + } + /*update ams extruder*/ if (m_extruder->updateNozzleNum(m_total_ext_count, series_name)) { diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 31c6b86feb..93d9acee67 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -21,6 +21,7 @@ namespace Slic3r { namespace GUI { //Previous definitions class uiAmsPercentHumidityDryPopup; +class AMSDryCtrWin; class AMSControl : public wxSimplebook { @@ -118,6 +119,7 @@ protected: AmsHumidityTipPopup m_Humidity_tip_popup; uiAmsPercentHumidityDryPopup* m_percent_humidity_dry_popup; + AMSDryCtrWin* m_dry_ctr_win{nullptr}; std::string m_last_ams_id = ""; std::string m_last_tray_id = ""; From 044a113d54946c55e39b6d67c940e61402733948 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 14:47:33 +0800 Subject: [PATCH 016/130] feat: update error dialog stop-drying to use CtrlAmsStopDrying Keeps command_ams_drying_stop() fallback for backward compatibility. --- src/slic3r/GUI/DeviceErrorDialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/slic3r/GUI/DeviceErrorDialog.cpp b/src/slic3r/GUI/DeviceErrorDialog.cpp index 353250361f..41d54e0ecd 100644 --- a/src/slic3r/GUI/DeviceErrorDialog.cpp +++ b/src/slic3r/GUI/DeviceErrorDialog.cpp @@ -5,6 +5,7 @@ #include "GUI_App.hpp" #include "MainFrame.hpp" #include "ReleaseNote.hpp" +#include "DeviceCore/DevFilaSystem.h" namespace Slic3r { namespace GUI @@ -449,6 +450,11 @@ void DeviceErrorDialog::on_button_click(ActionButton btn_id) break; } case DeviceErrorDialog::STOP_DRYING: { + // Use the canonical CtrlAmsStopDrying path + if (m_obj && m_obj->GetFilaSystem()) { + m_obj->GetFilaSystem()->CtrlAmsStopDrying(0); + } + // Fallback to the old command for backward compatibility m_obj->command_ams_drying_stop(); break; } From 2524669139a1324e7e51567c81ff673b2a09c121 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 14:47:52 +0800 Subject: [PATCH 017/130] Revert "feat: update error dialog stop-drying to use CtrlAmsStopDrying" This reverts commit 044a113d54946c55e39b6d67c940e61402733948. --- src/slic3r/GUI/DeviceErrorDialog.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/slic3r/GUI/DeviceErrorDialog.cpp b/src/slic3r/GUI/DeviceErrorDialog.cpp index 41d54e0ecd..353250361f 100644 --- a/src/slic3r/GUI/DeviceErrorDialog.cpp +++ b/src/slic3r/GUI/DeviceErrorDialog.cpp @@ -5,7 +5,6 @@ #include "GUI_App.hpp" #include "MainFrame.hpp" #include "ReleaseNote.hpp" -#include "DeviceCore/DevFilaSystem.h" namespace Slic3r { namespace GUI @@ -450,11 +449,6 @@ void DeviceErrorDialog::on_button_click(ActionButton btn_id) break; } case DeviceErrorDialog::STOP_DRYING: { - // Use the canonical CtrlAmsStopDrying path - if (m_obj && m_obj->GetFilaSystem()) { - m_obj->GetFilaSystem()->CtrlAmsStopDrying(0); - } - // Fallback to the old command for backward compatibility m_obj->command_ams_drying_stop(); break; } From 668654da5f57c9876c6f82ec5a74206121b7f527 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 14:58:51 +0800 Subject: [PATCH 018/130] fix: use dark humidity icons in dark mode --- src/slic3r/GUI/AMSDryControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index f8ced3ea39..7e727abbdf 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -42,7 +42,7 @@ static std::string get_humidity_level_img_path(int humidity_percent) } if (wxGetApp().dark_mode()) { - return "hum_level" + std::to_string(hum_level) + "_no_num_light"; + return "hum_level" + std::to_string(hum_level) + "_no_num_dark"; } else { return "hum_level" + std::to_string(hum_level) + "_no_num_light"; } From 23799e02100f69f37fbc97ef78ffd7d0c4bd74e6 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 15:20:26 +0800 Subject: [PATCH 019/130] chore: remove superpowers planning docs --- .../2026-07-07-ams-drying-control-plan.md | 1046 ----------------- .../2026-07-07-ams-drying-control-design.md | 325 ----- 2 files changed, 1371 deletions(-) delete mode 100644 docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md delete mode 100644 docs/superpowers/specs/2026-07-07-ams-drying-control-design.md diff --git a/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md b/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md deleted file mode 100644 index 6cd673c5a6..0000000000 --- a/docs/superpowers/plans/2026-07-07-ams-drying-control-plan.md +++ /dev/null @@ -1,1046 +0,0 @@ -# AMS Drying Control — Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Port the AMS filament drying control feature from BambuStudio into OrcaSlicer, enabling users to start, monitor, and stop filament drying via the AMS unit from the slicer UI. - -**Architecture:** Add drying status enums/structs to the `DevAms` data model, extend the JSON parser to populate them, add `CtrlAmsStartDryingHour`/`CtrlAmsStopDrying` commands to `DevFilaSystem`, create a `DevUtilBackend` utility for filament drying preset lookup, and build the `AMSDryCtrWin` dialog. Wire the dialog to open when clicking the AMS humidity indicator for N3F/N3S AMS types. - -**Tech Stack:** C++17, wxWidgets, nlohmann/json, Boost - -## Global Constraints - -- **N3F/N3S only:** Standard AMS and AMS Lite do not have heating hardware; the dialog is not shown for them -- **Backward compatibility:** Existing `command_ams_drying_stop()` is preserved; new commands are additive -- **Cross-platform:** wxWidgets UI must work on Windows, macOS, Linux -- **Dark mode:** Dialog must support dark mode via `wxGetApp().dark_mode()` and `StateColor::darkModeColorFor()` -- **Profile compatibility:** Existing profiles with `filament_dev_ams_drying_*` keys (Qidi) continue to work; the feature reads the same keys -- **No printer-agent changes needed:** All commands go through existing `publish_json()` → `NetworkAgent` path -- **Reference:** `D:\projects\BambuStudio` — match its behavior as much as possible; when in doubt, check the BambuStudio source - ---- - -### Task 1: Global `DevAmsType` enum in `DevDefs.h` - -**Files:** -- Modify: `src/slic3r/GUI/DeviceCore/DevDefs.h` -- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` (replace local `AmsType` enum with typedef) -- Modify: `src/slic3r/GUI/DeviceCore/DevMapping.cpp` (rename `DevAms::DUMMY` → `DevAms::EXT_SPOOL`) - -**Interfaces:** -- Produces: Global `enum DevAmsType { EXT_SPOOL=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }` in `DevDefs.h` -- Produces: `using AmsType = DevAmsType;` inside `DevAms` class (replaces old local enum) -- Note: Old `DevAms::DUMMY` becomes `DevAms::EXT_SPOOL`; all existing references update accordingly - -- [ ] **Step 1: Add global `DevAmsType` enum to `DevDefs.h`** - -In `src/slic3r/GUI/DeviceCore/DevDefs.h`, add before the closing `namespace Slic3r` or after existing enums: - -```cpp -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 -}; -``` - -- [ ] **Step 2: Replace `DevAms::AmsType` local enum with typedef** - -In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, find the `DevAms` class and replace the local enum: - -```cpp -// Before (delete this): - enum AmsType : int - { - DUMMY = 0, - AMS = 1, // AMS - AMS_LITE = 2, // AMS-Lite - N3F = 3, // N3F - N3S = 4, // N3S - }; - -// After (replace with): - using AmsType = DevAmsType; -``` - -- [ ] **Step 3: Rename `DevAms::DUMMY` → `DevAms::EXT_SPOOL` in `DevMapping.cpp`** - -In `src/slic3r/GUI/DeviceCore/DevMapping.cpp` line 189: - -```cpp -// Before: -_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::DUMMY, tray, info); -// After: -_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::EXT_SPOOL, tray, info); -``` - -- [ ] **Step 4: Rename `DUMMY` → `EXT_SPOOL` in `DevFilaSystem.cpp`** - -In `src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp` line 114: - -```cpp -// Before: -assert(DUMMY < type && m_ams_type <= N3S); -// After: -assert(EXT_SPOOL < type && m_ams_type <= N3S); -``` - -- [ ] **Step 5: Verify the build compiles** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -Expected: build succeeds, no `DUMMY` or `AmsType` related compile errors. - -- [ ] **Step 6: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevDefs.h src/slic3r/GUI/DeviceCore/DevFilaSystem.h src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp src/slic3r/GUI/DeviceCore/DevMapping.cpp -git commit -m "refactor: promote DevAmsType to global enum, rename DUMMY to EXT_SPOOL - -Matches BambuStudio's DevAmsType naming convention." -``` - ---- - -### Task 2: Drying enums and structs in `DevAms` - -**Files:** -- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` - -**Interfaces:** -- Produces: `DevAms::DryCtrlMode`, `DevAms::DryStatus`, `DevAms::DrySubStatus`, `DevAms::DryFanStatus`, `DevAms::CannotDryReason` enums -- Produces: `DevAms::DrySettings` struct -- Produces: Getters: `GetDryStatus()`, `GetDrySubStatus()`, `GetFan1Status()`, `GetFan2Status()`, `GetCannotDryReason()`, `GetDrySettings()` -- Produces: `IsSupportRemoteDry(const MachineObject*)`, `AmsIsDrying()` -- Produces: `SupportDrying()` — already exists as `m_ams_type > AMS_LITE`; update to check N3F/N3S -- Produces: Members: `m_dry_status`, `m_dry_sub_status`, `m_dry_fan1_status`, `m_dry_fan2_status`, `m_dry_cannot_reasons`, `m_dry_settings` - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.h` lines 119–262 - -- [ ] **Step 1: Add enums inside `DevAms` class** - -In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, inside the `DevAms` class (after the `using AmsType = DevAmsType;` line, before the `public:` constructor section), add: - -```cpp -public: - - enum class DryCtrlMode : int - { - 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 - }; -``` - -- [ ] **Step 2: Add new getters to `DevAms`** - -After the existing `GetLeftDryTime()` getter, add: - -```cpp - // remote drying control - bool IsSupportRemoteDry(const MachineObject* obj) const; - std::optional GetDryStatus() const { return m_dry_status; }; - std::optional GetDrySubStatus() const { return m_dry_sub_status; } - std::optional GetFan1Status() const { return m_dry_fan1_status; } - std::optional GetFan2Status() const { return m_dry_fan2_status; } - std::optional> GetCannotDryReason() const { return m_dry_cannot_reasons; } - std::optional GetDrySettings() const { return m_dry_settings; }; - - bool AmsIsDrying(); -``` - -- [ ] **Step 3: Add new private members to `DevAms`** - -In the private section of `DevAms`, after `m_left_dry_time`, add: - -```cpp - // see is_support_remote_dry - std::optional m_dry_status; - std::optional m_dry_sub_status; - std::optional m_dry_fan1_status; - std::optional m_dry_fan2_status; - std::optional> m_dry_cannot_reasons; - std::optional m_dry_settings; -``` - -Note: In BambuStudio these members are `public:` (prefixed with `public:` before `m_dry_status`). Keep them private and use getters. The friends (`DevFilaSystemParser`) can access them. - -Also remove the duplicate `GetAmsType()` which currently returns `m_ams_type` — since `m_ams_type` is now `DevAmsType`, the getter still works. - -- [ ] **Step 4: Add forward declaration for `DevFilamentDryingPreset`** - -At the top of the file, after the existing forward declarations: - -```cpp -struct DevFilamentDryingPreset; -``` - -- [ ] **Step 5: Verify the header compiles** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -Expected: build succeeds. If there are compilation errors related to `GetAmsType()` return type, check that `AmsType` typedef resolves correctly. - -- [ ] **Step 6: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevFilaSystem.h -git commit -m "feat: add drying enums, structs, getters to DevAms - -Adds DryCtrlMode, DryStatus, DrySubStatus, DryFanStatus, -CannotDryReason enums and DrySettings struct for AMS drying control." -``` - ---- - -### Task 3: `DevFilamentDryingPreset` struct and `DevFilaSystem` ctrl declarations - -**Files:** -- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.h` - -**Interfaces:** -- Produces: `struct DevFilamentDryingPreset` at namespace scope -- Produces: `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 = false) const` -- Produces: `DevFilaSystem::CtrlAmsStopDrying(int ams_id) const` -- Produces: `DevAmsTray::get_ams_drying_preset()` method - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.h` lines 350–362 - -- [ ] **Step 1: Add `DevFilamentDryingPreset` struct at namespace scope** - -In `src/slic3r/GUI/DeviceCore/DevFilaSystem.h`, add after the `DevFilaSystemParser` class (at the very end of the file, before `}// namespace Slic3r`): - -```cpp -struct DevFilamentDryingPreset -{ - std::string filament_id; - - std::unordered_set ams_limitations; // only use ams types in the set - std::unordered_map filament_dev_ams_drying_time_on_idle; // hour - std::unordered_map filament_dev_ams_drying_temperature_on_idle; - std::unordered_map filament_dev_ams_drying_time_on_print; // hour - std::unordered_map 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; -}; -``` - -- [ ] **Step 2: Add control method declarations to `DevFilaSystem`** - -In the `DevFilaSystem` class, after the existing `CtrlAmsReset()` declaration: - -```cpp - // 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; -``` - -- [ ] **Step 3: Add `get_ams_drying_preset()` to `DevAmsTray`** - -In the `DevAmsTray` class, add after the `get_filament_type()` method: - -```cpp - std::optional get_ams_drying_preset() const; -``` - -Also add `#include ` and `#include ` to the includes if not already present. -Add `#include ` if not already present. - -- [ ] **Step 4: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 5: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevFilaSystem.h -git commit -m "feat: add DevFilamentDryingPreset, ctrl method declarations, tray preset getter" -``` - ---- - -### Task 4: `DevUtilBackend` utility class - -**Files:** -- Create: `src/slic3r/GUI/DeviceCore/DevUtilBackend.h` -- Create: `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp` -- Modify: `src/slic3r/GUI/DeviceCore/CMakeLists.txt` - -**Interfaces:** -- Produces: `DevUtilBackend::GetFilamentDryingPreset(const std::string& fila_id)` → `std::optional` - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevUtilBackend.h`, `DevUtilBackend.cpp` - -- [ ] **Step 1: Create `DevUtilBackend.h`** - -Create `src/slic3r/GUI/DeviceCore/DevUtilBackend.h`: - -```cpp -/** - * @file DevUtilBackend.h - * @brief Provides common static utility methods for backend (preset/slicing). - */ - -#pragma once -#include "DevDefs.h" -#include "DevFilaSystem.h" - -#include -#include - -namespace Slic3r -{ - -class DevUtilBackend -{ -public: - DevUtilBackend() = delete; - -public: - // for filament preset - static std::optional GetFilamentDryingPreset(const std::string& fila_id); -}; - -}; // namespace Slic3r -``` - -- [ ] **Step 2: Create `DevUtilBackend.cpp`** - -Create `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp`: - -```cpp -#include "DevUtilBackend.h" - -#include "slic3r/GUI/GUI_App.hpp" - -#include "libslic3r/Preset.hpp" - -#include - -namespace Slic3r -{ - -static std::unordered_map s_ams_type_map = { - {"0", DevAmsType::N3F}, - {"1", DevAmsType::N3S}, -}; - -std::optional 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 types = config.option("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("filament_dev_ams_drying_temperature")->get_at(0); - info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_temperature")->get_at(1); - info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_temperature")->get_at(2); - info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3S] = config.option("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("filament_dev_ams_drying_time")->get_at(0); - info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(1); - info.filament_dev_ams_drying_time_on_print[DevAmsType::N3F] = config.option("filament_dev_ams_drying_time")->get_at(2); - info.filament_dev_ams_drying_time_on_print[DevAmsType::N3S] = config.option("filament_dev_ams_drying_time")->get_at(3); - } - - if (config.has("filament_dev_drying_softening_temperature")) { - info.filament_dev_drying_softening_temperature = config.option("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("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("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 -``` - -- [ ] **Step 3: Register new files in CMakeLists.txt** - -In `src/slic3r/GUI/DeviceCore/CMakeLists.txt`, add the new files. After the existing `DevFilaSystemCtrl.cpp` line: - -```cmake - GUI/DeviceCore/DevUtilBackend.h - GUI/DeviceCore/DevUtilBackend.cpp -``` - -- [ ] **Step 4: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -Expected: build succeeds. If `ConfigOptionStrings` or `ConfigOptionFloats` are not found, check the includes — they're in `libslic3r/Preset.hpp` and `libslic3r/PrintConfig.hpp`. - -- [ ] **Step 5: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevUtilBackend.h src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp src/slic3r/GUI/DeviceCore/CMakeLists.txt -git commit -m "feat: add DevUtilBackend with GetFilamentDryingPreset - -Reads filament_dev_ams_drying_* config keys from filament presets -and returns structured DevFilamentDryingPreset data." -``` - ---- - -### Task 5: JSON parsing for drying status fields - -**Files:** -- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp` - -**Interfaces:** -- Consumes: `DevAms::DryStatus`, `DevAms::DrySubStatus`, `DevAms::DryFanStatus`, `DevAms::CannotDryReason`, `DevAms::DrySettings` -- Parses from JSON: `dry_time`, info flag bits (dry_status/fan1/fan2/sub_status), `dry_setting`, `dry_sf_reason` - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystem.cpp` lines 690–712 - -- [ ] **Step 1: Locate the AMS parsing section in `DevFilaSystemParser::ParseV1_0()`** - -First, read `DevFilaSystem.cpp` to find where `m_left_dry_time` is parsed (look for "dry_time") and where the AMS info section is. The parsing function is `DevFilaSystemParser::ParseV1_0`. - -- [ ] **Step 2: Add drying status field parsing** - -After the existing `m_left_dry_time` parsing line (which parses `"dry_time"` from JSON), add the drying status parsing. The exact location will be in the AMS loop where `curr_ams` is populated. - -After `DevJsonValParser::ParseVal(j_ams, "dry_time", curr_ams->m_left_dry_time);` (or the equivalent line), add: - -```cpp - // Drying status — only parse if printer supports remote drying - if (obj->is_support_remote_dry) { - if (j_ams.contains("info")) { - const std::string& info = j_ams["info"].get(); - 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); - } - - if (j_ams.contains("dry_setting")) { - const auto& j_dry_settings = j_ams["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 (j_ams.contains("dry_sf_reason")) { - curr_ams->m_dry_cannot_reasons = DevJsonValParser::GetVal>(j_ams, "dry_sf_reason"); - } - } -``` - -Note: Check if `DevUtil::get_flag_bits` and `DevJsonValParser` exist in OrcaSlicer. If not, these utilities must be added. Check BambuStudio's `DevUtil.h` for `get_flag_bits` and `DevJsonValParser` for the parsing helper. If these are missing, add minimal versions or inline the parsing. - -Check specifically whether `DevUtil.h` in OrcaSlicer has `get_flag_bits`. The `DevUtil.h` exists in the CMakeLists. Check its contents — it should have a static `get_flag_bits(std::string, int, int)` method. If not present, port it from BambuStudio. - -- [ ] **Step 3: Implement `IsSupportRemoteDry()` and `AmsIsDrying()`** - -In the same file, add the implementations after the existing `DevAms` methods: - -```cpp -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; -} -``` - -- [ ] **Step 4: Implement `DevAmsTray::get_ams_drying_preset()`** - -```cpp -std::optional DevAmsTray::get_ams_drying_preset() const -{ - return DevUtilBackend::GetFilamentDryingPreset(setting_id); -} -``` - -- [ ] **Step 5: Ensure `#include "DevUtilBackend.h"` is present in `DevFilaSystem.cpp`** - -Add at the top if not present. - -- [ ] **Step 6: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 7: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp -git commit -m "feat: add drying status JSON parsing and DevAms helper methods - -Parse dry_status, dry_sub_status, dry_fan statuses, -dry_settings, and dry_cannot_reasons from printer JSON. -Implement IsSupportRemoteDry, AmsIsDrying, get_ams_drying_preset." -``` - ---- - -### Task 6: `is_support_remote_dry` flag on `MachineObject` - -**Files:** -- Modify: `src/slic3r/GUI/DeviceManager.hpp` (add field) -- Modify: `src/slic3r/GUI/DeviceManager.cpp` (parse the flag) - -**Interfaces:** -- Produces: `MachineObject::is_support_remote_dry` (bool) - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceManager.hpp` line 566, `DeviceManager.cpp` line 4403 - -- [ ] **Step 1: Add `is_support_remote_dry` field to `MachineObject`** - -In `src/slic3r/GUI/DeviceManager.hpp`, find the section with other `is_support_*` flags (near `is_support_ams_humidity`) and add: - -```cpp - bool is_support_remote_dry = false; -``` - -- [ ] **Step 2: Parse `is_support_remote_dry` from firmware flags** - -In `src/slic3r/GUI/DeviceManager.cpp`, find the `parse_version_func()` or `parse_new_info()` method where other `is_support_*` flags are set. Look for the `is_support_ams_humidity` parsing pattern. - -Add parsing for `is_support_remote_dry` from the `fun2` field. Check the BambuStudio reference: it uses `get_flag_bits_no_border(fun2, 5) == 1` for bit 5. The exact location depends on how OrcaSlicer parses firmware capability bits. - -If a `fun2` parsing block exists, add: -```cpp - is_support_remote_dry = (get_flag_bits_no_border(fun2, 5) == 1); -``` - -If `fun2` parsing or `get_flag_bits_no_border` don't exist yet in OrcaSlicer, check how similar flags like `is_support_ams_humidity` are parsed and follow the same pattern. If the needed helper methods are missing, port them from BambuStudio's `DeviceManager.cpp`. - -- [ ] **Step 3: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 4: Commit** - -```bash -git add src/slic3r/GUI/DeviceManager.hpp src/slic3r/GUI/DeviceManager.cpp -git commit -m "feat: add is_support_remote_dry flag to MachineObject - -Parsed from firmware fun2 bit 5. Controls whether drying -status fields are parsed and drying commands are available." -``` - ---- - -### Task 7: Start/Stop drying commands in `DevFilaSystemCtrl.cpp` - -**Files:** -- Modify: `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp` - -**Interfaces:** -- Consumes: `MachineObject::m_sequence_id`, `MachineObject::publish_json()` -- Produces: `DevFilaSystem::CtrlAmsStartDryingHour(...)`, `DevFilaSystem::CtrlAmsStopDrying(int)` - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\DeviceCore\DevFilaSystemCtrl.cpp` - -- [ ] **Step 1: Add `CtrlAmsStartDryingHour` and `CtrlAmsStopDrying`** - -In `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp`, add after the existing `CtrlAmsReset()` method: - -```cpp -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"] = 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"] = 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); -} -``` - -Note: The `DevAms::DryCtrlMode` enum class uses `DevAms::DryCtrlMode::OnTime` in C++. When serialized to JSON (`jj_command["print"]["mode"] = DevAms::DryCtrlMode::OnTime`), nlohmann/json will convert the enum class to its underlying int (1). This matches the BambuStudio behavior. If the implicit conversion doesn't compile, add a `static_cast()` wrapper. - -- [ ] **Step 2: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 3: Commit** - -```bash -git add src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp -git commit -m "feat: add CtrlAmsStartDryingHour and CtrlAmsStopDrying commands - -Publish 'ams_filament_drying' JSON commands via MQTT for -starting and stopping AMS filament drying." -``` - ---- - -### Task 8: Copy image assets from BambuStudio - -**Files:** -- Copy 14 image files from `D:\projects\BambuStudio\resources\images\` to `resources\images\` - -**Assets to copy:** - -```powershell -Copy-Item "D:\projects\BambuStudio\resources\images\hum_level1_no_num_light.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\hum_level2_no_num_light.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\hum_level3_no_num_light.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\hum_level4_no_num_light.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\hum_level5_no_num_light.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_heating.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_dehumidifying.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_error.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3f_cooling.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_heating.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_dehumidifying.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_error.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_n3s_cooling.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_heating_icon.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_filament_in_chamber.png" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_enable.svg" -Destination "resources\images\" -Copy-Item "D:\projects\BambuStudio\resources\images\dev_ams_dry_ctr_disable.svg" -Destination "resources\images\" -``` - -- [ ] **Step 1: Copy each asset** - -Run each Copy-Item command. If any file is missing from the source, note it — the dialog will degrade gracefully with null bitmaps. - -- [ ] **Step 2: Verify files exist** - -```powershell -Get-ChildItem resources\images\dev_ams_dry_ctr_*, resources\images\hum_level* | Select Name -``` - -Expected: all 17 files listed. - -- [ ] **Step 3: Commit** - -```bash -git add resources/images/dev_ams_dry_ctr_* resources/images/hum_level* -git commit -m "assets: add AMS drying control images from BambuStudio - -14 images: humidity level icons, drying state images per AMS type, -heating icon, guide illustration, tray status icons." -``` - ---- - -### Task 9: `AMSDryControl` UI dialog - -**Files:** -- Create: `src/slic3r/GUI/AMSDryControl.hpp` -- Create: `src/slic3r/GUI/AMSDryControl.cpp` - -**Interfaces:** -- Produces: `AMSDryCtrWin` dialog class extending `DPIDialog` -- Produces: `FilamentItemPanel`, `AMSFilamentPanel` helper widget classes -- Consumes: `DevFilaSystem`, `MachineObject`, `DevAms`, `DevUtilBackend::GetFilamentDryingPreset()` - -**Reference:** `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.hpp` and `AMSDryControl.cpp` - -- [ ] **Step 1: Create `AMSDryControl.hpp`** - -Create `src/slic3r/GUI/AMSDryControl.hpp`. Port the full header from BambuStudio `AMSDryControl.hpp`, adapting includes for OrcaSlicer paths: - -Key adaptations: -- Change `#include "GUI_ObjectLayers.hpp"` to appropriate OrcaSlicer equivalent (check if it exists; if not, it may not be needed or can be replaced with `wx/wx.h`) -- Keep includes for `slic3r/GUI/Widgets/AMSItem.hpp`, `Widgets/Label.hpp`, `Widgets/PopupWindow.hpp`, `wxExtensions.hpp`, `DeviceCore/DevFilaSystem.h` -- Keep the full class declarations for `FilamentItemPanel`, `AMSFilamentPanel`, `AMSDryCtrWin` - -The complete header from `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.hpp` (lines 1–252) should be ported with path adjustments. Due to the file's length (~250 lines), copy the full content from the reference and adapt. - -- [ ] **Step 2: Create `AMSDryControl.cpp`** - -Create `src/slic3r/GUI/AMSDryControl.cpp`. Port from `D:\projects\BambuStudio\src\slic3r\GUI\AMSDryControl.cpp` (lines 1–1860). Key adaptations: - -Replace these BambuStudio includes: -```cpp -#include "AMSDryControl.hpp" -#include "DeviceCore/DevFilaSystem.h" -#include "GUI_App.hpp" -#include "I18N.hpp" -#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h" -#include "slic3r/GUI/DeviceCore/DevUpgrade.h" -#include "slic3r/GUI/DeviceCore/DevManager.h" -#include "slic3r/GUI/MsgDialog.hpp" -#include "slic3r/GUI/Widgets/AnimaController.hpp" -#include "slic3r/GUI/Widgets/Label.hpp" -#include "slic3r/GUI/Widgets/ComboBox.hpp" -#include "slic3r/GUI/Widgets/ProgressBar.hpp" -#include "DeviceCore/DevUtilBackend.h" -``` - -Adapt includes for OrcaSlicer paths. Check which of these already exist: -- `GUI_App.hpp` → existing -- `I18N.hpp` → existing -- `DeviceCore/DevFilaSystem.h` → existing -- `Widgets/Label.hpp`, `Widgets/ComboBox.hpp`, `Widgets/ProgressBar.hpp` → check existence in OrcaSlicer - -Since this file is ~1860 lines, port it in full from the BambuStudio reference, adapting only the include paths and namespace references as needed for OrcaSlicer. The implementation logic should be identical to BambuStudio. - -Key parts to verify during port: -- `AMS_ITEMS_PANEL_SIZE`, `AMS_CONTROL_DEF_BLOCK_BK_COLOUR`, `AMS_CONTROL_BRAND_COLOUR`, `AMS_CONTROL_DISABLE_COLOUR`, `AMS_CONTROL_WHITE_COLOUR` — these constants are defined in `AMSItem.hpp`. Verify they exist in OrcaSlicer's version. -- `_L()` and `_CTX_utf8()` — I18N macros; verify they work the same in OrcaSlicer -- `StateColor` — widget state color class; verify it exists in OrcaSlicer -- `ScalableBitmap` — verify it exists in OrcaSlicer -- `ComboBox` — OrcaSlicer custom combobox; verify path -- `ProgressBar` — OrcaSlicer custom progress bar; verify path -- `FromDIP()` — DPI scaling helper; should exist in OrcaSlicer -- `encode_path()` — path encoding utility; should exist -- `resources_dir()` — resources directory getter; verify it exists -- `bool is_support_user_preset` on `MachineObject` — verify this field exists - -- [ ] **Step 3: Register `AMSDryControl` in CMakeLists** - -In `src/slic3r/CMakeLists.txt`, add after the `AMSSetting` entries (around line 30): - -```cmake - GUI/AMSDryControl.cpp - GUI/AMSDryControl.hpp -``` - -- [ ] **Step 4: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -Fix any compilation errors from missing includes or type mismatches between OrcaSlicer and BambuStudio APIs. - -- [ ] **Step 5: Commit** - -```bash -git add src/slic3r/GUI/AMSDryControl.hpp src/slic3r/GUI/AMSDryControl.cpp -git commit -m "feat: add AMSDryControl dialog for AMS filament drying - -Three-page wizard: main status/control page, guide page with -filament tray status, and progress page. Supports N3F and N3S AMS types." -``` - ---- - -### Task 10: Wire humidity click to open `AMSDryCtrWin` - -**Files:** -- Modify: `src/slic3r/GUI/Widgets/AMSControl.hpp` -- Modify: `src/slic3r/GUI/Widgets/AMSControl.cpp` - -**Interfaces:** -- Consumes: `AMSDryCtrWin` dialog class -- Modifies: `EVT_AMS_SHOW_HUMIDITY_TIPS` handler — for N3F/N3S AMS types, opens `AMSDryCtrWin` instead of the popup - -- [ ] **Step 1: Add member and include to `AMSControl.hpp`** - -In `src/slic3r/GUI/Widgets/AMSControl.hpp`: - -Add forward declaration: -```cpp -class AMSDryCtrWin; -``` - -Add member variable near the existing `m_percent_humidity_dry_popup`: -```cpp - AMSDryCtrWin* m_dry_ctr_win{nullptr}; -``` - -- [ ] **Step 2: Add include to `AMSControl.cpp`** - -```cpp -#include "slic3r/GUI/AMSDryControl.hpp" -``` - -- [ ] **Step 3: Modify the `EVT_AMS_SHOW_HUMIDITY_TIPS` handler** - -In the handler at around line 243, modify the `else` branch (for non-GENERIC_AMS types) to check if the AMS type is N3F/N3S and open the `AMSDryCtrWin` instead of the popup: - -```cpp - Bind(EVT_AMS_SHOW_HUMIDITY_TIPS, [this](wxCommandEvent& evt) { - uiAmsHumidityInfo *info = (uiAmsHumidityInfo *) evt.GetClientData(); - if (info) - { - if (info->ams_type == AMSModel::GENERIC_AMS) - { - wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x - m_Humidity_tip_popup.GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); - m_Humidity_tip_popup.Position(popup_pos, wxSize(0, 0)); - - 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 if (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS) - { - // Open full drying control dialog for N3F/N3S AMS - if (!m_dry_ctr_win) { - m_dry_ctr_win = new AMSDryCtrWin(this); - } - m_dry_ctr_win->set_ams_id(info->ams_id); - // Get fila system and machine object via the parent chain - // The dialog will be updated in parse_object() - m_dry_ctr_win->ShowModal(); - } - else - { - m_percent_humidity_dry_popup->Update(info); - - wxPoint img_pos = ClientToScreen(wxPoint(0, 0)); - wxPoint popup_pos(img_pos.x - m_percent_humidity_dry_popup->GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80)); - m_percent_humidity_dry_popup->Move(popup_pos); - m_percent_humidity_dry_popup->ShowModal(); - } - } - - delete info; - }); -``` - -Note: The `AMSDryCtrWin` needs `DevFilaSystem` and `MachineObject` references for its `update()` method. The dialog's `update()` should be called before `ShowModal()`. The `MachineObject*` can be obtained from the parent widget chain or stored as a member of `AMSControl`. Check how `AMSControl` currently accesses `MachineObject` (likely through `m_obj` or similar). Pass it to the dialog's `update()` call. - -- [ ] **Step 4: Add periodic update for the dialog in `parse_object()`** - -In the `parse_object()` method (around line 954), find the existing humidity popup update block and extend it to also update the dry control dialog: - -```cpp - /*update AMS dry control dialog*/ - if (m_dry_ctr_win && m_dry_ctr_win->IsShown()) - { - // Get the MachineObject and DevFilaSystem from the current device - // m_dry_ctr_win->update(obj->GetFilaSystem_ptr(), obj); - } -``` - -Note: The exact code depends on how `AMSControl` accesses `MachineObject*`. Check existing patterns — it likely has access through `m_obj` or a similar member. The update will need both the `DevFilaSystem` (as `shared_ptr`) and `MachineObject*`. - -- [ ] **Step 5: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 6: Commit** - -```bash -git add src/slic3r/GUI/Widgets/AMSControl.hpp src/slic3r/GUI/Widgets/AMSControl.cpp -git commit -m "feat: wire AMS humidity click to open AMSDryControl dialog - -For N3F and N3S AMS types, clicking the humidity indicator -now opens the full drying control dialog instead of the popup." -``` - ---- - -### Task 11: Update error dialog stop-drying call - -**Files:** -- Modify: `src/slic3r/GUI/DeviceErrorDialog.cpp` - -**Interfaces:** -- Consumes: `DevFilaSystem::CtrlAmsStopDrying(int)` - -- [ ] **Step 1: Update `STOP_DRYING` case in `DeviceErrorDialog.cpp`** - -In `src/slic3r/GUI/DeviceErrorDialog.cpp` around line 452, update the stop drying action: - -```cpp - case DeviceErrorDialog::STOP_DRYING: { - // Use the canonical CtrlAmsStopDrying path - if (m_obj && m_obj->GetFilaSystem()) { - // Get the AMS ID — check how the dialog knows which AMS is involved - // For now, stop all AMS units or use the first one - m_obj->GetFilaSystem()->CtrlAmsStopDrying(0); - } - // Fallback to the old command for backward compatibility - m_obj->command_ams_drying_stop(); - break; - } -``` - -Note: The exact AMS ID to pass depends on the error context. Check how BambuStudio handles this — it may use a specific AMS ID from the error data, or stop all drying. The fallback to `command_ams_drying_stop()` ensures backward compatibility if `CtrlAmsStopDrying` fails or the fila system isn't available. - -- [ ] **Step 2: Verify build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -- [ ] **Step 3: Commit** - -```bash -git add src/slic3r/GUI/DeviceErrorDialog.cpp -git commit -m "feat: update error dialog stop-drying to use CtrlAmsStopDrying - -Keeps command_ams_drying_stop() fallback for backward compatibility." -``` - ---- - -### Task 12: Build, verify, and final integration test - -**Files:** All modified files - -- [ ] **Step 1: Full clean build** - -```powershell -cmake --build . --config RelWithDebInfo --target ALL_BUILD -- -m -``` - -Expected: Zero errors, zero warnings related to the new code. - -- [ ] **Step 2: Verify no regressions in existing AMS features** - -- Confirm the app launches -- Confirm AMS panel renders correctly for printers without N3F/N3S -- Confirm humidity popup still works for standard AMS and AMS Lite -- Confirm existing `command_ams_drying_stop()` still functions - -- [ ] **Step 3: Manual UI smoke test (requires N3F/N3S printer)** - -If a printer with N3F or N3S AMS is available: -1. Connect to the printer -2. Click AMS humidity indicator → verify `AMSDryCtrWin` opens -3. Verify humidity/temperature readings match printer data -4. Verify filament combobox is populated -5. Verify temp/time auto-fill when selecting a filament -6. Verify validation warnings for invalid temperatures -7. Verify the dialog closes cleanly - -- [ ] **Step 4: Commit any final fixes** - -```bash -git add -A -git commit -m "fix: final integration fixes for AMS drying control" -``` diff --git a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md b/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md deleted file mode 100644 index cecbf7852f..0000000000 --- a/docs/superpowers/specs/2026-07-07-ams-drying-control-design.md +++ /dev/null @@ -1,325 +0,0 @@ -# AMS Drying Control — Design Spec - -**Date:** 2026-07-07 -**Source:** Port from BambuStudio `AMSDryControl` feature -**Reference:** `D:\projects\BambuStudio` — match its behavior as much as possible; when in doubt, check the BambuStudio source -**Branch:** `dev/ams-heat` - -## Overview - -Port the AMS filament drying control feature from BambuStudio into OrcaSlicer. This allows users to start, monitor, and stop AMS-based filament drying directly from the slicer UI. Currently OrcaSlicer can monitor drying state and stop drying, but cannot initiate it. This feature adds the missing start-drying command, the full drying control dialog, and the drying preset lookup infrastructure. - -**Target AMS models:** N3F (AMS 2 Pro, max 65°C) and N3S (AMS HT, max 85°C) — the only AMS units with heating hardware. - -## Architecture - -The feature spans three layers, matching the existing OrcaSlicer `DeviceCore/` pattern: - -``` -┌─────────────────────────────────────────────────────┐ -│ UI Layer │ -│ AMSDryControl.hpp/.cpp (new dialog) │ -│ AMSControl.cpp (hook: click → dialog) │ -│ DeviceErrorDialog.cpp (stop drying on error) │ -├─────────────────────────────────────────────────────┤ -│ Command/Control Layer │ -│ DevFilaSystemCtrl.cpp (start/stop drying) │ -│ DevUtilBackend.h/.cpp (preset lookup) │ -├─────────────────────────────────────────────────────┤ -│ Data Model Layer │ -│ DevFilaSystem.h/.cpp (enums, structs, parse) │ -│ DevDefs.h (DevAmsType enum) │ -└─────────────────────────────────────────────────────┘ -│ Communication Layer (already exists) │ -│ MachineObject::publish_json() → MQTT → printer │ -└─────────────────────────────────────────────────────┘ -``` - -### New files (4 source + headers) - -| File | Purpose | -|------|---------| -| `src/slic3r/GUI/AMSDryControl.hpp` | AMS drying control dialog class declarations | -| `src/slic3r/GUI/AMSDryControl.cpp` | Dialog implementation (~1800 lines) | -| `src/slic3r/GUI/DeviceCore/DevFilaSystemCtrl.cpp` | `CtrlAmsStartDryingHour()` and `CtrlAmsStopDrying()` | -| `src/slic3r/GUI/DeviceCore/DevUtilBackend.h` | Static utility class declaring `GetFilamentDryingPreset()` | -| `src/slic3r/GUI/DeviceCore/DevUtilBackend.cpp` | Reads filament drying presets from printer config | - -### Modified files - -| File | Changes | -|------|---------| -| `DevFilaSystem.h` | Add drying enums/structs to `DevAms`; add `DevFilamentDryingPreset` struct; add ctrl method declarations to `DevFilaSystem`; add `get_ams_drying_preset()` to `DevAmsTray` | -| `DevFilaSystem.cpp` | Parse dry status fields in `DevFilaSystemParser`; implement `IsSupportRemoteDry()`, `AmsIsDrying()`, `get_ams_drying_preset()` | -| `DevDefs.h` | Add `DevAmsType` as a global enum | -| `AMSControl.cpp` | Wire humidity indicator click to open `AMSDryCtrWin` for N3F/N3S AMS | -| `DeviceErrorDialog.cpp` | Update stop-drying to use `DevFilaSystem::CtrlAmsStopDrying()` | -| `DeviceCore/CMakeLists.txt` | Register new source files | - -### New image assets (14) - -| Asset | Purpose | -|-------|---------| -| `hum_level1_no_num_light.svg` – `hum_level5_no_num_light.svg` | 5 humidity level icons | -| `dev_ams_dry_ctr_n3f_heating.png`, `_dehumidifying.png`, `_error.png`, `_cooling.png` | 4 N3F drying state images | -| `dev_ams_dry_ctr_n3s_heating.png`, `_dehumidifying.png`, `_error.png`, `_cooling.png` | 4 N3S drying state images | -| `dev_ams_dry_ctr_heating_icon.svg` | Animated heating indicator | -| `dev_ams_dry_ctr_filament_in_chamber.png` | Guide page illustration | -| `dev_ams_dry_ctr_enable.svg`, `dev_ams_dry_ctr_disable.svg` | Filament tray status icons | - -Additionally, OrcaSlicer already has `ams_drying.svg` and `ams_is_drying.svg`. - -## Data Model - -### `DevDefs.h` — Global `DevAmsType` enum - -Promoted from `DevAms::AmsType` (currently local to the class) to a global enum in `DevDefs.h` so `DevFilamentDryingPreset` and `DevUtilBackend` can reference it without depending on `DevAms`. `DevAms::AmsType` is updated to be a typedef for `DevAmsType`, and all existing references to `DevAms::AmsType` remain valid (it's the same type): - -```cpp -// DevDefs.h — global enum matching BambuStudio's DevAmsType naming -enum DevAmsType : int { - EXT_SPOOL = 0, - AMS = 1, - AMS_LITE = 2, - N3F = 3, // AMS 2 Pro - N3S = 4, // AMS HT -}; - -// DevFilaSystem.h — DevAms class updated: -// Replace "enum AmsType { DUMMY=0, AMS=1, AMS_LITE=2, N3F=3, N3S=4 }" -// with "using AmsType = DevAmsType;" -// Existing references to DevAms::DUMMY become DevAms::EXT_SPOOL (same value, different name). -``` - -### `DevAms` class additions (in `DevFilaSystem.h`) - -**New enums:** - -| Enum | Values | -|------|--------| -| `DryCtrlMode` | `Off=0, OnTime=1, OnHumidity=2` | -| `DryStatus` | `Off=0, Checking=1, Drying=2, Cooling=3, Stopping=4, Error=5, CannotStopHeatOutofControl=6, PrdTesting=7` | -| `DrySubStatus` | `Off=0, Heating=1, Dehumidify=2` | -| `DryFanStatus` | `Off=0, On=1` | -| `CannotDryReason` | `TaskOccupied=0, InsufficientPower=1, AmsBusy=2, ConsumableAtAmsOutlet=3, InitiatingAmsDrying=4, NotSupportedIn2dMode=5, DryingInProgress=6, Upgrading=7, InsufficientPowerNeedPluginPower=8, FilamentAtAmsOutletManualUnload=10` | - -**New struct:** - -```cpp -struct DrySettings { - std::string dry_filament; - int dry_temp = -1; // -1 means invalid - int dry_hour = -1; // hours -}; -``` - -**New getters on `DevAms`:** - -- `std::optional GetDryStatus() const` -- `std::optional GetDrySubStatus() const` -- `std::optional GetFan1Status() const` -- `std::optional GetFan2Status() const` -- `std::optional> GetCannotDryReason() const` -- `std::optional GetDrySettings() const` -- `bool IsSupportRemoteDry(const MachineObject* obj) const` -- `bool AmsIsDrying()` - -**New private members:** `m_dry_status`, `m_dry_sub_status`, `m_dry_fan1_status`, `m_dry_fan2_status`, `m_dry_cannot_reasons`, `m_dry_settings` — all `std::optional<>`. - -### `DevFilamentDryingPreset` struct (namespace scope in `DevFilaSystem.h`) - -```cpp -struct DevFilamentDryingPreset { - std::string filament_id; - std::unordered_set ams_limitations; - std::unordered_map filament_dev_ams_drying_time_on_idle; // hours - std::unordered_map filament_dev_ams_drying_temperature_on_idle; - std::unordered_map filament_dev_ams_drying_time_on_print; // hours - std::unordered_map filament_dev_ams_drying_temperature_on_print; - float filament_dev_drying_cooling_temperature; - float filament_dev_drying_softening_temperature; - float filament_dev_ams_drying_heat_distortion_temperature; -}; -``` - -Populated from filament preset config keys (`filament_dev_ams_drying_temperature`, `filament_dev_ams_drying_time`, `filament_dev_drying_softening_temperature`, etc.). - -### `DevAmsTray` addition - -```cpp -std::optional get_ams_drying_preset() const; -``` - -Delegates to `DevUtilBackend::GetFilamentDryingPreset(setting_id)`. - -### JSON parsing - -`DevFilaSystemParser::ParseV1_0()` extended to parse the following fields from the printer's AMS status JSON: - -| JSON field | DevAms member | -|------------|---------------| -| `dry_status` | `m_dry_status` (`DryStatus` enum) | -| `dry_sub_status` | `m_dry_sub_status` (`DrySubStatus` enum) | -| `dry_fan1_status` | `m_dry_fan1_status` | -| `dry_fan2_status` | `m_dry_fan2_status` | -| `dry_cannot_reasons` | `m_dry_cannot_reasons` (vector of `CannotDryReason`) | -| `dry_settings` | `m_dry_settings` (`DrySettings` struct) | - -## Commands - -### `DevFilaSystem::CtrlAmsStartDryingHour()` - -Publishes JSON command `"ams_filament_drying"` via `MachineObject::publish_json()`: - -```json -{ - "print": { - "command": "ams_filament_drying", - "sequence_id": "", - "ams_id": , - "mode": 1, - "filament": "", - "temp": , - "duration": , - "humidity": 0, - "rotate_tray": , - "cooling_temp": , - "close_power_conflict": false - } -} -``` - -### `DevFilaSystem::CtrlAmsStopDrying()` - -Same command with `mode: 0` (Off). - -### Existing `MachineObject::command_ams_drying_stop()` - -Kept for backward compatibility. The error dialog will be updated to call `CtrlAmsStopDrying()` instead, which is the preferred path. - -## Backend Utility - -### `DevUtilBackend` (new, `DeviceCore/DevUtilBackend.h/.cpp`) - -Static utility class. Only method needed for this feature: - -```cpp -static std::optional GetFilamentDryingPreset(const std::string& fila_id); -``` - -Iterates `wxGetApp().preset_bundle->filaments` to find the matching filament_id, then reads config keys into a `DevFilamentDryingPreset`. Uses a static map `{"0" → N3F, "1" → N3S}` for the `ams_limitations` string-to-enum conversion. - -## UI Dialog - -### `AMSDryCtrWin` (extends `DPIDialog`) - -Three pages in a `wxSimplebook`: - -#### Page 0: Main Page - -Split left/right layout: - -**Left panel — Status display:** -- Large humidity/drying state image: humidity level icon when idle; heating/dehumidifying/error animation when active -- Status label with animated heating icon ("Idle", "Drying-Heating", "Drying-Dehumidifying") -- Three stat labels: Humidity (%), Temperature (°C), Left Time (HH:MM). Left Time hidden when idle. - -**Right panel — Controls.** Three sub-panels shown/hidden based on `DryStatus` and `CannotDryReason`: - -| Sub-panel | When shown | Contents | -|-----------|------------|----------| -| Normal state | `DryStatus` is Off or Cooling | Filament type combobox → Temperature input (numeric, validated to AMS limits) → Time input (hours, 1–24) → Validation warning text → **Start** button | -| Cannot dry | `CannotDryReason` is non-empty (excluding only `DryingInProgress`) | Formatted reason text + **Unload** button (only for `ConsumableAtAmsOutlet` reason) | -| Drying error | `DryStatus` is Error | Error message + **Stop** button | -| Drying active | `DryStatus` is Checking/Drying/Stopping | Read-only temp/time display + **Stop** button | - -**Temperature validation rules:** -- Hardware limits: N3F 45–65°C, N3S 45–85°C -- Heat distortion check: temp must not exceed `filament_dev_ams_drying_heat_distortion_temperature` when filament is present -- Printing mode: temp must not exceed recommended drying temp when this AMS is actively feeding a print -- Time: 1–24 hours - -#### Page 1: Guide Page - -Shown after clicking Start on Page 0, before sending the command: -- Instructional text about removing heat-sensitive filament -- `AMSFilamentPanel` showing each tray's filament type with ✅/⚠ icons based on whether drying temp exceeds that filament's softening point -- "Rotate spool when drying" checkbox -- **Back** and **Start** buttons - -#### Page 2: Progress Page - -Shown while waiting for printer to confirm drying has started: -- Animated progress bar (cycles 0–99% until printer state changes) -- Cycling status messages -- Auto-transitions back to Page 0 when printer reports drying active - -### Helper classes (in `AMSDryControl.hpp`) - -- **`FilamentItemPanel`** — Renders a single filament item with icon and text, with custom rounded-rectangle border painting -- **`AMSFilamentPanel`** — Container for multiple `FilamentItemPanel` instances, labeled with AMS name -- **`DryingPreset` struct, `DryCtrState` enum, `DryCtrDev` enum** — Local types for tracking preset state - -### Dialog lifecycle - -- Created on first click of the AMS humidity indicator -- Updated on each `AMSControl::parse_object()` cycle via `update(fila_system, obj)` -- Auto-closes if: AMS is removed from the system, AMS no longer supports remote drying, or AMS ID becomes invalid -- Closed manually via close button or dialog destruction -- On close: stops progress timer, resets to main page, restores button states - -## Integration - -### Entry point: AMS humidity click → dialog - -In `AMSControl.cpp`, the `EVT_AMS_SHOW_HUMIDITY_TIPS` handler currently shows either `AmsHumidityTipPopup` or `uiAmsPercentHumidityDryPopup`. For N3F and N3S AMS types only, replace this with opening `AMSDryCtrWin`: - -1. Lazily create `AMSDryCtrWin*` member on `AMSControl` (like `m_percent_humidity_dry_popup` today) -2. Call `set_ams_id()` and `update(fila_system, obj)` before showing -3. Show the dialog modally via `ShowModal()` (matching BambuStudio behavior) - -### Periodic updates - -`AMSControl::parse_object()` updates AMS state on a timer. Extend it to: -1. If `m_dry_ctr_win` is shown, call `update()` to refresh readings -2. Update the dialog's AMS ID if the user switches AMS view - -### Error dialog - -`DeviceErrorDialog.cpp` line 452 calls `m_obj->command_ams_drying_stop()`. Update to use `obj->GetFilaSystem()->CtrlAmsStopDrying(ams_id)` for the correct AMS ID. - -### CMakeLists - -- `src/slic3r/GUI/DeviceCore/CMakeLists.txt`: add `DevFilaSystemCtrl.cpp`, `DevUtilBackend.h`, `DevUtilBackend.cpp` -- GUI sources list: add `AMSDryControl.hpp`, `AMSDryControl.cpp` - -## Testing - -### Manual verification - -1. **Prerequisite:** Connect to a printer with N3F or N3S AMS hardware -2. Click AMS humidity indicator → verify dialog opens with correct humidity/temperature readings -3. Select a filament from the combobox → verify temp/time auto-fill from preset -4. Enter valid temp/time → verify Start button enables -5. Enter invalid temp (e.g., 100°C for N3F) → verify warning appears and button disables -6. Click Start → verify guide page shows filament tray status -7. Click Start on guide page → verify progress page appears, command is sent -8. Verify printer begins drying → dialog shows active drying state with countdown -9. Click Stop → verify drying stops -10. Test "cannot dry" states (e.g., during print, filament at outlet) - -### Code-level checks - -- Verify `CtrlAmsStartDryingHour` publishes correct JSON structure -- Verify `CtrlAmsStopDrying` publishes stop command -- Verify `GetFilamentDryingPreset` returns correct values for known filament IDs -- Verify dark mode rendering of all dialog pages - -## Constraints - -- **N3F/N3S only:** Standard AMS and AMS Lite do not have heating hardware; the dialog is not shown for them -- **Backward compatibility:** Existing `command_ams_drying_stop()` is preserved; new commands are additive -- **Cross-platform:** wxWidgets UI must work on Windows, macOS, Linux -- **Dark mode:** Dialog must support dark mode via `wxGetApp().dark_mode()` and `StateColor::darkModeColorFor()` -- **Profile compatibility:** Existing profiles with `filament_dev_ams_drying_*` keys (Qidi) continue to work; the feature reads the same keys -- **No printer-agent changes needed:** All commands go through existing `publish_json()` → `NetworkAgent` path, which already handles MQTT for connected printers From 0e20f607122144ce18175655ea99ec5cf331f82c Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 15:25:32 +0800 Subject: [PATCH 020/130] fix: adapt SVG colors to OrcaSlicer palette MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dev_ams_dry_ctr_enable.svg: Bambu green #00AE42 → Orca teal #009688 - dev_ams_dry_ctr_heating_icon.svg: red #E14747 → amber #F09A17 (matches ams_is_drying.svg) --- resources/images/dev_ams_dry_ctr_enable.svg | 2 +- resources/images/dev_ams_dry_ctr_heating_icon.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/images/dev_ams_dry_ctr_enable.svg b/resources/images/dev_ams_dry_ctr_enable.svg index 0c8d4ca146..31eb482d17 100644 --- a/resources/images/dev_ams_dry_ctr_enable.svg +++ b/resources/images/dev_ams_dry_ctr_enable.svg @@ -1,4 +1,4 @@ - + diff --git a/resources/images/dev_ams_dry_ctr_heating_icon.svg b/resources/images/dev_ams_dry_ctr_heating_icon.svg index 9084670fb7..614b0c9a92 100644 --- a/resources/images/dev_ams_dry_ctr_heating_icon.svg +++ b/resources/images/dev_ams_dry_ctr_heating_icon.svg @@ -1,3 +1,3 @@ - + From f713c7ae4937d9f85f6d5d8fbf05e07b257f56c1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 16:34:35 +0800 Subject: [PATCH 021/130] Make sure codes uses same structure/naming/position as BambuStudio for easier code comparasion & porting in the future --- src/libslic3r/Preset.cpp | 20 ++++++ src/libslic3r/Preset.hpp | 3 + src/slic3r/GUI/AMSDryControl.cpp | 2 +- src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp | 69 +++++++++--------- src/slic3r/GUI/DeviceCore/DevFilaSystem.h | 7 +- src/slic3r/GUI/DeviceManager.hpp | 2 +- src/slic3r/GUI/StatusPanel.cpp | 1 + src/slic3r/GUI/Widgets/AMSControl.cpp | 80 +++++++++++---------- src/slic3r/GUI/Widgets/AMSControl.hpp | 5 +- 9 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 98a5a4fcb6..6d08ca9f2d 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -3781,6 +3781,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(preset.config.option("compatible_printers")); diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index bbbdc6c5ff..cd3c244fd9 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -803,6 +803,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: diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index 7e727abbdf..98b35b5809 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -1615,7 +1615,7 @@ int AMSDryCtrWin::update_filament_list(DevAms* dev_ams, MachineObject* obj) } filament_id_set.insert(filament_it->filament_id); - auto filament_alias = filament_it->alias; + auto filament_alias = filaments.get_preset_alias(*filament_it, true); if (!filament_alias.empty()) { auto opt_info = preset_bundle->get_filament_by_filament_id(filament_it->filament_id); if (opt_info.has_value()) { diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp index a2787577fd..c54b8b8964 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.cpp @@ -99,8 +99,7 @@ std::string DevAmsTray::get_filament_type() return m_fila_type; } - -std::optional DevAmsTray::get_ams_drying_preset() const +std::optional DevAmsTray::get_ams_drying_preset() const { return DevUtilBackend::GetFilamentDryingPreset(setting_id); } @@ -454,32 +453,17 @@ 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(); - } - - // 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(); - 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); + std::string temp = (*it)["temp"].get(); + try + { + curr_ams->m_current_temperature = DevUtil::string_to_float(temp); } - - 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>((*it), "dry_sf_reason"); + catch (...) + { + curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE; } } @@ -509,17 +493,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(); - try - { - curr_ams->m_current_temperature = DevUtil::string_to_float(temp); + curr_ams->m_left_dry_time = (*it)["dry_time"].get(); + } + + // 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(); + 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>((*it), "dry_sf_reason"); } } diff --git a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h index 283de146db..23f8d23b50 100644 --- a/src/slic3r/GUI/DeviceCore/DevFilaSystem.h +++ b/src/slic3r/GUI/DeviceCore/DevFilaSystem.h @@ -104,10 +104,11 @@ public: std::string get_display_filament_type() const; std::string get_filament_type(); - std::optional get_ams_drying_preset() const; // static static wxColour decode_color(const std::string& color); + + std::optional get_ams_drying_preset() const; }; /** @@ -228,7 +229,7 @@ public: int GetHumidityLevel() const { return m_humidity_level; } int GetHumidityPercent() const { return m_humidity_percent; } - 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 @@ -333,6 +334,8 @@ 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; diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 6e4007a62b..a0d8f97ea6 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -254,7 +254,6 @@ public: bool is_tunnel_mqtt = false; //AmsTray vt_tray; // virtual tray - bool is_support_remote_dry = false; long ams_exist_bits = 0; long tray_exist_bits = 0; long tray_is_bbl_bits = 0; @@ -621,6 +620,7 @@ public: // fun2 bool is_support_print_with_emmc{false}; + bool is_support_remote_dry = false; bool installed_upgrade_kit{false}; int bed_temperature_limit = -1; diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 5cbf3e2a83..6b1cb8ebd2 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3334,6 +3334,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; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index ea62d18d92..24e35cda12 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -6,7 +6,6 @@ #include "slic3r/GUI/MsgDialog.hpp" #include "slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h" -#include "slic3r/GUI/AMSDryControl.hpp" #include "slic3r/GUI/DeviceCore/DevManager.h" #include "slic3r/GUI/DeviceCore/DevFilaSystem.h" @@ -30,6 +29,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) { @@ -245,6 +245,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)); @@ -254,27 +260,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 if (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS) - { - // Open full drying control dialog for N3F/N3S AMS - if (!m_dry_ctr_win) { - m_dry_ctr_win = new AMSDryCtrWin(this); - } - m_dry_ctr_win->set_ams_id(info->ams_id); + } 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); - Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (dev) { - MachineObject *obj = dev->get_selected_machine(); - if (obj && obj->GetFilaSystem()) { - std::shared_ptr fila_ptr(obj->GetFilaSystem(), [](DevFilaSystem*){}); - m_dry_ctr_win->update(fila_ptr, obj); - } - } - m_dry_ctr_win->ShowModal(); - } - else - { + 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)); @@ -294,7 +287,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; @@ -512,8 +510,8 @@ void AMSControl::msw_rescale() m_percent_humidity_dry_popup->msw_rescale(); } - if (m_dry_ctr_win){ - m_dry_ctr_win->msw_rescale(); + if (m_ams_dry_ctr_win) { + m_ams_dry_ctr_win->msw_rescale(); } m_Humidity_tip_popup.msw_rescale(); @@ -839,6 +837,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 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 AMSControl::GenerateSimulateData() { auto caninfo0_0 = Caninfo{ "0", (""), *wxRED, AMSCanType::AMS_CAN_TYPE_VIRTUAL }; auto caninfo0_1 = Caninfo{ "1", (""), *wxGREEN, AMSCanType::AMS_CAN_TYPE_VIRTUAL }; @@ -993,19 +1012,6 @@ void AMSControl::UpdateAms(const std::string &series_name, } } - /*update AMS dry control dialog*/ - if (m_dry_ctr_win && m_dry_ctr_win->IsShown()) - { - Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager(); - if (dev) { - MachineObject *obj = dev->get_selected_machine(); - if (obj && obj->GetFilaSystem()) { - std::shared_ptr fila_ptr(obj->GetFilaSystem(), [](DevFilaSystem*){}); - m_dry_ctr_win->update(fila_ptr, obj); - } - } - } - /*update ams extruder*/ if (m_extruder->updateNozzleNum(m_total_ext_count, series_name)) { diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 93d9acee67..ff727fd77c 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -15,13 +15,13 @@ #include #include "slic3r/GUI/DeviceCore/DevExtruderSystem.h" +#include "slic3r/GUI/AMSDryControl.hpp" namespace Slic3r { namespace GUI { //Previous definitions class uiAmsPercentHumidityDryPopup; -class AMSDryCtrWin; class AMSControl : public wxSimplebook { @@ -119,7 +119,7 @@ protected: AmsHumidityTipPopup m_Humidity_tip_popup; uiAmsPercentHumidityDryPopup* m_percent_humidity_dry_popup; - AMSDryCtrWin* m_dry_ctr_win{nullptr}; + AMSDryCtrWin* m_ams_dry_ctr_win; std::string m_last_ams_id = ""; std::string m_last_tray_id = ""; @@ -158,6 +158,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 ams_info, From 922af972c70c534d630e01d9f9958dd5995f6e8e Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 17:29:10 +0800 Subject: [PATCH 022/130] refactor: convert m_fila_system from raw pointer to shared_ptr Matches BambuStudio commit c8f70c6ca. DevFilaSystem* m_fila_system becomes std::shared_ptr, enabling proper shared ownership for the AMS drying control feature without no-op deleter hacks. - DeviceManager.hpp: m_fila_system and GetFilaSystem() use shared_ptr - DeviceManager.cpp: std::make_shared allocation, remove manual delete, add .get() to ParseV1_0 calls - MoonrakerPrinterAgent.cpp: add .get() to GetFilaSystem() in ParseV1_0 --- src/slic3r/GUI/DeviceManager.cpp | 6 ++---- src/slic3r/GUI/DeviceManager.hpp | 4 ++-- src/slic3r/Utils/MoonrakerPrinterAgent.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/DeviceManager.cpp b/src/slic3r/GUI/DeviceManager.cpp index 2562d73b22..f8d7c970b2 100644 --- a/src/slic3r/GUI/DeviceManager.cpp +++ b/src/slic3r/GUI/DeviceManager.cpp @@ -566,7 +566,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(this); m_hms_system = new DevHMS(this); m_config = new DevConfig(this); @@ -612,8 +612,6 @@ MachineObject::~MachineObject() delete m_ctrl; m_ctrl = nullptr; - delete m_fila_system; - m_fila_system = nullptr; delete m_hms_system; m_hms_system = nullptr; @@ -3723,7 +3721,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*/ diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index a0d8f97ea6..fae8d60415 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -114,7 +114,7 @@ private: std::shared_ptr m_extension_tool; DevExtderSystem* m_extder_system; DevNozzleSystem* m_nozzle_system; - DevFilaSystem* m_fila_system; + std::shared_ptr m_fila_system; DevFan* m_fan; DevBed * m_bed; DevStorage* m_storage; @@ -329,7 +329,7 @@ public: DevNozzleSystem* GetNozzleSystem() const { return m_nozzle_system;} - DevFilaSystem* GetFilaSystem() const { return m_fila_system;} + std::shared_ptr GetFilaSystem() const { return m_fila_system;} bool HasAms() const; DevLamp* GetLamp() const { return m_lamp; } diff --git a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp index f1d892134b..b0ea653dd3 100644 --- a/src/slic3r/Utils/MoonrakerPrinterAgent.cpp +++ b/src/slic3r/Utils/MoonrakerPrinterAgent.cpp @@ -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. From f58a1f350a077715e3590db1cecd7d95ff4b1c4d Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 17:45:08 +0800 Subject: [PATCH 023/130] feat: add drying-while-printing warning in SelectMachine dialog Port from BambuStudio commit c8f70c6ca. Shows a warning when AMS is actively drying during print job preparation, alerting users that the drying temperature will be lowered during printing. --- src/slic3r/GUI/SelectMachine.cpp | 29 +++++++++++++++++++++++++++++ src/slic3r/GUI/SelectMachine.hpp | 6 ++++++ 2 files changed, 35 insertions(+) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 09314d3b49..3330f527ca 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -506,6 +506,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); @@ -716,6 +724,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)); @@ -1443,6 +1453,18 @@ int SelectMachineDialog::convert_filament_map_nozzle_id_to_task_nozzle_id(int no } } +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; +} + void SelectMachineDialog::prepare(int print_plate_idx) { m_print_plate_idx = print_plate_idx; @@ -3285,6 +3307,12 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_) m_check_ext_change_assist->Enable(false); } + if (is_ams_drying(obj_)) { + m_warn_when_drying_sizer->Show(true); + } else { + m_warn_when_drying_sizer->Show(false); + } + /*reading done*/ if (wxGetApp().app_config) { if (obj_->upgrade_force_upgrade) { @@ -3774,6 +3802,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(); diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index ab88240ec0..c6c8ed458b 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -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 }; @@ -511,6 +515,8 @@ public: bool is_nozzle_type_match(DevExtderSystem data, wxString& error_message) const; int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const; + bool is_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; } From 1b93f35565a33e86830f81c47dedf540013b0761 Mon Sep 17 00:00:00 2001 From: "changyu.chen" Date: Wed, 14 Jan 2026 10:17:23 +0800 Subject: [PATCH 024/130] FIX: print warning when ams drying jira: [STUDIO-16505] Change-Id: I47b98643a7d941c594eb4d90c08f48a7880c947e (cherry picked from commit bdc833d49440c73a56cf10b723fb02d33d1c3a98) --- src/slic3r/GUI/SelectMachine.cpp | 31 ++++++++++++++++++++++++++++++- src/slic3r/GUI/SelectMachine.hpp | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 3330f527ca..5efbe7a620 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -1465,6 +1465,35 @@ bool SelectMachineDialog::is_ams_drying(MachineObject* obj) 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; @@ -3307,7 +3336,7 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_) m_check_ext_change_assist->Enable(false); } - if (is_ams_drying(obj_)) { + if (is_selected_ams_drying(obj_)) { m_warn_when_drying_sizer->Show(true); } else { m_warn_when_drying_sizer->Show(false); diff --git a/src/slic3r/GUI/SelectMachine.hpp b/src/slic3r/GUI/SelectMachine.hpp index c6c8ed458b..deb40237ab 100644 --- a/src/slic3r/GUI/SelectMachine.hpp +++ b/src/slic3r/GUI/SelectMachine.hpp @@ -516,6 +516,7 @@ public: int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const; 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); From c2f5a87e243aa433d3b9d143d50dead1644f93d4 Mon Sep 17 00:00:00 2001 From: "changyu.chen" Date: Fri, 16 Jan 2026 18:43:59 +0800 Subject: [PATCH 025/130] FIX: print warning when ams is drying jira: [STUDIO-16558] Change-Id: I6313c4c02dce6853d48fd4b175a161bf116865a9 (cherry picked from commit 49609394cd92b7043f4f65debf585cbc37f382bd) --- src/slic3r/GUI/SelectMachine.cpp | 54 +++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 5efbe7a620..d5ea29046b 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -3336,10 +3336,14 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_) m_check_ext_change_assist->Enable(false); } - if (is_selected_ams_drying(obj_)) { - m_warn_when_drying_sizer->Show(true); - } else { - m_warn_when_drying_sizer->Show(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*/ @@ -3941,6 +3945,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); @@ -3970,7 +3978,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;} @@ -4049,6 +4070,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(); @@ -4459,6 +4485,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]; @@ -4481,6 +4511,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;} @@ -4557,6 +4598,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 From ae5d9c26fb47963947a6679d6e262359ccead46e Mon Sep 17 00:00:00 2001 From: "weizhen.xie" Date: Mon, 24 Nov 2025 11:36:49 +0800 Subject: [PATCH 026/130] ENH: Add filament ams/chamber parameters Jira: None Change-Id: I4c0a2d5b7e1c503fc9af9eb656fc6325e99af1de (cherry picked from commit ce88e7794cb8786fae85603617757628a963e807) --- src/libslic3r/Preset.cpp | 6 +++++- src/libslic3r/PrintConfig.cpp | 24 ++++++++++++++++++++++++ src/libslic3r/PrintConfig.hpp | 9 +++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 6d08ca9f2d..dbdd48a0df 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1348,7 +1348,11 @@ static std::vector s_Preset_filament_options {/*"filament_colour", "filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature", //BBS filament change length while the extruder color "filament_change_length","filament_flush_volumetric_speed","filament_flush_temp", "filament_cooling_before_tower", - "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 s_Preset_machine_limits_options { diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index dda24e4e5b..c053b3f8fa 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7307,6 +7307,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_"; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3b8b809c78..2948f24417 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1490,6 +1490,15 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionStrings, small_area_infill_flow_compensation_model)) ((ConfigOptionBool, has_scarf_joint_seam)) + //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. From 4227a192cd35e4e18db2ea3e590d1dab625b9d17 Mon Sep 17 00:00:00 2001 From: shsst Date: Wed, 10 Dec 2025 21:07:39 +0800 Subject: [PATCH 027/130] ENH:[Process/Filament] MOD: filament_ams parameters Profile Edited by lianhu.xiong Change-Id: I2f540d0afd6ba368100bc88433cdf2024a1c7d3c (cherry picked from commit 316d8461476d65a85de8dba41a861877c358dba5) --- .../BBL/filament/Bambu ASA-Aero @base.json | 4 +-- .../BBL/filament/Bambu ASA-CF @base.json | 3 ++ .../BBL/filament/Bambu PAHT-CF @base.json | 3 ++ .../BBL/filament/Bambu PET-CF @base.json | 21 +++++++++++++ .../Bambu Support For PA PET @base.json | 18 +++++++++++ .../filament/Bambu Support For PLA @base.json | 15 +++++++-- .../Bambu Support For PLA-PETG @base.json | 18 +++++++++-- .../BBL/filament/Bambu Support G @base.json | 21 +++++++++++-- .../filament/Bambu Support for ABS @base.json | 9 ++++-- .../BBL/filament/Generic PA @base.json | 15 +++++++++ .../BBL/filament/Generic PCTG @base.json | 28 +++++++++++++++++ .../BBL/filament/Generic PPS @base.json | 23 +++++++++++++- .../Polymaker/Fiberon PET-CF @base.json | 27 ++++++++++++++-- .../BBL/filament/fdm_filament_abs.json | 21 +++++++++++++ .../BBL/filament/fdm_filament_asa.json | 21 +++++++++++++ .../BBL/filament/fdm_filament_bvoh.json | 28 +++++++++++++++++ .../BBL/filament/fdm_filament_eva.json | 28 +++++++++++++++++ .../BBL/filament/fdm_filament_hips.json | 24 ++++++++++++-- .../BBL/filament/fdm_filament_pa.json | 24 ++++++++++++++ .../BBL/filament/fdm_filament_pc.json | 21 +++++++++++++ .../BBL/filament/fdm_filament_pctg.json | 31 +++++++++++++++++++ .../BBL/filament/fdm_filament_pe.json | 25 +++++++++++++++ .../BBL/filament/fdm_filament_pet.json | 28 +++++++++++++++++ .../BBL/filament/fdm_filament_pha.json | 25 +++++++++++++++ .../BBL/filament/fdm_filament_pla.json | 31 +++++++++++++++++-- .../BBL/filament/fdm_filament_pp.json | 28 +++++++++++++++++ .../BBL/filament/fdm_filament_ppa.json | 28 +++++++++++++++++ .../BBL/filament/fdm_filament_pps.json | 25 +++++++++++++++ .../BBL/filament/fdm_filament_pva.json | 21 +++++++++++++ .../BBL/filament/fdm_filament_tpu.json | 24 ++++++++++++++ 30 files changed, 614 insertions(+), 24 deletions(-) diff --git a/resources/profiles/BBL/filament/Bambu ASA-Aero @base.json b/resources/profiles/BBL/filament/Bambu ASA-Aero @base.json index 2dcf633a26..1a36118d7f 100644 --- a/resources/profiles/BBL/filament/Bambu ASA-Aero @base.json +++ b/resources/profiles/BBL/filament/Bambu ASA-Aero @base.json @@ -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" diff --git a/resources/profiles/BBL/filament/Bambu ASA-CF @base.json b/resources/profiles/BBL/filament/Bambu ASA-CF @base.json index 9c425dba90..69624032bb 100644 --- a/resources/profiles/BBL/filament/Bambu ASA-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu ASA-CF @base.json @@ -32,6 +32,9 @@ "filament_vendor": [ "Bambu Lab" ], + "filament_dev_drying_cooling_temperature": [ + "95" + ], "hot_plate_temp": [ "100" ], diff --git a/resources/profiles/BBL/filament/Bambu PAHT-CF @base.json b/resources/profiles/BBL/filament/Bambu PAHT-CF @base.json index 54122f3bbf..28b1391f84 100644 --- a/resources/profiles/BBL/filament/Bambu PAHT-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu PAHT-CF @base.json @@ -33,6 +33,9 @@ "full_fan_speed_layer": [ "2" ], + "filament_dev_chamber_drying_time": [ + "16" + ], "impact_strength_z": [ "13.3" ], diff --git a/resources/profiles/BBL/filament/Bambu PET-CF @base.json b/resources/profiles/BBL/filament/Bambu PET-CF @base.json index b982cd1361..ff8b40070f 100644 --- a/resources/profiles/BBL/filament/Bambu PET-CF @base.json +++ b/resources/profiles/BBL/filament/Bambu PET-CF @base.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/Bambu Support For PA PET @base.json b/resources/profiles/BBL/filament/Bambu Support For PA PET @base.json index a622bff105..d199cdb0a0 100644 --- a/resources/profiles/BBL/filament/Bambu Support For PA PET @base.json +++ b/resources/profiles/BBL/filament/Bambu Support For PA PET @base.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/Bambu Support For PLA @base.json b/resources/profiles/BBL/filament/Bambu Support For PLA @base.json index 10e4983ebf..9bfdef5bf9 100644 --- a/resources/profiles/BBL/filament/Bambu Support For PLA @base.json +++ b/resources/profiles/BBL/filament/Bambu Support For PLA @base.json @@ -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" diff --git a/resources/profiles/BBL/filament/Bambu Support For PLA-PETG @base.json b/resources/profiles/BBL/filament/Bambu Support For PLA-PETG @base.json index 0f1b87e83f..38443f5be3 100644 --- a/resources/profiles/BBL/filament/Bambu Support For PLA-PETG @base.json +++ b/resources/profiles/BBL/filament/Bambu Support For PLA-PETG @base.json @@ -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" diff --git a/resources/profiles/BBL/filament/Bambu Support G @base.json b/resources/profiles/BBL/filament/Bambu Support G @base.json index c903f92d07..9cb01972b8 100644 --- a/resources/profiles/BBL/filament/Bambu Support G @base.json +++ b/resources/profiles/BBL/filament/Bambu Support G @base.json @@ -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" diff --git a/resources/profiles/BBL/filament/Bambu Support for ABS @base.json b/resources/profiles/BBL/filament/Bambu Support for ABS @base.json index 35e13e67a0..bc8867db2a 100644 --- a/resources/profiles/BBL/filament/Bambu Support for ABS @base.json +++ b/resources/profiles/BBL/filament/Bambu Support for ABS @base.json @@ -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" diff --git a/resources/profiles/BBL/filament/Generic PA @base.json b/resources/profiles/BBL/filament/Generic PA @base.json index 5947f5a859..fe819487b0 100644 --- a/resources/profiles/BBL/filament/Generic PA @base.json +++ b/resources/profiles/BBL/filament/Generic PA @base.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/Generic PCTG @base.json b/resources/profiles/BBL/filament/Generic PCTG @base.json index d0ec60848f..e8b7c1ce0a 100644 --- a/resources/profiles/BBL/filament/Generic PCTG @base.json +++ b/resources/profiles/BBL/filament/Generic PCTG @base.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/Generic PPS @base.json b/resources/profiles/BBL/filament/Generic PPS @base.json index e8da776dfc..882fea94e0 100644 --- a/resources/profiles/BBL/filament/Generic PPS @base.json +++ b/resources/profiles/BBL/filament/Generic PPS @base.json @@ -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" + ] } diff --git a/resources/profiles/BBL/filament/Polymaker/Fiberon PET-CF @base.json b/resources/profiles/BBL/filament/Polymaker/Fiberon PET-CF @base.json index 921ce55dd6..365ebb2fd7 100644 --- a/resources/profiles/BBL/filament/Polymaker/Fiberon PET-CF @base.json +++ b/resources/profiles/BBL/filament/Polymaker/Fiberon PET-CF @base.json @@ -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}" ] diff --git a/resources/profiles/BBL/filament/fdm_filament_abs.json b/resources/profiles/BBL/filament/fdm_filament_abs.json index d05b005db9..4eb47ce0bd 100644 --- a/resources/profiles/BBL/filament/fdm_filament_abs.json +++ b/resources/profiles/BBL/filament/fdm_filament_abs.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_asa.json b/resources/profiles/BBL/filament/fdm_filament_asa.json index de053b5e14..b5ae3ad8b5 100644 --- a/resources/profiles/BBL/filament/fdm_filament_asa.json +++ b/resources/profiles/BBL/filament/fdm_filament_asa.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_bvoh.json b/resources/profiles/BBL/filament/fdm_filament_bvoh.json index 1a766a5a71..ee15cc5e30 100644 --- a/resources/profiles/BBL/filament/fdm_filament_bvoh.json +++ b/resources/profiles/BBL/filament/fdm_filament_bvoh.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_eva.json b/resources/profiles/BBL/filament/fdm_filament_eva.json index 283606c21e..a3f9ab0011 100644 --- a/resources/profiles/BBL/filament/fdm_filament_eva.json +++ b/resources/profiles/BBL/filament/fdm_filament_eva.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_hips.json b/resources/profiles/BBL/filament/fdm_filament_hips.json index 25c0acbb6f..7016a866f6 100644 --- a/resources/profiles/BBL/filament/fdm_filament_hips.json +++ b/resources/profiles/BBL/filament/fdm_filament_hips.json @@ -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" diff --git a/resources/profiles/BBL/filament/fdm_filament_pa.json b/resources/profiles/BBL/filament/fdm_filament_pa.json index 629ef70885..61aeed66ce 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pa.json +++ b/resources/profiles/BBL/filament/fdm_filament_pa.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pc.json b/resources/profiles/BBL/filament/fdm_filament_pc.json index 11dcf5ea46..a73a56b440 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pc.json +++ b/resources/profiles/BBL/filament/fdm_filament_pc.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pctg.json b/resources/profiles/BBL/filament/fdm_filament_pctg.json index f735c26f48..01810a2ddc 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pctg.json +++ b/resources/profiles/BBL/filament/fdm_filament_pctg.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pe.json b/resources/profiles/BBL/filament/fdm_filament_pe.json index 51549b2d8d..9235c3301e 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pe.json +++ b/resources/profiles/BBL/filament/fdm_filament_pe.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pet.json b/resources/profiles/BBL/filament/fdm_filament_pet.json index 8fde5f2faa..23a8f73fe4 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pet.json +++ b/resources/profiles/BBL/filament/fdm_filament_pet.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pha.json b/resources/profiles/BBL/filament/fdm_filament_pha.json index b9ac18587d..2bd348e2de 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pha.json +++ b/resources/profiles/BBL/filament/fdm_filament_pha.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pla.json b/resources/profiles/BBL/filament/fdm_filament_pla.json index 3c6713b86d..f1e1c9a244 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pla.json +++ b/resources/profiles/BBL/filament/fdm_filament_pla.json @@ -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" diff --git a/resources/profiles/BBL/filament/fdm_filament_pp.json b/resources/profiles/BBL/filament/fdm_filament_pp.json index dd390e0a82..2d8c3772ba 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pp.json +++ b/resources/profiles/BBL/filament/fdm_filament_pp.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_ppa.json b/resources/profiles/BBL/filament/fdm_filament_ppa.json index bb06a73c76..3bba318bc5 100644 --- a/resources/profiles/BBL/filament/fdm_filament_ppa.json +++ b/resources/profiles/BBL/filament/fdm_filament_ppa.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pps.json b/resources/profiles/BBL/filament/fdm_filament_pps.json index a19a5aca2b..d1c6a6aed2 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pps.json +++ b/resources/profiles/BBL/filament/fdm_filament_pps.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_pva.json b/resources/profiles/BBL/filament/fdm_filament_pva.json index 98ca7e63b9..55d83517ce 100644 --- a/resources/profiles/BBL/filament/fdm_filament_pva.json +++ b/resources/profiles/BBL/filament/fdm_filament_pva.json @@ -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" ], diff --git a/resources/profiles/BBL/filament/fdm_filament_tpu.json b/resources/profiles/BBL/filament/fdm_filament_tpu.json index f6ab1d3edf..d2ef5db84e 100644 --- a/resources/profiles/BBL/filament/fdm_filament_tpu.json +++ b/resources/profiles/BBL/filament/fdm_filament_tpu.json @@ -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" ], From 7f67946dbf4eb74283e22ad8bb4e29607bce5412 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 22:02:10 +0800 Subject: [PATCH 028/130] Fix incorrect length modification when loading device-related parameters (cherry picked from commit bambulab/BambuStudio@ebf57372da54e7515d3a469b0dbe468ff16e9aed) Co-Authored-By: weizhen.xie --- src/libslic3r/Preset.cpp | 2 ++ src/libslic3r/PrintConfig.cpp | 11 +++++++++++ src/libslic3r/PrintConfig.hpp | 2 ++ 3 files changed, 15 insertions(+) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index dbdd48a0df..077814130d 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -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());*/ diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c053b3f8fa..7c116dce3e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -8538,6 +8538,17 @@ std::set printer_options_with_variant_2 = { std::set empty_options; +std::set 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()); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 2948f24417..6ea1f9db1c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -698,6 +698,8 @@ extern std::set printer_options_with_variant_1; extern std::set printer_options_with_variant_2; extern std::set empty_options; +extern std::set filament_dev_options; + 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& f_maps); From 696a94a1a6c76a4bec04072b735b8f8af83726f1 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 22:29:28 +0800 Subject: [PATCH 029/130] Update color --- src/slic3r/GUI/AMSDryControl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index 98b35b5809..9efe7faa87 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -86,7 +86,7 @@ FilamentItemPanel::FilamentItemPanel(wxWindow* parent, const wxString& text, con : wxPanel(parent, id) , m_icon_name(icon_name) { - SetBackgroundColour(wxColour("#F7F7F7")); // Light gray background + SetBackgroundColour(wxColour("#F0F0F1")); // Light gray background SetMinSize(wxSize(FromDIP(64), FromDIP(106))); // Width: 64, Height: 106 SetSize(wxSize(FromDIP(64), FromDIP(106))); // Fixed size @@ -99,7 +99,7 @@ FilamentItemPanel::FilamentItemPanel(wxWindow* parent, const wxString& text, con m_text_label = new Label(this, text); m_text_label->SetForegroundColour(StateColor::darkModeColorFor(wxColour(*wxBLACK))); - m_text_label->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F7F7F7"))); + m_text_label->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F0F0F1"))); m_text_label->SetFont(Label::Body_12); m_text_label->Wrap(FromDIP(40)); top_sizer->Add(m_text_label, 0, wxALIGN_CENTER_HORIZONTAL); @@ -112,7 +112,7 @@ FilamentItemPanel::FilamentItemPanel(wxWindow* parent, const wxString& text, con bottom_sizer->AddStretchSpacer(1); m_icon_bitmap = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap); - m_icon_bitmap->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F7F7F7"))); + m_icon_bitmap->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#F0F0F1"))); m_icon_bitmap->SetMinSize(wxSize(FromDIP(24), FromDIP(24))); m_icon_bitmap->SetMaxSize(wxSize(FromDIP(24), FromDIP(24))); bottom_sizer->Add(m_icon_bitmap, 0, wxALIGN_CENTER_HORIZONTAL); @@ -170,7 +170,7 @@ void FilamentItemPanel::OnPaint(wxPaintEvent& event) wxSize size = GetSize(); // bool is_dark_mode = wxGetApp().dark_mode(); - wxColour backgroundColor = StateColor::darkModeColorFor(wxColour("#F7F7F7")); + wxColour backgroundColor = StateColor::darkModeColorFor(wxColour("#F0F0F1")); wxColour borderColor = StateColor::darkModeColorFor(wxColour("#DBDBDB")); // Draw white background rectangle with rounded corners inside the thick vertical lines @@ -208,7 +208,7 @@ AMSFilamentPanel::AMSFilamentPanel(wxWindow* parent, const wxString& ams_name, w // Filament items section m_filament_container = new wxPanel(this); - m_filament_container->SetBackgroundColour(wxColour("#F7F7F7")); + m_filament_container->SetBackgroundColour(wxColour("#F0F0F1")); m_filament_sizer = new wxBoxSizer(wxHORIZONTAL); m_filament_container->SetSizer(m_filament_sizer); From 40fd22530870ed65828231c669d76d8c189f3f4f Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Tue, 7 Jul 2026 23:16:04 +0800 Subject: [PATCH 030/130] Make sure new strings are translated --- localization/i18n/list.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/localization/i18n/list.txt b/localization/i18n/list.txt index d968cd5322..d63686b1da 100644 --- a/localization/i18n/list.txt +++ b/localization/i18n/list.txt @@ -274,4 +274,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 From 12b63ebe361b4efe092f7c140e7bf31e6d6645bc Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Wed, 8 Jul 2026 09:16:00 -0300 Subject: [PATCH 031/130] Localization context (verb noun adjective adverb) (#14646) * Torre de purga capitalization * Russian navigation back * Inches * verb noun adjective adverb * Posterior * Fix atras for camera view * Camera view --- localization/i18n/OrcaSlicer.pot | 27 ++++++++-- localization/i18n/ca/OrcaSlicer_ca.po | 36 ++++++++++--- localization/i18n/cs/OrcaSlicer_cs.po | 32 ++++++++++-- localization/i18n/de/OrcaSlicer_de.po | 36 ++++++++++--- localization/i18n/en/OrcaSlicer_en.po | 27 ++++++++-- localization/i18n/es/OrcaSlicer_es.po | 50 +++++++++++++------ localization/i18n/fr/OrcaSlicer_fr.po | 34 ++++++++++--- localization/i18n/hu/OrcaSlicer_hu.po | 32 ++++++++++-- localization/i18n/it/OrcaSlicer_it.po | 36 ++++++++++--- localization/i18n/ja/OrcaSlicer_ja.po | 36 ++++++++++--- localization/i18n/ko/OrcaSlicer_ko.po | 36 ++++++++++--- localization/i18n/lt/OrcaSlicer_lt.po | 30 +++++++++-- localization/i18n/nl/OrcaSlicer_nl.po | 33 +++++++++--- localization/i18n/pl/OrcaSlicer_pl.po | 36 ++++++++++--- localization/i18n/pt_BR/OrcaSlicer_pt_BR.po | 30 +++++++++-- localization/i18n/ru/OrcaSlicer_ru.po | 34 +++++++++++-- localization/i18n/sv/OrcaSlicer_sv.po | 36 ++++++++++--- localization/i18n/th/OrcaSlicer_th.po | 30 +++++++++-- localization/i18n/tr/OrcaSlicer_tr.po | 32 ++++++++++-- localization/i18n/uk/OrcaSlicer_uk.po | 32 ++++++++++-- localization/i18n/vi/OrcaSlicer_vi.po | 32 ++++++++++-- localization/i18n/zh_CN/OrcaSlicer_zh_CN.po | 32 ++++++++++-- localization/i18n/zh_TW/OrcaSlicer_zh_TW.po | 32 ++++++++++-- src/slic3r/GUI/ExtrusionCalibration.cpp | 2 +- src/slic3r/GUI/GCodeViewer.cpp | 4 +- src/slic3r/GUI/GLCanvas3D.cpp | 6 +-- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 4 +- .../GUI/Gizmos/GizmoObjectManipulation.cpp | 4 +- src/slic3r/GUI/ImageGrid.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 10 ++-- src/slic3r/GUI/MediaFilePanel.cpp | 6 +-- src/slic3r/GUI/SelectMachine.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 2 +- src/slic3r/GUI/WebViewDialog.cpp | 2 +- 35 files changed, 660 insertions(+), 157 deletions(-) diff --git a/localization/i18n/OrcaSlicer.pot b/localization/i18n/OrcaSlicer.pot index b50789a152..79b8fb0fb0 100644 --- a/localization/i18n/OrcaSlicer.pot +++ b/localization/i18n/OrcaSlicer.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:50-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -325,6 +325,7 @@ msgstr "" msgid "Optimize orientation" msgstr "" +msgctxt "Verb" msgid "Scale" msgstr "" @@ -368,6 +369,9 @@ msgstr "" msgid "Object operations" msgstr "" +msgid "Scale" +msgstr "" + msgid "Volume operations" msgstr "" @@ -413,6 +417,10 @@ msgstr "" msgid "Reset current rotation to real zeros." msgstr "" +msgctxt "Noun" +msgid "Scale" +msgstr "" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "" @@ -3499,6 +3507,7 @@ msgstr "" msgid "Save" msgstr "" +msgctxt "Navigation" msgid "Back" msgstr "" @@ -4781,6 +4790,7 @@ msgstr "" msgid "Color change" msgstr "" +msgctxt "Noun" msgid "Print" msgstr "" @@ -4936,11 +4946,15 @@ msgstr "" msgid "Align to Y axis" msgstr "" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "" + +msgctxt "Camera View" msgid "Left" msgstr "" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "" @@ -5257,6 +5271,10 @@ msgstr "" msgid "Export G-code file" msgstr "" +msgctxt "Verb" +msgid "Print" +msgstr "" + msgid "Export plate sliced file" msgstr "" @@ -13920,6 +13938,9 @@ msgstr "" msgid "Aligned back" msgstr "" +msgid "Back" +msgstr "" + msgid "Random" msgstr "" diff --git a/localization/i18n/ca/OrcaSlicer_ca.po b/localization/i18n/ca/OrcaSlicer_ca.po index 9f18508808..a509c7a89f 100644 --- a/localization/i18n/ca/OrcaSlicer_ca.po +++ b/localization/i18n/ca/OrcaSlicer_ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2025-03-15 10:55+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -332,6 +332,7 @@ msgstr "Gizmo-Rotació" msgid "Optimize orientation" msgstr "Optimitzar l'orientació" +msgctxt "Verb" msgid "Scale" msgstr "Escalar" @@ -376,6 +377,9 @@ msgstr "Ràtios d'escala" msgid "Object operations" msgstr "Operacions amb objectes" +msgid "Scale" +msgstr "Escalar" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Operacions de volum" @@ -427,6 +431,10 @@ msgstr "Restableix la rotació actual al valor d'quan s'ha obert l'eina de rotac msgid "Reset current rotation to real zeros." msgstr "Restableix la rotació actual a zeros reals." +msgctxt "Noun" +msgid "Scale" +msgstr "Escalar" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Mida" @@ -3652,7 +3660,7 @@ msgstr "Calibratge completat. Trobeu la línia d'extrusió més uniforme al vost msgid "Save" msgstr "Desar" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Darrera" @@ -5035,6 +5043,7 @@ msgstr "Canvis d'eina" msgid "Color change" msgstr "Canvi de color" +msgctxt "Noun" msgid "Print" msgstr "Imprimir" @@ -5198,11 +5207,15 @@ msgstr "Evitar la regió de calibratge d'extrusió" msgid "Align to Y axis" msgstr "Alinear a l'eix Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Darrera" + +msgctxt "Camera View" msgid "Left" msgstr "Esquerra" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Dreta" @@ -5531,6 +5544,10 @@ msgstr "Imprimir placa d'impressió" msgid "Export G-code file" msgstr "Exportar el fitxer del Codi-G" +msgctxt "Verb" +msgid "Print" +msgstr "Imprimir" + msgid "Export plate sliced file" msgstr "Exportar fitxer de la placa laminada" @@ -14808,6 +14825,10 @@ msgstr "Alineat" msgid "Aligned back" msgstr "Alineat al darrere" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Darrera" + msgid "Random" msgstr "Aleatori" @@ -19647,6 +19668,9 @@ msgstr "" "Evitar la deformació( warping )\n" "Sabíeu que quan imprimiu materials propensos a deformar-se, com ara l'ABS, augmentar adequadament la temperatura del llit pot reduir la probabilitat de deformació?" +#~ msgid "Print" +#~ msgstr "Imprimir" + #~ msgid "in" #~ msgstr "polç" @@ -21103,10 +21127,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Desmarcar" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Escalar" - #~ msgid "Lift Z Enforcement" #~ msgstr "Forçar elevació Z" diff --git a/localization/i18n/cs/OrcaSlicer_cs.po b/localization/i18n/cs/OrcaSlicer_cs.po index a5bdbb3ed9..7c32cff068 100644 --- a/localization/i18n/cs/OrcaSlicer_cs.po +++ b/localization/i18n/cs/OrcaSlicer_cs.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: Jakub Hencl\n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "Gizmo-Otočit" msgid "Optimize orientation" msgstr "Optimalizovat orientaci" +msgctxt "Verb" msgid "Scale" msgstr "Měřítko" @@ -371,6 +372,9 @@ msgstr "Poměry měřítka" msgid "Object operations" msgstr "Operace s objektem" +msgid "Scale" +msgstr "Měřítko" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Operace s hlasitostí" @@ -422,6 +426,10 @@ msgstr "Obnovit aktuální rotaci na hodnotu při otevření nástroje pro rotac msgid "Reset current rotation to real zeros." msgstr "Obnovit aktuální rotaci na skutečné nuly." +msgctxt "Noun" +msgid "Scale" +msgstr "Měřítko" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Velikost" @@ -3651,7 +3659,7 @@ msgstr "Kalibrace byla dokončena. Najděte na vyhřívané podložce nejrovnom msgid "Save" msgstr "Uložit" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Zpět" @@ -5032,6 +5040,7 @@ msgstr "Výměny nástrojů" msgid "Color change" msgstr "Změna barvy" +msgctxt "Noun" msgid "Print" msgstr "Tisk" @@ -5195,11 +5204,15 @@ msgstr "Vyhněte se kalibrační oblasti extruze" msgid "Align to Y axis" msgstr "Zarovnat na osu Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Zpět" + +msgctxt "Camera View" msgid "Left" msgstr "Levý" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Pravý" @@ -5527,6 +5540,10 @@ msgstr "Tisková deska" msgid "Export G-code file" msgstr "Exportovat G-code soubor" +msgctxt "Verb" +msgid "Print" +msgstr "Tisk" + msgid "Export plate sliced file" msgstr "Exportovat nařezaný soubor desky" @@ -14855,6 +14872,10 @@ msgstr "Zarovnáno" msgid "Aligned back" msgstr "Zarovnat zpět" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Zpět" + msgid "Random" msgstr "Náhodně" @@ -19681,6 +19702,9 @@ msgstr "" "Zamezte kroucení\n" "Víte, že při tisku materiálů náchylných ke kroucení, jako je ABS, může vhodné zvýšení teploty vyhřívané desky snížit pravděpodobnost kroucení?" +#~ msgid "Print" +#~ msgstr "Tisk" + #~ msgid "in" #~ msgstr "v" diff --git a/localization/i18n/de/OrcaSlicer_de.po b/localization/i18n/de/OrcaSlicer_de.po index 3849457ddc..1fac95632e 100644 --- a/localization/i18n/de/OrcaSlicer_de.po +++ b/localization/i18n/de/OrcaSlicer_de.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: Heiko Liebscher \n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "Gizmo-Drehen" msgid "Optimize orientation" msgstr "Optimiere Ausrichtung" +msgctxt "Verb" msgid "Scale" msgstr "Skalieren" @@ -371,6 +372,9 @@ msgstr "Skalierungsverhältnisse" msgid "Object operations" msgstr "Objekt-Operationen" +msgid "Scale" +msgstr "Skalieren" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Volumen Operationen" @@ -422,6 +426,10 @@ msgstr "Setze die aktuelle Rotation auf den Wert zurück, als das Rotationswerkz msgid "Reset current rotation to real zeros." msgstr "Setze die aktuelle Rotation auf die realen Nullen zurück." +msgctxt "Noun" +msgid "Scale" +msgstr "Skalieren" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Größe" @@ -3654,7 +3662,7 @@ msgstr "Kalibrierung abgeschlossen. Bitte suchen Sie die gleichmäßigste Extrus msgid "Save" msgstr "Speichern" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Zurück" @@ -5036,6 +5044,7 @@ msgstr "Werkzeugwechsel" msgid "Color change" msgstr "Farbwechsel" +msgctxt "Noun" msgid "Print" msgstr "aktuelle Platte drucken" @@ -5199,11 +5208,15 @@ msgstr "Vermeiden Sie den Bereich der Extrusionskalibrierung" msgid "Align to Y axis" msgstr "An Y-Achse ausrichten" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Zurück" + +msgctxt "Camera View" msgid "Left" msgstr "links" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "rechts" @@ -5529,6 +5542,10 @@ msgstr "Aktuelle Platte drucken" msgid "Export G-code file" msgstr "G-Code als Datei exportieren" +msgctxt "Verb" +msgid "Print" +msgstr "aktuelle Platte drucken" + msgid "Export plate sliced file" msgstr "Exportiere aktuelle Platte als STL Datei" @@ -14962,6 +14979,10 @@ msgstr "Ausgerichtet" msgid "Aligned back" msgstr "Ausgerichtet hinten" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Zurück" + msgid "Random" msgstr "Zufall" @@ -19822,6 +19843,9 @@ msgstr "" "Verwerfungen vermeiden\n" "Wussten Sie, dass beim Drucken von Materialien, die zu Verwerfungen neigen, wie z.B. ABS, durch eine entsprechende Erhöhung der Heizbetttemperatur die Wahrscheinlichkeit von Verwerfungen verringert werden kann?" +#~ msgid "Print" +#~ msgstr "aktuelle Platte drucken" + #~ msgid "in" #~ msgstr "in" @@ -21730,10 +21754,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Abwählen" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Skalieren" - #~ msgid "Lift Z Enforcement" #~ msgstr "Z-Höhe einhalten" diff --git a/localization/i18n/en/OrcaSlicer_en.po b/localization/i18n/en/OrcaSlicer_en.po index 6e6628b5ce..b314b99808 100644 --- a/localization/i18n/en/OrcaSlicer_en.po +++ b/localization/i18n/en/OrcaSlicer_en.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-06-17 15:44-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: \n" @@ -321,6 +321,7 @@ msgstr "" msgid "Optimize orientation" msgstr "" +msgctxt "Verb" msgid "Scale" msgstr "" @@ -364,6 +365,9 @@ msgstr "" msgid "Object operations" msgstr "" +msgid "Scale" +msgstr "" + msgid "Volume operations" msgstr "" @@ -409,6 +413,10 @@ msgstr "" msgid "Reset current rotation to real zeros." msgstr "" +msgctxt "Noun" +msgid "Scale" +msgstr "" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "" @@ -3495,6 +3503,7 @@ msgstr "" msgid "Save" msgstr "" +msgctxt "Navigation" msgid "Back" msgstr "" @@ -4777,6 +4786,7 @@ msgstr "" msgid "Color change" msgstr "" +msgctxt "Noun" msgid "Print" msgstr "" @@ -4932,11 +4942,15 @@ msgstr "" msgid "Align to Y axis" msgstr "" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "" + +msgctxt "Camera View" msgid "Left" msgstr "" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "" @@ -5253,6 +5267,10 @@ msgstr "" msgid "Export G-code file" msgstr "" +msgctxt "Verb" +msgid "Print" +msgstr "" + msgid "Export plate sliced file" msgstr "" @@ -13916,6 +13934,9 @@ msgstr "" msgid "Aligned back" msgstr "" +msgid "Back" +msgstr "" + msgid "Random" msgstr "" diff --git a/localization/i18n/es/OrcaSlicer_es.po b/localization/i18n/es/OrcaSlicer_es.po index cdbe024f27..a0cdb98728 100644 --- a/localization/i18n/es/OrcaSlicer_es.po +++ b/localization/i18n/es/OrcaSlicer_es.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: Ian A. Bassi <>\n" "Language-Team: \n" @@ -321,6 +321,7 @@ msgstr "Herramienta de rotación" msgid "Optimize orientation" msgstr "Optimizar orientación" +msgctxt "Verb" msgid "Scale" msgstr "Escalar" @@ -332,7 +333,7 @@ msgstr "Error: Por favor, cierre primero todos los menús de la barra de herrami msgctxt "inches" msgid "in" -msgstr "" +msgstr "\"" msgid "mm" msgstr "mm" @@ -364,6 +365,9 @@ msgstr "Factor de escalado" msgid "Object operations" msgstr "Operaciones con objetos" +msgid "Scale" +msgstr "Escalar" + msgid "Volume operations" msgstr "Operaciones de volumen" @@ -409,6 +413,10 @@ msgstr "Restablecer la rotación actual al valor que tenía al abrir la herramie msgid "Reset current rotation to real zeros." msgstr "Restablecer la rotación actual a ceros reales." +msgctxt "Noun" +msgid "Scale" +msgstr "Escala" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Tamaño" @@ -3580,6 +3588,7 @@ msgstr "Calibración completada. Por favor, observe cual es línea de extrusión msgid "Save" msgstr "Guardar" +msgctxt "Navigation" msgid "Back" msgstr "Atrás" @@ -4709,7 +4718,7 @@ msgid "Support interface" msgstr "Interfaz de soporte" msgid "Prime tower" -msgstr "Torre de Purga" +msgstr "Torre de purga" msgid "Bottom surface" msgstr "Relleno sólido inferior" @@ -4930,8 +4939,9 @@ msgstr "Cambios de herramienta" msgid "Color change" msgstr "Cambio de color" +msgctxt "Noun" msgid "Print" -msgstr "Imprimir" +msgstr "Impresión" msgid "Printer" msgstr "Impresora" @@ -5089,11 +5099,15 @@ msgstr "Evitar la zona de calibración del extrusor" msgid "Align to Y axis" msgstr "Alinear con el eje Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Posterior" + +msgctxt "Camera View" msgid "Left" msgstr "Izquierda" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Derecha" @@ -5416,6 +5430,10 @@ msgstr "Imprimir cama" msgid "Export G-code file" msgstr "Exportar archivo G-Code" +msgctxt "Verb" +msgid "Print" +msgstr "Imprimir" + msgid "Export plate sliced file" msgstr "Exportar los objetos laminados de la cama a un archivo" @@ -5488,10 +5506,10 @@ msgid "Front View" msgstr "Vista frontal" msgid "Rear" -msgstr "Trasera" +msgstr "Posterior" msgid "Rear View" -msgstr "Vista trasera" +msgstr "Vista posterior" msgid "Left View" msgstr "Vista izquierda" @@ -9190,7 +9208,7 @@ msgstr "Característica experimental: Retraer y cortar el filamento a mayor dist msgid "" "When recording timelapse without toolhead, it is recommended to add a \"Timelapse Wipe Tower\" \n" "by right-click the empty position of build plate and choose \"Add Primitive\"->\"Timelapse Wipe Tower\"." -msgstr "Cuando se graba un timelapse sin cabezal, se recomienda añadir una \"Torre de Purga de Timelapse\" haciendo clic con el botón derecho del ratón en una posición vacía de la cama de impresión y seleccionando \"Añadir Primitivo\"->Torre de Purga de Timelapse\"." +msgstr "Cuando se graba un timelapse sin cabezal, se recomienda añadir una \"Torre de purga de Timelapse\" haciendo clic con el botón derecho del ratón en una posición vacía de la cama de impresión y seleccionando \"Añadir Primitivo\"->\"Torre de purga de Timelapse\"." msgid "A copy of the current system preset will be created, which will be detached from the system preset." msgstr "Se creará una copia de el perfil de sistema actual, que quedará separado del perfil de sistema." @@ -10896,7 +10914,7 @@ msgid " is too close to clumping detection area, there may be collisions when pr msgstr " está demasiado cerca del área de detección de aglomeraciones, puede haber colisiones durante la impresión." msgid "Prime Tower" -msgstr "Torre de Purga" +msgstr "Torre de purga" msgid " is too close to others, and collisions may be caused.\n" msgstr " está demasiado cerca de otros, y se pueden producir colisiones.\n" @@ -12750,7 +12768,7 @@ msgid "After a tool change, the exact position of the newly loaded filament insi msgstr "Tras un cambio de cabezal, es posible que no se conozca la posición exacta del filamento recién cargado dentro de la boquilla y que la presión del filamento aún no sea estable. Antes de purgar el cabezal de impresión en un relleno o en un objeto de sacrificio, OrcaSlicer siempre cebará esta cantidad de material en la torre de purga para producir sucesivas extrusiones de relleno u objetos de sacrificio de forma fiable." msgid "Wipe tower cooling" -msgstr "Refrigeración de Torre de Purga" +msgstr "Refrigeración de torre de purga" msgid "Temperature drop before entering filament tower" msgstr "Descenso de temperatura antes de entrar en la torre de filamentos" @@ -14657,6 +14675,9 @@ msgstr "Alineado" msgid "Aligned back" msgstr "Alineado atrás" +msgid "Back" +msgstr "Atrás" + msgid "Random" msgstr "Aleatorio" @@ -19429,6 +19450,9 @@ msgstr "" "Evita la deformación\n" "¿Sabías que al imprimir materiales propensos a la deformación como el ABS, aumentar adecuadamente la temperatura de la cama térmica puede reducir la probabilidad de deformaciones?" +#~ msgid "Print" +#~ msgstr "Imprimir" + #~ msgid "in" #~ msgstr "pulg" @@ -21012,10 +21036,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Deseleccionar" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Escala" - #~ msgid "Lift Z Enforcement" #~ msgstr "Forzar elevación Z" diff --git a/localization/i18n/fr/OrcaSlicer_fr.po b/localization/i18n/fr/OrcaSlicer_fr.po index c789268248..e3f054b7c1 100644 --- a/localization/i18n/fr/OrcaSlicer_fr.po +++ b/localization/i18n/fr/OrcaSlicer_fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: Guislain Cyril, Thomas Lété\n" @@ -324,6 +324,7 @@ msgstr "Gizmo-Pivoter" msgid "Optimize orientation" msgstr "Optimiser l'orientation" +msgctxt "Verb" msgid "Scale" msgstr "Redimensionner" @@ -367,6 +368,9 @@ msgstr "Rapports d'échelle" msgid "Object operations" msgstr "Opérations sur les objets" +msgid "Scale" +msgstr "Redimensionner" + msgid "Volume operations" msgstr "Opérations sur les volumes" @@ -412,6 +416,10 @@ msgstr "Réinitialiser la rotation actuelle à la valeur lors de l'ouverture de msgid "Reset current rotation to real zeros." msgstr "Réinitialiser la rotation actuelle à zéro." +msgctxt "Noun" +msgid "Scale" +msgstr "Redimensionner" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Taille" @@ -3569,6 +3577,7 @@ msgstr "Calibrage terminé. Veuillez trouver la ligne d'extrusion la plus unifor msgid "Save" msgstr "Enregistrer" +msgctxt "Navigation" msgid "Back" msgstr "Arrière" @@ -4916,6 +4925,7 @@ msgstr "Changements d’outil" msgid "Color change" msgstr "Changement de couleur" +msgctxt "Noun" msgid "Print" msgstr "Imprimer" @@ -5075,11 +5085,15 @@ msgstr "Éviter la région de calibration de l'extrusion" msgid "Align to Y axis" msgstr "Aligner sur l’axe Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Arrière" + +msgctxt "Camera View" msgid "Left" msgstr "Gauche" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Droite" @@ -5402,6 +5416,10 @@ msgstr "Imprimer le plateau" msgid "Export G-code file" msgstr "Exporter le fichier G-code" +msgctxt "Verb" +msgid "Print" +msgstr "Imprimer" + msgid "Export plate sliced file" msgstr "Exporter le fichier découpé du plateau" @@ -14628,6 +14646,9 @@ msgstr "Alignée" msgid "Aligned back" msgstr "Aligné à l'arrière" +msgid "Back" +msgstr "Arrière" + msgid "Random" msgstr "Aléatoire" @@ -19397,6 +19418,9 @@ msgstr "" "Éviter la déformation\n" "Saviez-vous que lors de l’impression de matériaux susceptibles de se déformer, tels que l’ABS, une augmentation appropriée de la température du plateau chauffant peut réduire la probabilité de déformation?" +#~ msgid "Print" +#~ msgstr "Imprimer" + #~ msgid "in" #~ msgstr "dans" @@ -21107,10 +21131,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Désélectionner" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Redimensionner" - #~ msgid "Lift Z Enforcement" #~ msgstr "Exécution du décalage en Z" diff --git a/localization/i18n/hu/OrcaSlicer_hu.po b/localization/i18n/hu/OrcaSlicer_hu.po index 497f0ebf29..1cf18316e2 100644 --- a/localization/i18n/hu/OrcaSlicer_hu.po +++ b/localization/i18n/hu/OrcaSlicer_hu.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -324,6 +324,7 @@ msgstr "Gizmo-Forgatás" msgid "Optimize orientation" msgstr "Orientáció optimalizálása" +msgctxt "Verb" msgid "Scale" msgstr "Átméretezés" @@ -368,6 +369,9 @@ msgstr "Méretarányok" msgid "Object operations" msgstr "Objektum műveletek" +msgid "Scale" +msgstr "Átméretezés" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Térfogat műveletek" @@ -419,6 +423,10 @@ msgstr "Az aktuális forgatás visszaállítása a forgatás eszköz megnyitása msgid "Reset current rotation to real zeros." msgstr "Az aktuális forgatás visszaállítása valódi nullára." +msgctxt "Noun" +msgid "Scale" +msgstr "Átméretezés" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Méret" @@ -3645,7 +3653,7 @@ msgstr "A kalibrálás befejeződött. Kérlek, válaszd ki az alábbi képen l msgid "Save" msgstr "Mentés" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Hátul" @@ -5026,6 +5034,7 @@ msgstr "Szerszámváltások" msgid "Color change" msgstr "Színváltás" +msgctxt "Noun" msgid "Print" msgstr "Nyomtatás" @@ -5189,11 +5198,15 @@ msgstr "Extrudáláskalibráció környékének elkerülése" msgid "Align to Y axis" msgstr "Igazítás az Y-tengelyhez" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Hátul" + +msgctxt "Camera View" msgid "Left" msgstr "Bal" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Jobb" @@ -5521,6 +5534,10 @@ msgstr "Nyomtatótálca" msgid "Export G-code file" msgstr "G-kód fájl exportálása" +msgctxt "Verb" +msgid "Print" +msgstr "Nyomtatás" + msgid "Export plate sliced file" msgstr "Szeletelt tálca exportálása" @@ -14880,6 +14897,10 @@ msgstr "Igazított" msgid "Aligned back" msgstr "Hátulra igazítva" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Hátul" + msgid "Random" msgstr "Véletlenszerû" @@ -19712,6 +19733,9 @@ msgstr "" "Kunkorodás elkerülése\n" "Tudtad, hogy a kunkorodásra hajlamos anyagok (például ABS) nyomtatásakor a tárgyasztal hőmérsékletének növelése csökkentheti a kunkorodás valószínűségét?" +#~ msgid "Print" +#~ msgstr "Nyomtatás" + #~ msgid "in" #~ msgstr "in" diff --git a/localization/i18n/it/OrcaSlicer_it.po b/localization/i18n/it/OrcaSlicer_it.po index 6aa547173a..70ee57c0e9 100644 --- a/localization/i18n/it/OrcaSlicer_it.po +++ b/localization/i18n/it/OrcaSlicer_it.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "Strumento di rotazione" msgid "Optimize orientation" msgstr "Ottimizza orientamento" +msgctxt "Verb" msgid "Scale" msgstr "Ridimensiona" @@ -371,6 +372,9 @@ msgstr "Rapporti di scala" msgid "Object operations" msgstr "Operazioni sugli oggetti" +msgid "Scale" +msgstr "Ridimensiona" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Operazioni volume" @@ -422,6 +426,10 @@ msgstr "Reimposta la rotazione corrente al valore di apertura dello strumento." msgid "Reset current rotation to real zeros." msgstr "Reimposta la rotazione corrente a zero reale." +msgctxt "Noun" +msgid "Scale" +msgstr "Ridimensiona" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Dimensioni" @@ -3646,7 +3654,7 @@ msgstr "Calibrazione completata. Trova la linea di estrusione più uniforme sul msgid "Save" msgstr "Salva" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Posteriore" @@ -5027,6 +5035,7 @@ msgstr "Cambi testina" msgid "Color change" msgstr "Cambio colore" +msgctxt "Noun" msgid "Print" msgstr "Stampa" @@ -5190,11 +5199,15 @@ msgstr "Evitare la regione di calibrazione dell'estrusione" msgid "Align to Y axis" msgstr "Allinea all'asse Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Posteriore" + +msgctxt "Camera View" msgid "Left" msgstr "Sinistra" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Destra" @@ -5522,6 +5535,10 @@ msgstr "Piatto di stampa" msgid "Export G-code file" msgstr "Esporta file G-code" +msgctxt "Verb" +msgid "Print" +msgstr "Stampa" + msgid "Export plate sliced file" msgstr "Esporta il file del piatto elaborato" @@ -14854,6 +14871,10 @@ msgstr "Allineato" msgid "Aligned back" msgstr "Allineato dietro" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Posteriore" + msgid "Random" msgstr "Casuale" @@ -19692,6 +19713,9 @@ msgstr "" "Evita le deformazioni\n" "Sapevi che quando si stampano materiali soggetti a deformazioni come l'ABS, aumentare in modo appropriato la temperatura del piano riscaldato può ridurre la probabilità di deformazione?" +#~ msgid "Print" +#~ msgstr "Stampa" + #~ msgid "in" #~ msgstr "in" @@ -21208,10 +21232,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Deseleziona" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Ridimensiona" - #~ msgid "Lift Z Enforcement" #~ msgstr "Applicazione dell'ascensore Z" diff --git a/localization/i18n/ja/OrcaSlicer_ja.po b/localization/i18n/ja/OrcaSlicer_ja.po index 3faef352c0..03a498fd2a 100644 --- a/localization/i18n/ja/OrcaSlicer_ja.po +++ b/localization/i18n/ja/OrcaSlicer_ja.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "ギズモ-回転" msgid "Optimize orientation" msgstr "向きを最適化" +msgctxt "Verb" msgid "Scale" msgstr "スケール" @@ -371,6 +372,9 @@ msgstr "倍率" msgid "Object operations" msgstr "オブジェクト操作" +msgid "Scale" +msgstr "スケール" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "操作" @@ -422,6 +426,10 @@ msgstr "回転ツールを開いた時の値にリセットします。" msgid "Reset current rotation to real zeros." msgstr "現在の回転を0にリセットします。" +msgctxt "Noun" +msgid "Scale" +msgstr "スケール" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "サイズ" @@ -3629,7 +3637,7 @@ msgstr "キャリブレーションが完了しました。下の写真のよう msgid "Save" msgstr "保存" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "背面" @@ -5000,6 +5008,7 @@ msgstr "ツールチェンジ" msgid "Color change" msgstr "色変更" +msgctxt "Noun" msgid "Print" msgstr "造形する" @@ -5163,11 +5172,15 @@ msgstr "押出しキャリブレーション領域を避ける" msgid "Align to Y axis" msgstr "Y軸に整列" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "背面" + +msgctxt "Camera View" msgid "Left" msgstr "左" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "右" @@ -5489,6 +5502,10 @@ msgstr "造形開始" msgid "Export G-code file" msgstr "G-codeをエクスポート" +msgctxt "Verb" +msgid "Print" +msgstr "造形する" + msgid "Export plate sliced file" msgstr "エクスポート" @@ -14502,6 +14519,10 @@ msgstr "整列" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "背面" + msgid "Random" msgstr "ランダム" @@ -19160,6 +19181,9 @@ msgstr "" "反りを避ける\n" "ABSのような反りやすい素材を印刷する場合、ヒートベッドの温度を適切に上げることで、反りが発生する確率を下げることができることをご存知ですか?" +#~ msgid "Print" +#~ msgstr "造形する" + #~ msgid "in" #~ msgstr "に" @@ -20106,10 +20130,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "選択解除" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "スケール" - #~ msgid "Z-hop when retract" #~ msgstr "リトラクト時にZ方向調整" diff --git a/localization/i18n/ko/OrcaSlicer_ko.po b/localization/i18n/ko/OrcaSlicer_ko.po index 769694b8d6..3dae5ed37e 100644 --- a/localization/i18n/ko/OrcaSlicer_ko.po +++ b/localization/i18n/ko/OrcaSlicer_ko.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2025-06-02 17:12+0900\n" "Last-Translator: crwusiz \n" "Language-Team: \n" @@ -331,6 +331,7 @@ msgstr "변형도구 - 회전" msgid "Optimize orientation" msgstr "방향 최적화" +msgctxt "Verb" msgid "Scale" msgstr "배율" @@ -375,6 +376,9 @@ msgstr "배율비" msgid "Object operations" msgstr "객체 작업" +msgid "Scale" +msgstr "배율" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "용량 작업" @@ -426,6 +430,10 @@ msgstr "회전 도구를 열었을 때의 값으로 현재 회전을 초기화 msgid "Reset current rotation to real zeros." msgstr "현재 회전을 0으로 초기화합니다." +msgctxt "Noun" +msgid "Scale" +msgstr "배율" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "크기" @@ -3644,7 +3652,7 @@ msgstr "교정이 완료되었습니다. 당신의 고온 베드에서 아래 msgid "Save" msgstr "저장" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "뒷면" @@ -5026,6 +5034,7 @@ msgstr "" msgid "Color change" msgstr "색 변경" +msgctxt "Noun" msgid "Print" msgstr "출력" @@ -5189,11 +5198,15 @@ msgstr "압출 교정 영역을 피하세요" msgid "Align to Y axis" msgstr "Y축에 정렬" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "뒷면" + +msgctxt "Camera View" msgid "Left" msgstr "왼쪽" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "오른쪽" @@ -5517,6 +5530,10 @@ msgstr "플레이트 출력" msgid "Export G-code file" msgstr "Gcode 파일 내보내기" +msgctxt "Verb" +msgid "Print" +msgstr "출력" + msgid "Export plate sliced file" msgstr "플레이트 슬라이스 파일 내보내기" @@ -14720,6 +14737,10 @@ msgstr "정렬" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "뒷면" + msgid "Random" msgstr "무작위" @@ -19528,6 +19549,9 @@ msgstr "" "뒤틀림 방지\n" "ABS와 같이 뒤틀림이 발생하기 쉬운 소재를 출력할 때, 히트베드 온도를 적절하게 높이면 뒤틀림 가능성을 줄일 수 있다는 사실을 알고 계셨나요?" +#~ msgid "Print" +#~ msgstr "출력" + #~ msgid "in" #~ msgstr "인치" @@ -21019,10 +21043,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "선택 취소" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "규모" - #~ msgid "Lift Z Enforcement" #~ msgstr "강제 Z 올리기" diff --git a/localization/i18n/lt/OrcaSlicer_lt.po b/localization/i18n/lt/OrcaSlicer_lt.po index 69de514c68..99cb03a620 100644 --- a/localization/i18n/lt/OrcaSlicer_lt.po +++ b/localization/i18n/lt/OrcaSlicer_lt.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-07-02 14:13+0300\n" "Last-Translator: Gintaras Kučinskas \n" "Language-Team: \n" @@ -326,6 +326,7 @@ msgstr "Manipuliatorius – Pasukimas" msgid "Optimize orientation" msgstr "Optimizuoti orientaciją" +msgctxt "Verb" msgid "Scale" msgstr "Mastelis" @@ -369,6 +370,9 @@ msgstr "Mastelio koeficientai" msgid "Object operations" msgstr "" +msgid "Scale" +msgstr "Mastelis" + msgid "Volume operations" msgstr "" @@ -414,6 +418,10 @@ msgstr "Atkurti dabartinį pasukimą iki vertės, buvusios atidarius pasukimo į msgid "Reset current rotation to real zeros." msgstr "Atstatyti dabartinį sukimąsi į tikrąsias nulines vertes." +msgctxt "Noun" +msgid "Scale" +msgstr "Mastelis" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Dydis" @@ -3576,6 +3584,7 @@ msgstr "Kalibravimas baigtas. Raskite tolygiausią ekstruzijos liniją ant kaiti msgid "Save" msgstr "Išsaugoti" +msgctxt "Navigation" msgid "Back" msgstr "Atgal" @@ -4906,6 +4915,7 @@ msgstr "Įrankio keitimai" msgid "Color change" msgstr "Spalvos keitimas" +msgctxt "Noun" msgid "Print" msgstr "Spausdinti" @@ -5069,11 +5079,15 @@ msgstr "Vengti ekstruzijos kalibravimo srities" msgid "Align to Y axis" msgstr "Išlygiuoti pagal Y ašį" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Atgal" + +msgctxt "Camera View" msgid "Left" msgstr "Kairė" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Dešinė" @@ -5396,6 +5410,10 @@ msgstr "Spausdinti plokštę" msgid "Export G-code file" msgstr "Eksportuoti G-kodo failą" +msgctxt "Verb" +msgid "Print" +msgstr "Spausdinti" + msgid "Export plate sliced file" msgstr "Eksportuoti supjaustytos plokštės failą" @@ -14604,6 +14622,9 @@ msgstr "Sulygiuota" msgid "Aligned back" msgstr "Sulygiuota gale" +msgid "Back" +msgstr "Atgal" + msgid "Random" msgstr "Atsitiktinė" @@ -19346,6 +19367,9 @@ msgstr "" "Venkite deformacijų (warping)\n" "Ar žinojote, kad spausdinant medžiagas, kurios yra linkusios trauktis ir riestis (pvz., ABS), tinkamas kaitinamojo pagrindo temperatūros padidinimas gali sumažinti deformacijų (warping) tikimybę?" +#~ msgid "Print" +#~ msgstr "Spausdinti" + #~ msgid "in" #~ msgstr "col." diff --git a/localization/i18n/nl/OrcaSlicer_nl.po b/localization/i18n/nl/OrcaSlicer_nl.po index 4a264ad25a..03f731c243 100644 --- a/localization/i18n/nl/OrcaSlicer_nl.po +++ b/localization/i18n/nl/OrcaSlicer_nl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "Roteren" msgid "Optimize orientation" msgstr "Oriëntatie optimaliseren" +msgctxt "Verb" msgid "Scale" msgstr "Schalen" @@ -371,6 +372,9 @@ msgstr "Schaalverhoudingen" msgid "Object operations" msgstr "Objectbewerkingen" +msgid "Scale" +msgstr "Schalen" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Volumebewerkingen" @@ -422,6 +426,10 @@ msgstr "" msgid "Reset current rotation to real zeros." msgstr "" +msgctxt "Noun" +msgid "Scale" +msgstr "Schalen" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Maat" @@ -3611,7 +3619,7 @@ msgstr "Kalibratie voltooid. Zoek de meest uniforme extrusielijn op uw hotbed, z msgid "Save" msgstr "Bewaar" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Achterzijde" @@ -4971,6 +4979,7 @@ msgstr "Toolwisselingen" msgid "Color change" msgstr "Kleur veranderen" +msgctxt "Noun" msgid "Print" msgstr "" @@ -5129,11 +5138,15 @@ msgstr "Vermijd het extrusie kalibratie gebied" msgid "Align to Y axis" msgstr "Uitlijnen op Y-as" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Achterzijde" + +msgctxt "Camera View" msgid "Left" msgstr "Links" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Rechts" @@ -5457,6 +5470,10 @@ msgstr "Printplaat" msgid "Export G-code file" msgstr "G-codebestand exporteren" +msgctxt "Verb" +msgid "Print" +msgstr "" + msgid "Export plate sliced file" msgstr "Exporteer plate sliced bestand" @@ -14427,6 +14444,10 @@ msgstr "Uitgelijnd" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Achterzijde" + msgid "Random" msgstr "Willekeurig" @@ -20321,10 +20342,6 @@ msgstr "" #~ msgid "Thick bridges" #~ msgstr "Dikke bruggen" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Schalen" - #~ msgid "Z-hop when retract" #~ msgstr "Z-hop tijdens terugtrekken (retraction)" diff --git a/localization/i18n/pl/OrcaSlicer_pl.po b/localization/i18n/pl/OrcaSlicer_pl.po index 63ea040cc2..1810dc6092 100644 --- a/localization/i18n/pl/OrcaSlicer_pl.po +++ b/localization/i18n/pl/OrcaSlicer_pl.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer 2.3.0-rc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: \n" "Last-Translator: Krzysztof Morga <>\n" "Language-Team: \n" @@ -329,6 +329,7 @@ msgstr "Uchwyt-Obróć" msgid "Optimize orientation" msgstr "Optymalizuj orientację" +msgctxt "Verb" msgid "Scale" msgstr "Skaluj" @@ -373,6 +374,9 @@ msgstr "Współczynniki skali" msgid "Object operations" msgstr "Operacje na obiekcie" +msgid "Scale" +msgstr "Skaluj" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Operacje na objętości" @@ -424,6 +428,10 @@ msgstr "Zresetuj bieżący obrót do wartości ustawionej przy otwarciu narzędz msgid "Reset current rotation to real zeros." msgstr "Zresetuj bieżący obrót do wartości zerowej." +msgctxt "Noun" +msgid "Scale" +msgstr "Skaluj" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Rozmiar" @@ -3649,7 +3657,7 @@ msgstr "Kalibracja zakończona. Proszę znaleźć na płycie roboczej, linie eks msgid "Save" msgstr "Zapisz" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Tył" @@ -5023,6 +5031,7 @@ msgstr "Zmiany narzędzi" msgid "Color change" msgstr "Zmiana koloru" +msgctxt "Noun" msgid "Print" msgstr "Drukuj" @@ -5186,11 +5195,15 @@ msgstr "Unikaj obszaru kalibracji ekstruzji" msgid "Align to Y axis" msgstr "Wyrównaj do osi Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Tył" + +msgctxt "Camera View" msgid "Left" msgstr "Lewy" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Prawy" @@ -5518,6 +5531,10 @@ msgstr "Drukuj aktualną płytę" msgid "Export G-code file" msgstr "Eksportuj plik G-code" +msgctxt "Verb" +msgid "Print" +msgstr "Drukuj" + msgid "Export plate sliced file" msgstr "Eksportuj plik pociętej płyty" @@ -14738,6 +14755,10 @@ msgstr "Wyrównany" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Tył" + msgid "Random" msgstr "Losowo" @@ -19542,6 +19563,9 @@ msgstr "" "Unikaj odkształceń\n" "Czy wiesz, że podczas drukowania filamentami podatnymi na odkształcenia, takimi jak ABS, odpowiednie zwiększenie temperatury podgrzewanej płyty może zmniejszyć prawdopodobieństwo odkształceń?" +#~ msgid "Print" +#~ msgstr "Drukuj" + #~ msgid "in" #~ msgstr "cal" @@ -21000,10 +21024,6 @@ msgstr "" #~ msgid "Unselect" #~ msgstr "Odznacz" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Skala" - #~ msgid "Lift Z Enforcement" #~ msgstr "Wymuszenie podniesienia osi Z" diff --git a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po index 9b40d74f18..a1e9a39ce2 100644 --- a/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po +++ b/localization/i18n/pt_BR/OrcaSlicer_pt_BR.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-07-04 11:51-0300\n" "Last-Translator: Alexandre Folle de Menezes\n" "Language-Team: Portuguese, Brazilian\n" @@ -326,6 +326,7 @@ msgstr "Gizmo-Rotacionar" msgid "Optimize orientation" msgstr "Otimizar orientação" +msgctxt "Verb" msgid "Scale" msgstr "Escala" @@ -369,6 +370,9 @@ msgstr "Proporções de escala" msgid "Object operations" msgstr "Operações de objeto" +msgid "Scale" +msgstr "Escala" + msgid "Volume operations" msgstr "Operações de volume" @@ -414,6 +418,10 @@ msgstr "Redefinir rotação para o valor de abertura da ferramenta de rotação. msgid "Reset current rotation to real zeros." msgstr "Redefinir rotação atual para zeros reais." +msgctxt "Noun" +msgid "Scale" +msgstr "Escala" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Tamanho" @@ -3580,6 +3588,7 @@ msgstr "Calibração concluída. Por favor, encontre a linha de extrusão mais u msgid "Save" msgstr "Salvar" +msgctxt "Navigation" msgid "Back" msgstr "Atrás" @@ -4940,6 +4949,7 @@ msgstr "Trocas de ferramenta" msgid "Color change" msgstr "Mudança de cor" +msgctxt "Noun" msgid "Print" msgstr "Imprimir" @@ -5102,11 +5112,15 @@ msgstr "Evitar a região de calibração da extrusão" msgid "Align to Y axis" msgstr "Alinhar com o eixo Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Atrás" + +msgctxt "Camera View" msgid "Left" msgstr "Esquerda" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Direita" @@ -5433,6 +5447,10 @@ msgstr "Imprimir placa" msgid "Export G-code file" msgstr "Exportar arquivo G-code" +msgctxt "Verb" +msgid "Print" +msgstr "Imprimir" + msgid "Export plate sliced file" msgstr "Exportar arquivo de placa fatiada" @@ -14720,6 +14738,9 @@ msgstr "Alinhada" msgid "Aligned back" msgstr "Alinhada atrás" +msgid "Back" +msgstr "Atrás" + msgid "Random" msgstr "Aleatória" @@ -19489,6 +19510,9 @@ msgstr "" "Evitar empenamento\n" "Você sabia que ao imprimir materiais propensos ao empenamento como ABS, aumentar adequadamente a temperatura da mesa aquecida pode reduzir a probabilidade de empenamento?" +#~ msgid "Print" +#~ msgstr "Imprimir" + #~ msgid "in" #~ msgstr "pol" diff --git a/localization/i18n/ru/OrcaSlicer_ru.po b/localization/i18n/ru/OrcaSlicer_ru.po index 86110c89ee..712f9bcbec 100644 --- a/localization/i18n/ru/OrcaSlicer_ru.po +++ b/localization/i18n/ru/OrcaSlicer_ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: OrcaSlicer V2.5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-02-25 13:38+0300\n" "Last-Translator: Felix14_v2\n" "Language-Team: Felix14_v2 (ДС/ТГ: @felix14_v2, почта: aleks111001@list.ru), Andylg \n" @@ -337,6 +337,7 @@ msgstr "Инструмент вращения" msgid "Optimize orientation" msgstr "Оптимизация положения модели" +msgctxt "Verb" msgid "Scale" msgstr "Масштаб" @@ -380,6 +381,9 @@ msgstr "Коэф. масштаба" msgid "Object operations" msgstr "Операции с моделями" +msgid "Scale" +msgstr "Масштаб" + msgid "Volume operations" msgstr "Булевы операции с телами" @@ -425,6 +429,10 @@ msgstr "Сбросить последние изменения ориентац msgid "Reset current rotation to real zeros." msgstr "Сбросить ориентацию до изначальной" +msgctxt "Noun" +msgid "Scale" +msgstr "Масштаб" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Размер" @@ -3657,9 +3665,9 @@ msgstr "Калибровка завершена. Теперь найдите н msgid "Save" msgstr "Сохранить" -# Используется в нескольких местах: в 2 местах в значении расположения (шва и камеры), в одном – на кнопке "назад" (калибровка бамбу) +msgctxt "Navigation" msgid "Back" -msgstr "Сзади" +msgstr "Назад" msgid "Example" msgstr "Пример" @@ -5065,6 +5073,7 @@ msgstr "Смена инструмента" msgid "Color change" msgstr "Смена цвета" +msgctxt "Noun" msgid "Print" msgstr "Печать" @@ -5227,11 +5236,15 @@ msgstr "Избегать зону калибровки экструзии" msgid "Align to Y axis" msgstr "Выравнивать по оси Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Сзади" + +msgctxt "Camera View" msgid "Left" msgstr "Слева" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Справа" @@ -5589,6 +5602,10 @@ msgstr "Распечатать стол" msgid "Export G-code file" msgstr "Экспорт в G-код" +msgctxt "Verb" +msgid "Print" +msgstr "Печать" + msgid "Export plate sliced file" msgstr "Экспорт стола в файл проекта" @@ -15086,6 +15103,10 @@ msgstr "В углах" msgid "Aligned back" msgstr "В углах сзади" +# Используется в нескольких местах: в 2 местах в значении расположения (шва и камеры), в одном – на кнопке "назад" (калибровка бамбу) +msgid "Back" +msgstr "Сзади" + msgid "Random" msgstr "Случайная" @@ -20096,6 +20117,9 @@ msgstr "" "Предотвращение коробления материала\n" "Знаете ли вы, что при печати материалами, склонными к короблению, таких как ABS, повышение температуры подогреваемого стола может снизить эту вероятность?" +#~ msgid "Print" +#~ msgstr "Печать" + #~ msgid "in" #~ msgstr "дюйм" diff --git a/localization/i18n/sv/OrcaSlicer_sv.po b/localization/i18n/sv/OrcaSlicer_sv.po index 1f6843c487..0bbb793d5b 100644 --- a/localization/i18n/sv/OrcaSlicer_sv.po +++ b/localization/i18n/sv/OrcaSlicer_sv.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -324,6 +324,7 @@ msgstr "" msgid "Optimize orientation" msgstr "Optimisera placering" +msgctxt "Verb" msgid "Scale" msgstr "Skala" @@ -368,6 +369,9 @@ msgstr "Skalnings förhållande" msgid "Object operations" msgstr "Objekt Åtgärder" +msgid "Scale" +msgstr "Skala" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Volym Åtgärder" @@ -418,6 +422,10 @@ msgstr "" msgid "Reset current rotation to real zeros." msgstr "" +msgctxt "Noun" +msgid "Scale" +msgstr "Skala" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Storlek" @@ -3603,7 +3611,7 @@ msgstr "Kalibreringen klar. Vänligen hitta den mest enhetliga extruderingslinje msgid "Save" msgstr "Spara" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Tillbaka" @@ -4961,6 +4969,7 @@ msgstr "" msgid "Color change" msgstr "Färg byte" +msgctxt "Noun" msgid "Print" msgstr "Skriv ut" @@ -5120,11 +5129,15 @@ msgstr "Undvik kalibrerings området" msgid "Align to Y axis" msgstr "Justera mot Y-axeln" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Tillbaka" + +msgctxt "Camera View" msgid "Left" msgstr "Vänster" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Höger" @@ -5448,6 +5461,10 @@ msgstr "Skriv ut byggplattan" msgid "Export G-code file" msgstr "Exportera G-kod filen" +msgctxt "Verb" +msgid "Print" +msgstr "Skriv ut" + msgid "Export plate sliced file" msgstr "Exportera byggplattans beredda fil" @@ -14400,6 +14417,10 @@ msgstr "Linjerad" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Tillbaka" + msgid "Random" msgstr "Slumpmässig" @@ -19055,6 +19076,9 @@ msgstr "" "Undvik vridning\n" "Visste du att när du skriver ut material som är benägna att vrida, såsom ABS, kan en lämplig ökning av värmebäddens temperatur minska sannolikheten för vridning?" +#~ msgid "Print" +#~ msgstr "Skriv ut" + #~ msgid "in" #~ msgstr "i" @@ -20228,10 +20252,6 @@ msgstr "" #~ msgid "Thick bridges" #~ msgstr "Tjocka bridges" -#~ msgctxt "Verb" -#~ msgid "Scale" -#~ msgstr "Skala" - #~ msgid "Z-hop when retract" #~ msgstr "Z-hopp vid retraktion" diff --git a/localization/i18n/th/OrcaSlicer_th.po b/localization/i18n/th/OrcaSlicer_th.po index 3a4d12dd6b..0e1b189984 100644 --- a/localization/i18n/th/OrcaSlicer_th.po +++ b/localization/i18n/th/OrcaSlicer_th.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-06-19 13:40+0700\n" "Last-Translator: Icezaza\n" "Language-Team: Thai\n" @@ -324,6 +324,7 @@ msgstr "Gizmo-หมุน" msgid "Optimize orientation" msgstr "ปรับการวางแนวให้เหมาะสม" +msgctxt "Verb" msgid "Scale" msgstr "ปรับขนาด" @@ -367,6 +368,9 @@ msgstr "อัตราส่วนการปรับขนาด" msgid "Object operations" msgstr "การทำงานกับวัตถุ" +msgid "Scale" +msgstr "ปรับขนาด" + msgid "Volume operations" msgstr "การทำงานกับวอลลุ่ม" @@ -412,6 +416,10 @@ msgstr "รีเซ็ตการหมุนปัจจุบันเป็ msgid "Reset current rotation to real zeros." msgstr "รีเซ็ตการหมุนปัจจุบันให้เป็นศูนย์จริง" +msgctxt "Noun" +msgid "Scale" +msgstr "ปรับขนาด" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "ขนาด" @@ -3559,6 +3567,7 @@ msgstr "การสอบเทียบเสร็จสิ้น โปร msgid "Save" msgstr "บันทึก" +msgctxt "Navigation" msgid "Back" msgstr "กลับ" @@ -4907,6 +4916,7 @@ msgstr "การเปลี่ยนแปลงเครื่องมือ msgid "Color change" msgstr "เปลี่ยนสี" +msgctxt "Noun" msgid "Print" msgstr "พิมพ์" @@ -5066,11 +5076,15 @@ msgstr "หลีกเลี่ยงบริเวณการสอบเท msgid "Align to Y axis" msgstr "จัดแนวตามแกน Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "กลับ" + +msgctxt "Camera View" msgid "Left" msgstr "ซ้าย" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "ขวา" @@ -5393,6 +5407,10 @@ msgstr "พิมพ์ฐานพิมพ์" msgid "Export G-code file" msgstr "ส่งออกไฟล์ G-code" +msgctxt "Verb" +msgid "Print" +msgstr "พิมพ์" + msgid "Export plate sliced file" msgstr "ส่งออกไฟล์แผ่นสไลซ์บาง ๆ" @@ -14591,6 +14609,9 @@ msgstr "จัดตำแหน่ง" msgid "Aligned back" msgstr "จัดแนวกลับ" +msgid "Back" +msgstr "กลับ" + msgid "Random" msgstr "สุ่ม" @@ -19345,6 +19366,9 @@ msgstr "" "หลีกเลี่ยงการบิดเบี้ยว\n" "คุณรู้หรือไม่ว่าเมื่อพิมพ์วัสดุที่มีแนวโน้มที่จะเกิดการบิดเบี้ยว เช่น ABS การเพิ่มอุณหภูมิฐานพิมพ์อย่างเหมาะสมสามารถลดความน่าจะเป็นของการบิดเบี้ยวได้" +#~ msgid "Print" +#~ msgstr "พิมพ์" + #~ msgid "in" #~ msgstr "นิ้ว" diff --git a/localization/i18n/tr/OrcaSlicer_tr.po b/localization/i18n/tr/OrcaSlicer_tr.po index d879d550c5..163a45e2f4 100644 --- a/localization/i18n/tr/OrcaSlicer_tr.po +++ b/localization/i18n/tr/OrcaSlicer_tr.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-04-08 23:59+0300\n" "Last-Translator: GlauTech\n" "Language-Team: \n" @@ -327,6 +327,7 @@ msgstr "Gizmo-Döndür" msgid "Optimize orientation" msgstr "Yönü optimize edin" +msgctxt "Verb" msgid "Scale" msgstr "Ölçeklendir" @@ -371,6 +372,9 @@ msgstr "Ölçek oranları" msgid "Object operations" msgstr "Nesne İşlemleri" +msgid "Scale" +msgstr "Ölçeklendir" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Hacim İşlemleri" @@ -422,6 +426,10 @@ msgstr "Döndürme aracını açtığınızda mevcut döndürme değerini sıfı msgid "Reset current rotation to real zeros." msgstr "Mevcut dönüşü gerçek sıfırlara sıfırla." +msgctxt "Noun" +msgid "Scale" +msgstr "Ölçeklendir" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Boyut" @@ -3644,7 +3652,7 @@ msgstr "Kalibrasyon tamamlandı. Lütfen sıcak yatağınızdaki en düzgün eks msgid "Save" msgstr "Kaydet" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Arka" @@ -5027,6 +5035,7 @@ msgstr "Takım değişiklikleri" msgid "Color change" msgstr "Renk değişimi" +msgctxt "Noun" msgid "Print" msgstr "Yazdır" @@ -5190,11 +5199,15 @@ msgstr "Ekstrüzyon kalibrasyon bölgesinden kaçın" msgid "Align to Y axis" msgstr "Y eksenine hizala" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Arka" + +msgctxt "Camera View" msgid "Left" msgstr "Sol" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Sağ" @@ -5522,6 +5535,10 @@ msgstr "Plakayı Yazdır" msgid "Export G-code file" msgstr "G-kod dosyasını dışa aktar" +msgctxt "Verb" +msgid "Print" +msgstr "Yazdır" + msgid "Export plate sliced file" msgstr "Dilimlenmiş plaka dosyasını dışa aktar" @@ -14776,6 +14793,10 @@ msgstr "Hizalı" msgid "Aligned back" msgstr "Arkaya hizalı" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Arka" + msgid "Random" msgstr "Rastgele" @@ -19610,6 +19631,9 @@ msgstr "" "Eğilmeyi önleyin\n" "ABS gibi bükülmeye yatkın malzemelere baskı yaparken, ısıtma yatağı sıcaklığının uygun şekilde arttırılmasının bükülme olasılığını azaltabileceğini biliyor muydunuz?" +#~ msgid "Print" +#~ msgstr "Yazdır" + #~ msgid "in" #~ msgstr "in" diff --git a/localization/i18n/uk/OrcaSlicer_uk.po b/localization/i18n/uk/OrcaSlicer_uk.po index ab876dab5e..7de6f123b9 100644 --- a/localization/i18n/uk/OrcaSlicer_uk.po +++ b/localization/i18n/uk/OrcaSlicer_uk.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: orcaslicerua\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2025-03-07 09:30+0200\n" "Last-Translator: \n" "Language-Team: Ukrainian\n" @@ -332,6 +332,7 @@ msgstr "Gizmo обертання" msgid "Optimize orientation" msgstr "Оптимізувати орієнтацію" +msgctxt "Verb" msgid "Scale" msgstr "Масштаб" @@ -376,6 +377,9 @@ msgstr "Коефіцієнти масштабування" msgid "Object operations" msgstr "Операції з об'єктами" +msgid "Scale" +msgstr "Масштаб" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Операції з об’ємом" @@ -427,6 +431,10 @@ msgstr "Скинути поточне обертання до значення msgid "Reset current rotation to real zeros." msgstr "Скинути поточне обертання до нульових значень." +msgctxt "Noun" +msgid "Scale" +msgstr "Масштаб" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Розмір" @@ -3660,7 +3668,7 @@ msgstr "Калібрування завершено. Тепер знайдіть msgid "Save" msgstr "Зберегти" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Ззаду" @@ -5030,6 +5038,7 @@ msgstr "Зміна інструменту" msgid "Color change" msgstr "Зміна кольору" +msgctxt "Noun" msgid "Print" msgstr "Друк" @@ -5191,11 +5200,15 @@ msgstr "Уникайте області калібрування екструз msgid "Align to Y axis" msgstr "Розташувати вздовж осі Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Ззаду" + +msgctxt "Camera View" msgid "Left" msgstr "Ліво" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Право" @@ -5523,6 +5536,10 @@ msgstr "Друкувати пластину" msgid "Export G-code file" msgstr "Експорт файлу G-коду" +msgctxt "Verb" +msgid "Print" +msgstr "Друк" + msgid "Export plate sliced file" msgstr "Експортувати файл нарізки пластини" @@ -14753,6 +14770,10 @@ msgstr "Вирівняне" msgid "Aligned back" msgstr "" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Ззаду" + msgid "Random" msgstr "Випадкове" @@ -19554,6 +19575,9 @@ msgstr "" "Уникнення деформації\n" "Чи знаєте ви, що при друку матеріалами, схильними до деформації, такими як ABS, відповідне підвищення температури гарячого ліжка може зменшити ймовірність деформації?" +#~ msgid "Print" +#~ msgstr "Друк" + #~ msgid "in" #~ msgstr "в" diff --git a/localization/i18n/vi/OrcaSlicer_vi.po b/localization/i18n/vi/OrcaSlicer_vi.po index 42be9867cf..a25cc186c6 100644 --- a/localization/i18n/vi/OrcaSlicer_vi.po +++ b/localization/i18n/vi/OrcaSlicer_vi.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2025-10-02 17:43+0700\n" "Last-Translator: \n" "Language-Team: hainguyen.ts13@gmail.com\n" @@ -328,6 +328,7 @@ msgstr "Gizmo - Xoay" msgid "Optimize orientation" msgstr "Tối ưu định hướng" +msgctxt "Verb" msgid "Scale" msgstr "Tỷ lệ" @@ -372,6 +373,9 @@ msgstr "Tỷ lệ co giãn" msgid "Object operations" msgstr "Thao tác vật thể" +msgid "Scale" +msgstr "Tỷ lệ" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "Thao tác thể tích" @@ -423,6 +427,10 @@ msgstr "Đặt lại xoay hiện tại về giá trị khi mở công cụ xoay. msgid "Reset current rotation to real zeros." msgstr "Đặt lại xoay hiện tại về số không thực." +msgctxt "Noun" +msgid "Scale" +msgstr "Tỷ lệ" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "Kích thước" @@ -3630,7 +3638,7 @@ msgstr "Hiệu chỉnh hoàn tất. Vui lòng tìm đường đùn đồng đề msgid "Save" msgstr "Lưu" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "Sau" @@ -5001,6 +5009,7 @@ msgstr "" msgid "Color change" msgstr "Đổi màu" +msgctxt "Noun" msgid "Print" msgstr "In" @@ -5162,11 +5171,15 @@ msgstr "Tránh vùng hiệu chỉnh đùn" msgid "Align to Y axis" msgstr "Căn theo trục Y" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "Sau" + +msgctxt "Camera View" msgid "Left" msgstr "Trái" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "Phải" @@ -5490,6 +5503,10 @@ msgstr "In plate" msgid "Export G-code file" msgstr "Xuất file G-code" +msgctxt "Verb" +msgid "Print" +msgstr "In" + msgid "Export plate sliced file" msgstr "Xuất file plate đã slice" @@ -14668,6 +14685,10 @@ msgstr "Căn chỉnh" msgid "Aligned back" msgstr "Căn chỉnh sau" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "Sau" + msgid "Random" msgstr "Ngẫu nhiên" @@ -19475,6 +19496,9 @@ msgstr "" "Tránh cong vênh\n" "Bạn có biết rằng khi in vật liệu dễ cong vênh như ABS, tăng nhiệt độ bàn nóng một cách thích hợp có thể giảm xác suất cong vênh không?" +#~ msgid "Print" +#~ msgstr "In" + #~ msgid "in" #~ msgstr "in" diff --git a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po index eccc5752a3..d40c72b758 100644 --- a/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po +++ b/localization/i18n/zh_CN/OrcaSlicer_zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Slic3rPE\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2026-06-11 12:37-0300\n" "Last-Translator: Handle \n" "Language-Team: \n" @@ -330,6 +330,7 @@ msgstr "Gizmo-旋转" msgid "Optimize orientation" msgstr "优化朝向" +msgctxt "Verb" msgid "Scale" msgstr "缩放" @@ -374,6 +375,9 @@ msgstr "缩放比例" msgid "Object operations" msgstr "对象操作" +msgid "Scale" +msgstr "缩放" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "零件操作" @@ -425,6 +429,10 @@ msgstr "重置当前旋转为打开旋转工具时的值" msgid "Reset current rotation to real zeros." msgstr "重置当前旋转为真实零位" +msgctxt "Noun" +msgid "Scale" +msgstr "缩放" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "大小" @@ -3639,7 +3647,7 @@ msgstr "校准完成。如下图中的示例,请在您的热床上找到最均 msgid "Save" msgstr "保存" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "背面" @@ -5014,6 +5022,7 @@ msgstr "工具更换" msgid "Color change" msgstr "颜色更换" +msgctxt "Noun" msgid "Print" msgstr "打印" @@ -5178,11 +5187,15 @@ msgstr "避开挤出校准区域" msgid "Align to Y axis" msgstr "对齐到Y轴" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "背面" + +msgctxt "Camera View" msgid "Left" msgstr "左" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "右" @@ -5510,6 +5523,10 @@ msgstr "打印单盘" msgid "Export G-code file" msgstr "导出G-code文件" +msgctxt "Verb" +msgid "Print" +msgstr "打印" + msgid "Export plate sliced file" msgstr "导出单盘切片文件" @@ -14896,6 +14913,10 @@ msgstr "对齐" msgid "Aligned back" msgstr "背部对齐" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "背面" + msgid "Random" msgstr "随机" @@ -19737,6 +19758,9 @@ msgstr "" "避免翘曲\n" "您知道吗?打印ABS这类易翘曲材料时,适当提高热床温度可以降低翘曲的概率。" +#~ msgid "Print" +#~ msgstr "打印" + #~ msgid "in" #~ msgstr "在" diff --git a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po index 1c8f7b256a..2dad906eff 100644 --- a/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po +++ b/localization/i18n/zh_TW/OrcaSlicer_zh_TW.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Orca Slicer\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-07-07 10:05-0300\n" +"POT-Creation-Date: 2026-07-07 16:46-0300\n" "PO-Revision-Date: 2025-11-28 13:48-0600\n" "Last-Translator: tntchn <15895303+tntchn@users.noreply.github.com>\n" "Language-Team: \n" @@ -333,6 +333,7 @@ msgstr "Gizmo-旋轉" msgid "Optimize orientation" msgstr "最佳化方向" +msgctxt "Verb" msgid "Scale" msgstr "縮放" @@ -377,6 +378,9 @@ msgstr "縮放比例" msgid "Object operations" msgstr "物件操作" +msgid "Scale" +msgstr "縮放" + # TODO: Review, changed by lang refactor. PR 14254 msgid "Volume operations" msgstr "零件操作" @@ -428,6 +432,10 @@ msgstr "重設旋轉角度為開啟旋轉工具時的狀態。" msgid "Reset current rotation to real zeros." msgstr "將旋轉角度歸零" +msgctxt "Noun" +msgid "Scale" +msgstr "縮放" + #. TRN - Input label. Be short as possible msgid "Size" msgstr "尺寸" @@ -3650,7 +3658,7 @@ msgstr "校正完成。如下圖中的範例,請在您的熱床上找到最均 msgid "Save" msgstr "儲存" -# TODO: Review, changed by lang refactor. PR 14254 +msgctxt "Navigation" msgid "Back" msgstr "背面" @@ -5056,6 +5064,7 @@ msgstr "取代工具" msgid "Color change" msgstr "顏色更換" +msgctxt "Noun" msgid "Print" msgstr "列印" @@ -5220,11 +5229,15 @@ msgstr "避開擠出校正區域" msgid "Align to Y axis" msgstr "與 Y 軸對齊" -msgctxt "Camera" +msgctxt "Camera View" +msgid "Back" +msgstr "背面" + +msgctxt "Camera View" msgid "Left" msgstr "左" -msgctxt "Camera" +msgctxt "Camera View" msgid "Right" msgstr "右" @@ -5553,6 +5566,10 @@ msgstr "列印單一列印板" msgid "Export G-code file" msgstr "匯出 G-code 檔案" +msgctxt "Verb" +msgid "Print" +msgstr "列印" + msgid "Export plate sliced file" msgstr "匯出單一列印板切片檔案" @@ -14957,6 +14974,10 @@ msgstr "對齊" msgid "Aligned back" msgstr "背部對齊" +# TODO: Review, changed by lang refactor. PR 14254 +msgid "Back" +msgstr "背面" + msgid "Random" msgstr "隨機" @@ -19808,6 +19829,9 @@ msgstr "" "您知道嗎?當列印容易翹曲的材料(如 ABS)時,適當提高熱床溫度\n" "可以降低翹曲的機率。" +#~ msgid "Print" +#~ msgstr "列印" + #~ msgid "in" #~ msgstr "在" diff --git a/src/slic3r/GUI/ExtrusionCalibration.cpp b/src/slic3r/GUI/ExtrusionCalibration.cpp index 28255f37e4..cd3f49e977 100644 --- a/src/slic3r/GUI/ExtrusionCalibration.cpp +++ b/src/slic3r/GUI/ExtrusionCalibration.cpp @@ -239,7 +239,7 @@ void ExtrusionCalibration::create() m_button_save_result->SetStyle(ButtonStyle::Confirm, ButtonType::Choice); m_button_save_result->Bind(wxEVT_BUTTON, &ExtrusionCalibration::on_click_save, this); - m_button_last_step = new Button(m_step_2_panel, _L("Back")); // Back for english + m_button_last_step = new Button(m_step_2_panel, _CTX("Back", "Navigation")); // Back for english m_button_last_step->SetStyle(ButtonStyle::Regular, ButtonType::Choice); m_button_last_step->Bind(wxEVT_BUTTON, &ExtrusionCalibration::on_click_last, this); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 150a40dc0d..bb9de4976f 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4258,7 +4258,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv }; auto append_print = [&imgui, imperial_units](const ColorRGBA& color, const std::array& offsets, const Times& times, std::pair used_filament) { - imgui.text(_u8L("Print")); + imgui.text(_CTX_utf8("Print", "Noun")); ImGui::SameLine(); float icon_size = ImGui::GetTextLineHeight(); @@ -4292,7 +4292,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv for (const PartialTime& item : partial_times) { switch (item.type) { - case PartialTime::EType::Print: { labels.push_back(_u8L("Print")); break; } + case PartialTime::EType::Print: { labels.push_back(_CTX_utf8("Print", "Noun")); break; } case PartialTime::EType::Pause: { labels.push_back(_u8L("Pause")); break; } case PartialTime::EType::ColorChange: { labels.push_back(_u8L("Color change")); break; } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4237632393..c250d96f44 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6036,11 +6036,11 @@ void GLCanvas3D::_render_3d_navigator() strcpy(style.AxisLabels[ImGuizmo::Axis::Axis_Y], "Z"); // ORCA use uppercase to match text on tranform widgets strcpy(style.AxisLabels[ImGuizmo::Axis::Axis_Z], "X"); // ORCA use uppercase to match text on tranform widgets strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_FRONT], _utf8("Front").c_str()); - strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_BACK], _utf8("Back").c_str()); + strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_BACK], _CTX_utf8("Back", "Camera View").c_str()); strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_TOP], _utf8("Top").c_str()); strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_BOTTOM], _utf8("Bottom").c_str()); - strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_LEFT], _CTX_utf8(L_CONTEXT("Left", "Camera"), "Camera").c_str()); - strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_RIGHT], _CTX_utf8(L_CONTEXT("Right", "Camera"), "Camera").c_str()); + strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_LEFT], _CTX_utf8("Left", "Camera View").c_str()); + strcpy(style.FaceLabels[ImGuizmo::FACES::FACE_RIGHT], _CTX_utf8("Right", "Camera View").c_str()); float sc = get_scale(); #ifdef WIN32 diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 218a67890b..a99b68340d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1303,7 +1303,7 @@ void GLGizmoMeasure::render_dimensioning() return; const double ratio = new_value / old_value; - wxGetApp().plater()->take_snapshot(_u8L("Scale"), UndoRedo::SnapshotType::GizmoAction); + wxGetApp().plater()->take_snapshot(_CTX_utf8("Scale", "Verb"), UndoRedo::SnapshotType::GizmoAction); // apply scale TransformationType type; type.set_world(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 77fc7ef46c..ebbb76f348 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -143,9 +143,9 @@ bool GLGizmoScale3D::on_init() std::string GLGizmoScale3D::on_get_name() const { if (!on_is_activable() && m_state == EState::Off) { - return _u8L("Scale") + ":\n" + _u8L("Please select at least one object."); + return _CTX_utf8("Scale", "Verb") + ":\n" + _u8L("Please select at least one object."); } else { - return _u8L("Scale"); + return _CTX_utf8("Scale", "Verb"); } } diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp index 5297f95c82..3f82777a2a 100644 --- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp +++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp @@ -1161,7 +1161,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w imgui_wrapper->calc_text_size(_L("Part")).x }) + imgui_wrapper->calc_text_size("xxx"sv).x + imgui_wrapper->scaled(3.5f); float label_max = std::max({ - imgui_wrapper->calc_text_size(_L("Scale")).x, + imgui_wrapper->calc_text_size(_CTX("Scale", "Noun")).x, imgui_wrapper->calc_text_size(_L("Size")).x }); float caption_max = std::max(label_max, coord_combo_width - 3 * space_size); @@ -1218,7 +1218,7 @@ void GizmoObjectManipulation::do_render_scale_input_window(ImGuiWrapper* imgui_w //ImGui::PushItemWidth(unit_size * 2); ImGui::AlignTextToFramePadding(); - imgui_wrapper->text(_L("Scale")); + imgui_wrapper->text(_CTX("Scale", "Noun")); ImGui::SameLine(caption_max + space_size); ImGui::PushItemWidth(unit_size); ImGui::BBLInputDouble(label_scale_values[0][0], &scale[0], 0.0f, 0.0f, "%.2f"); diff --git a/src/slic3r/GUI/ImageGrid.cpp b/src/slic3r/GUI/ImageGrid.cpp index 77fd7b132e..3c333c93fb 100644 --- a/src/slic3r/GUI/ImageGrid.cpp +++ b/src/slic3r/GUI/ImageGrid.cpp @@ -644,7 +644,7 @@ void Slic3r::GUI::ImageGrid::renderContent1(wxDC &dc, wxPoint const &pt, int ind if (m_file_sys->GetFileType() == PrinterFileSystem::F_MODEL) { if (secondAction != _L("Play")) thirdAction = secondAction; - secondAction = _L("Print"); + secondAction = _CTX("Print", "Verb"); } // Draw buttons on hovered item wxRect rect{pt.x, pt.y + m_content_rect.GetBottom() - m_buttons_background.GetHeight(), m_content_rect.GetWidth(), m_buttons_background.GetHeight()}; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 66d7d87835..c2753f0bb1 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -2013,10 +2013,10 @@ wxBoxSizer* MainFrame::create_side_tools() }); // upload and print - SideButton* send_gcode_btn = new SideButton(p, _L("Print"), ""); + SideButton* send_gcode_btn = new SideButton(p, _CTX("Print", "Verb"), ""); send_gcode_btn->SetCornerRadius(0); send_gcode_btn->Bind(wxEVT_BUTTON, [this, p](wxCommandEvent&) { - m_print_btn->SetLabel(_L("Print")); + m_print_btn->SetLabel(_CTX("Print", "Verb")); m_print_select = eSendGcode; m_print_enable = get_enable_print_status(); m_print_btn->Enable(m_print_enable); @@ -2662,9 +2662,9 @@ static void add_common_view_menu_items(wxMenu* view_menu, MainFrame* mainFrame, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); append_menu_item(view_menu, wxID_ANY, _L("Rear") + "\t" + ctrl + "4", _L("Rear View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("rear"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); - append_menu_item(view_menu, wxID_ANY, _CTX(L_CONTEXT("Left", "Camera"), "Camera") + "\t" + ctrl + "5", _L("Left View"),[mainFrame](wxCommandEvent &) {mainFrame->select_view("left"); }, + append_menu_item(view_menu, wxID_ANY, _CTX("Left", "Camera View") + "\t" + ctrl + "5", _L("Left View"),[mainFrame](wxCommandEvent &) {mainFrame->select_view("left"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); - append_menu_item(view_menu, wxID_ANY, _CTX(L_CONTEXT("Right", "Camera"), "Camera") + "\t" + ctrl + "6", _L("Right View"),[mainFrame](wxCommandEvent &) { mainFrame->select_view("right"); }, + append_menu_item(view_menu, wxID_ANY, _CTX("Right", "Camera View") + "\t" + ctrl + "6", _L("Right View"),[mainFrame](wxCommandEvent &) { mainFrame->select_view("right"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); } @@ -4040,7 +4040,7 @@ void MainFrame::set_print_button_to_default(PrintSelectType select_type) m_print_btn->Enable(m_print_enable); this->Layout(); } else if (select_type == PrintSelectType::eSendGcode) { - m_print_btn->SetLabel(_L("Print")); + m_print_btn->SetLabel(_CTX("Print", "Verb")); m_print_select = eSendGcode; if (m_print_enable) m_print_enable = get_enable_print_status() && can_send_gcode(); diff --git a/src/slic3r/GUI/MediaFilePanel.cpp b/src/slic3r/GUI/MediaFilePanel.cpp index 1fca47e7c4..84ba61d9d4 100644 --- a/src/slic3r/GUI/MediaFilePanel.cpp +++ b/src/slic3r/GUI/MediaFilePanel.cpp @@ -556,7 +556,7 @@ void MediaFilePanel::doAction(size_t index, int action) } else if (action == 1) { if (fs->GetFileType() == PrinterFileSystem::F_MODEL) { if (index != -1) { - auto dlg = new MediaProgressDialog(_L("Print"), this, [fs] { fs->FetchModelCancel(); }); + auto dlg = new MediaProgressDialog(_CTX("Print", "Verb"), this, [fs] { fs->FetchModelCancel(); }); dlg->Update(0, _L("Fetching model information...")); fs->FetchModel(index, [this, fs, dlg, index](int result, std::string const &data) { dlg->Destroy(); @@ -566,7 +566,7 @@ void MediaFilePanel::doAction(size_t index, int action) wxString msg = data.empty() ? _L("Failed to fetch model information from printer.") : from_u8(data); CallAfter([this, msg] { - MessageDialog(this, msg, _L("Print"), wxOK).ShowModal(); + MessageDialog(this, msg, _CTX("Print", "Verb"), wxOK).ShowModal(); }); return; } @@ -579,7 +579,7 @@ void MediaFilePanel::doAction(size_t index, int action) || plate_data_list.empty()) { MessageDialog(this, _L("Failed to parse model information."), - _L("Print"), wxOK).ShowModal(); + _CTX("Print", "Verb"), wxOK).ShowModal(); return; } diff --git a/src/slic3r/GUI/SelectMachine.cpp b/src/slic3r/GUI/SelectMachine.cpp index 09314d3b49..9fd0a65087 100644 --- a/src/slic3r/GUI/SelectMachine.cpp +++ b/src/slic3r/GUI/SelectMachine.cpp @@ -138,7 +138,7 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater) /*mode switch*/ /*auto m_sizer_mode_switch = new wxBoxSizer(wxHORIZONTAL); - m_mode_print = new SendModeSwitchButton(scroll_area, _L("Print"), true); + m_mode_print = new SendModeSwitchButton(scroll_area, _CTX("Print", "Verb"), true); m_mode_send = new SendModeSwitchButton(scroll_area,_L("Save to printer"), false); m_sizer_mode_switch->Add(m_mode_print, 0, wxALIGN_CENTER, 0); m_sizer_mode_switch->Add(0, 0, 0, wxLEFT, FromDIP(8)); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 52537d9331..f1eb41b0b4 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -7677,7 +7677,7 @@ bool Tab::validate_filament_temperature_pairs() RichMessageDialog dialog(parent(), msg_text, _L("Temperature Safety Check"), wxYES | wxNO | wxICON_WARNING); dialog.SetButtonLabel(wxID_YES, _L("Continue"), true); - dialog.SetButtonLabel(wxID_NO, _L("Back")); + dialog.SetButtonLabel(wxID_NO, _CTX("Back", "Navigation")); dialog.ShowCheckBox(_L("Don't warn again for this preset")); const int answer = dialog.ShowModal(); // Session-only suppression (does not modify/save filament preset data). diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 20ed70e799..d10eaedef5 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -47,7 +47,7 @@ WebViewPanel::WebViewPanel(wxWindow *parent) // Create the button bSizer_toolbar = new wxBoxSizer(wxHORIZONTAL); - m_button_back = new wxButton(this, wxID_ANY, _L("Back"), wxDefaultPosition, wxDefaultSize, 0); + m_button_back = new wxButton(this, wxID_ANY, _CTX("Back", "Navigation"), wxDefaultPosition, wxDefaultSize, 0); m_button_back->Enable(false); bSizer_toolbar->Add(m_button_back, 0, wxALL, 5); From cab62070b5239e52bb51e5abdafea76b5a67bda3 Mon Sep 17 00:00:00 2001 From: anjis Date: Wed, 8 Jul 2026 20:24:55 +0800 Subject: [PATCH 032/130] Fix garbled Chinese filenames when importing ZIP files. (#14633) * Fix garbled Chinese filenames when importing ZIP files. * fix: avoid repeated ZIP path CRC calculation --- src/libslic3r/miniz_extension.cpp | 39 ++++++++++++++++++++++++++++ src/libslic3r/miniz_extension.hpp | 1 + src/slic3r/GUI/FileArchiveDialog.cpp | 11 +------- src/slic3r/GUI/Plater.cpp | 10 +------ 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/miniz_extension.cpp b/src/libslic3r/miniz_extension.cpp index 424e76462c..53a4a8e9de 100644 --- a/src/libslic3r/miniz_extension.cpp +++ b/src/libslic3r/miniz_extension.cpp @@ -1,6 +1,8 @@ #include +#include #include "miniz_extension.hpp" +#include "Utils.hpp" #if defined(_MSC_VER) || defined(__MINGW64__) #include "boost/nowide/cstdio.hpp" @@ -15,6 +17,33 @@ namespace Slic3r { namespace { +std::string decode_zip_unicode_path_extra_field(const std::string& extra, const std::string& path) +{ + size_t offset = 0; + const mz_uint32 path_crc = mz_crc32(0, reinterpret_cast(path.data()), path.size()); + + while (offset + 4 <= extra.size()) { + const unsigned char* field = reinterpret_cast(extra.data() + offset); + const std::uint16_t len = field[2] | (static_cast(field[3]) << 8); + if (offset + 4 + len > extra.size()) + break; + + if (field[0] == 0x75 && field[1] == 0x70 && len >= 5 && field[4] == 0x01) { + const mz_uint32 stored_crc = + static_cast(field[5]) | + (static_cast(field[6]) << 8) | + (static_cast(field[7]) << 16) | + (static_cast(field[8]) << 24); + if (stored_crc == path_crc) + return std::string(extra.data() + offset + 9, extra.data() + offset + 4 + len); + } + + offset += 4 + len; + } + + return Slic3r::decode_path(path.c_str()); +} + bool open_zip(mz_zip_archive *zip, const char *fname, bool isread) { if (!zip) return false; @@ -76,6 +105,16 @@ bool open_zip_writer(mz_zip_archive *zip, const std::string &fname) bool close_zip_reader(mz_zip_archive *zip) { return close_zip(zip, true); } bool close_zip_writer(mz_zip_archive *zip) { return close_zip(zip, false); } +std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat) +{ + if (stat.m_is_utf8) + return stat.m_filename; + + std::string extra(1024, 0); + const size_t extra_size = mz_zip_reader_get_extra(zip, stat.m_file_index, extra.data(), extra.size()); + return decode_zip_unicode_path_extra_field(extra.substr(0, extra_size > 0 ? extra_size - 1 : 0), stat.m_filename); +} + MZ_Archive::MZ_Archive() { mz_zip_zero_struct(&arch); diff --git a/src/libslic3r/miniz_extension.hpp b/src/libslic3r/miniz_extension.hpp index 006226bf24..1a1c96689f 100644 --- a/src/libslic3r/miniz_extension.hpp +++ b/src/libslic3r/miniz_extension.hpp @@ -10,6 +10,7 @@ bool open_zip_reader(mz_zip_archive *zip, const std::string &fname_utf8); bool open_zip_writer(mz_zip_archive *zip, const std::string &fname_utf8); bool close_zip_reader(mz_zip_archive *zip); bool close_zip_writer(mz_zip_archive *zip); +std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat); class MZ_Archive { public: diff --git a/src/slic3r/GUI/FileArchiveDialog.cpp b/src/slic3r/GUI/FileArchiveDialog.cpp index 18c804196f..982187211c 100644 --- a/src/slic3r/GUI/FileArchiveDialog.cpp +++ b/src/slic3r/GUI/FileArchiveDialog.cpp @@ -221,16 +221,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar std::vector> filtered_entries; // second is unzipped size for (mz_uint i = 0; i < num_entries; ++i) { if (mz_zip_reader_file_stat(archive, i, &stat)) { - std::string extra(1024, 0); - boost::filesystem::path path; - size_t extra_size = mz_zip_reader_get_filename_from_extra(archive, i, extra.data(), extra.size()); - if (extra_size > 0) { - path = boost::filesystem::path(extra.substr(0, extra_size)); - } else { - wxString wname = boost::nowide::widen(stat.m_filename); - std::string name = into_u8(wname); - path = boost::filesystem::path(name); - } + boost::filesystem::path path = Slic3r::decode_archive_entry_path(archive, stat); assert(!path.empty()); if (!path.has_extension()) continue; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 26b9217b3f..584386d984 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -13923,17 +13923,9 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path) if (mz_zip_reader_file_stat(&archive, i, &stat)) { if (size != stat.m_uncomp_size) // size must fit continue; - wxString wname = boost::nowide::widen(stat.m_filename); - std::string name = into_u8(wname); + std::string name = Slic3r::decode_archive_entry_path(&archive, stat); fs::path archive_path(name); - std::string extra(1024, 0); - size_t extra_size = mz_zip_reader_get_filename_from_extra(&archive, i, extra.data(), extra.size()); - if (extra_size > 0) { - archive_path = fs::path(extra.substr(0, extra_size)); - name = archive_path.string(); - } - if (archive_path.empty()) continue; if (path != archive_path) From cf86f20ae10a5df3bac275cadb56c5e990aad72b Mon Sep 17 00:00:00 2001 From: anjis Date: Wed, 8 Jul 2026 20:48:32 +0800 Subject: [PATCH 033/130] Improve filament change time estimation for CC & CC2 printers and add purge length statistics. (#14663) * Improve filament change time estimation for CC & CC2 printers and add purge length statistics. * fix(gcode): route elegoo M6211 handling --- src/libslic3r/CMakeLists.txt | 1 + .../GCode/ElegooGCodeProcessorHelper.cpp | 190 ++++++++++++++++++ src/libslic3r/GCode/GCodeProcessor.cpp | 14 +- src/libslic3r/GCode/GCodeProcessor.hpp | 5 + 4 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 93946ca477..01c1a0636b 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -221,6 +221,7 @@ set(lisbslic3r_sources GCode/FanMover.hpp GCode/GCodeProcessor.cpp GCode/GCodeProcessor.hpp + GCode/ElegooGCodeProcessorHelper.cpp GCode.hpp GCode/PchipInterpolatorHelper.cpp GCode/PchipInterpolatorHelper.hpp diff --git a/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp b/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp new file mode 100644 index 0000000000..cac53637a5 --- /dev/null +++ b/src/libslic3r/GCode/ElegooGCodeProcessorHelper.cpp @@ -0,0 +1,190 @@ +#include "GCodeProcessor.hpp" + +#include "libslic3r/libslic3r.h" + +#include +#include +#include +#include + +namespace Slic3r { +namespace { + +bool equals_case_insensitive(std::string_view lhs, std::string_view rhs) +{ + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), [](unsigned char l, unsigned char r) { + return std::tolower(l) == std::tolower(r); + }); +} + +float get_clamped_param(const GCodeReader::GCodeLine& line, char axis, float default_value, float min_value, float max_value) +{ + float value = default_value; + line.has_value(axis, value); + return std::clamp(value, min_value, max_value); +} + +float extrusion_time(float e_length, float feedrate) +{ + return feedrate > 0.0f && e_length > 0.0f ? e_length / feedrate * 60.0f : 0.0f; +} + +float retract_time(float e_length) +{ + static constexpr float retract_feedrate = 1800.0f; + return extrusion_time(std::max(e_length, 0.0f), retract_feedrate); +} + +float s819_time(float e_length, float feedrate) +{ + static constexpr float s819_tail_flush_length = 10.0f; + static constexpr float s819_tail_feedrate = 400.0f; + + const float tail_length = std::min(std::max(e_length, 0.0f), s819_tail_flush_length); + const float main_length = std::max(e_length - tail_length, 0.0f); + return extrusion_time(main_length, feedrate) + extrusion_time(tail_length, s819_tail_feedrate); +} + +float estimate_M6211_time_for_centauri_carbon(const GCodeReader::GCodeLine& line, float length, double current_x, + double current_y) +{ + static constexpr float max_segment_length = 73.0f; + static constexpr float wipe_after_flush_time = 2.8f; + static constexpr float main_feedrate = 500.0f; + static constexpr float tail_feedrate = 400.0f; + static constexpr float travel_feedrate = 5000.0f; + static constexpr double parking_x = 256.0; + static constexpr double parking_y = 0.0; + + const float flush_length = std::clamp(length, 10.0f, 1000.0f); + const float cool_time = get_clamped_param(line, 'P', 5000.0f, 0.0f, 20000.0f) * 0.001f; + const float travel_time = static_cast(std::abs(current_y - parking_y) + std::abs(current_x - parking_x)) / + travel_feedrate * 60.0f; + + // Initial time, including: material change, heating, etc. + float m6211_time = 18.2f + travel_time; + + float remaining_flush_length = std::max(flush_length, 0.0f); + while (remaining_flush_length > 0.0f) { + const float segment_length = std::min(remaining_flush_length, max_segment_length); + remaining_flush_length -= segment_length; + if (segment_length >= max_segment_length) { + // Full segment: 3-phase extrusion (30+35+10=75mm) + retract + m6211_time += extrusion_time(30.0f, main_feedrate) + extrusion_time(35.0f, main_feedrate) + + extrusion_time(10.0f, tail_feedrate) + extrusion_time(2.0f, tail_feedrate) + cool_time + + wipe_after_flush_time; + } else { + // Partial last segment: simple extrude at F500 + retract at F400 + m6211_time += extrusion_time(segment_length, main_feedrate) + extrusion_time(2.0f, tail_feedrate) + cool_time + + wipe_after_flush_time; + } + } + + return m6211_time; +} + +float estimate_M6211_time_for_centauri_carbon_2(const GCodeReader::GCodeLine& line, float length, float new_extruder_temp) +{ + const float flush_length = std::clamp(length, 10.0f, 1000.0f); + const float flush_length_single = get_clamped_param(line, 'K', 75.0f, 10.0f, 300.0f); + const float old_filament_e_feedrate = get_clamped_param(line, 'M', 300.0f, 10.0f, 600.0f); + const float new_filament_e_feedrate = get_clamped_param(line, 'N', 300.0f, 10.0f, 600.0f); + const float cool_time = get_clamped_param(line, 'P', 3000.0f, 0.0f, 20000.0f) * 0.001f; + + // The flush length of the old material, unit: mm + static constexpr float e_flush_dist = 15.0f; + // Wipe time after flush, in seconds + static constexpr float wipe_after_flush_time = 5.0f; + + const float flush_length_after_start = std::max(flush_length - e_flush_dist, 0.0f); + const int flush_times = std::max(1, static_cast(std::ceil(flush_length_after_start / flush_length_single))); + const float flush_length_actual = flush_length_single; + + // Initial time, including: material change, heating, moving, etc. + float m6211_time = 31.0f; + m6211_time += extrusion_time(std::min(e_flush_dist, flush_length), old_filament_e_feedrate); + + const int intermediate_flush_times = flush_times - 1; + const float intermediate_flush_time = s819_time(flush_length_actual, new_filament_e_feedrate) + retract_time(6.0f) + cool_time + + wipe_after_flush_time; + m6211_time += static_cast(intermediate_flush_times) * intermediate_flush_time; + m6211_time += s819_time(flush_length_actual, new_filament_e_feedrate * 0.8f) + retract_time(4.0f) + cool_time + wipe_after_flush_time; + + static constexpr float cooling_rate = 1.36f; + const float r_temp = get_clamped_param(line, 'R', new_extruder_temp + 20.0f, 185.0f, 350.0f); + const float s_temp = get_clamped_param(line, 'S', 250.0f, 185.0f, 350.0f); + + if (s_temp < r_temp) + m6211_time += (r_temp - s_temp) / cooling_rate; + + return m6211_time; +} + +float estimate_M6211_time(const GCodeReader::GCodeLine& line, std::string_view printer_model, float length, float new_extruder_temp, double current_x, double current_y) +{ + if (equals_case_insensitive(printer_model, "Elegoo Centauri Carbon") || equals_case_insensitive(printer_model, "Elegoo Centauri")) { + return estimate_M6211_time_for_centauri_carbon(line, length, current_x, current_y); + } else if (equals_case_insensitive(printer_model, "Elegoo Centauri Carbon 2") || + equals_case_insensitive(printer_model, "Elegoo Centauri 2")) { + return estimate_M6211_time_for_centauri_carbon_2(line, length, new_extruder_temp); + } + return 0.0f; +} + +} // namespace + +void GCodeProcessor::process_elegoo_M6211(const GCodeReader::GCodeLine& line) +{ + float length = 0.0f; + if (!line.has_value('L', length) || length <= 0.0f) + return; + + float t = -1.0f; + if (!line.has_value('T', t) || t < 0.0f) + return; + + const int filament_id = static_cast(std::round(t)); + if (filament_id < 0 || filament_id >= m_result.filaments_count) + return; + + const int extruder_id = m_filament_maps[filament_id]; + + float new_extruder_temp = 0.0f; + if (line.has_value('S', new_extruder_temp)) { + if (extruder_id >= 0 && static_cast(extruder_id) < m_extruder_temps.size()) + m_extruder_temps[static_cast(extruder_id)] = new_extruder_temp; + } + + const float m6211_time = estimate_M6211_time(line, m_printer_model, length, new_extruder_temp, + m_start_position[X], m_start_position[Y]); + const int curr_filament_id = get_filament_id(false); + const bool is_first_extrusion = (curr_filament_id == -1) || (filament_id == curr_filament_id); + + m_time_processor.filament_unload_times = 0; + m_time_processor.filament_load_times = m6211_time; + process_filament_change(filament_id); + + if (extruder_id >= 0 && static_cast(extruder_id) < m_remaining_volume.size()) { + const float remaining_volume = static_cast(extruder_id) < m_nozzle_volume.size() ? + m_nozzle_volume[extruder_id] : + 0.0f; + const float filament_diameter = static_cast(filament_id) < m_result.filament_diameters.size() ? + m_result.filament_diameters[filament_id] : + m_result.filament_diameters.back(); + const float area_filament_cross_section = static_cast(M_PI) * sqr(0.5f * filament_diameter); + const float volume_flushed_filament = area_filament_cross_section * length; + + if (volume_flushed_filament >= remaining_volume) { + if (!is_first_extrusion) + m_used_filaments.update_flush_per_filament(curr_filament_id, remaining_volume); + + m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament - remaining_volume); + m_remaining_volume[extruder_id] = 0.0f; + } else { + m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament); + m_remaining_volume[extruder_id] -= volume_flushed_filament; + } + } +} + +} // namespace Slic3r diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 44cb185aec..c0a92780c4 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1839,7 +1839,8 @@ void GCodeProcessor::register_commands() {"VM104", [this](const GCodeReader::GCodeLine& line) { process_VM104(line); }}, {"VM109", [this](const GCodeReader::GCodeLine& line) { process_VM109(line); }}, {"M622", [this](const GCodeReader::GCodeLine& line) { process_M622(line);}}, - {"M623", [this](const GCodeReader::GCodeLine& line) { process_M623(line);}} + {"M623", [this](const GCodeReader::GCodeLine& line) { process_M623(line);}}, + {"M6211", [this](const GCodeReader::GCodeLine& line) { process_M6211(line); }} }; std::unordered_setearly_quit_commands = { @@ -1863,6 +1864,12 @@ void GCodeProcessor::register_commands() } } +void GCodeProcessor::process_M6211(const GCodeReader::GCodeLine& line) +{ + if (boost::algorithm::istarts_with(m_printer_model, "elegoo")) + process_elegoo_M6211(line); +} + bool GCodeProcessor::check_multi_extruder_gcode_valid(const int extruder_size, const Pointfs plate_printable_area, const double plate_printable_height, @@ -2027,6 +2034,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_parser.apply_config(config); m_flavor = config.gcode_flavor; + m_printer_model = config.printer_model.value; m_single_extruder_multi_material = config.single_extruder_multi_material; @@ -2213,6 +2221,10 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (printer_settings_id != nullptr) m_result.settings_ids.printer = printer_settings_id->value; + const ConfigOptionString* printer_model = config.option("printer_model"); + if (printer_model != nullptr) + m_printer_model = printer_model->value; + // BBS m_result.filaments_count = config.option("filament_diameter")->values.size(); diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 1d2e0890da..fcefd1a9a7 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -846,6 +846,7 @@ class Print; float m_preheat_time; int m_preheat_steps; bool m_disable_m73; + std::string m_printer_model; enum class EProducer { @@ -1084,6 +1085,10 @@ class Print; // Unload the current filament into the MK3 MMU2 unit at the end of print. void process_M702(const GCodeReader::GCodeLine& line); + //Used for Elegoo printer to change tool head + void process_M6211(const GCodeReader::GCodeLine& line); + void process_elegoo_M6211(const GCodeReader::GCodeLine& line); + void process_SYNC(const GCodeReader::GCodeLine& line); // Processes T line (Select Tool) From dec67345be66a17075d7bfbd35f9e49699ed10a4 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Wed, 8 Jul 2026 07:58:39 -0500 Subject: [PATCH 034/130] fix: prevent out-of-bounds crash in Arachne beading interpolation (#14656) * fix: prevent out-of-bounds crash in Arachne beading interpolation SkeletalTrapezoidation::interpolate() derives an inset index from `left` but uses it to index the merged beading, which follows the thicker of left/right. When the thicker side has fewer insets, the index runs past the end and the slicer crashes during "Generating walls". Skip the adjustment when the index is out of range, as the adjacent guards already do. interpolate() uses no instance state, so make it static and add a regression test that exercises it directly. Fixes #14584 --- .../Arachne/SkeletalTrapezoidation.cpp | 10 ++++- .../Arachne/SkeletalTrapezoidation.hpp | 4 +- tests/libslic3r/test_arachne_walls.cpp | 44 +++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp index 2d2cf9896d..da5c7357c1 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp @@ -1660,7 +1660,7 @@ void SkeletalTrapezoidation::propagateBeadingsDownward(edge_t* edge_to_peak, ptr } -SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right, coord_t switching_radius) const +SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right, coord_t switching_radius) { assert(ratio_left_to_whole >= 0.0 && ratio_left_to_whole <= 1.0); Beading ret = interpolate(left, ratio_left_to_whole, right); @@ -1684,6 +1684,12 @@ SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beadin { // We cant adjust to fit the next edge because there is no previous one?! return ret; } + // ret follows the thicker of left/right, which can hold fewer insets than left when bead + // count and thickness disagree; skip the adjustment rather than index ret past its end. + if (next_inset_idx >= coord_t(ret.toolpath_locations.size())) + { + return ret; + } assert(next_inset_idx < coord_t(left.toolpath_locations.size())); assert(left.toolpath_locations[next_inset_idx] <= switching_radius); assert(left.toolpath_locations[next_inset_idx + 1] >= switching_radius); @@ -1703,7 +1709,7 @@ SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beadin } -SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right) const +SkeletalTrapezoidation::Beading SkeletalTrapezoidation::interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right) { assert(ratio_left_to_whole >= 0.0 && ratio_left_to_whole <= 1.0); float ratio_right_to_whole = 1.0 - ratio_left_to_whole; diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp index 70c2a7d9a3..d87cd74728 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp @@ -488,7 +488,7 @@ protected: * beads. * \return The beading at the interpolated location. */ - Beading interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right, coord_t switching_radius) const; + static Beading interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right, coord_t switching_radius); /*! * Subroutine of \ref interpolate(const Beading&, Ratio, const Beading&, coord_t) @@ -501,7 +501,7 @@ protected: * \param right One of the beadings to interpolate between. * \return The beading at the interpolated location. */ - Beading interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right) const; + static Beading interpolate(const Beading& left, double ratio_left_to_whole, const Beading& right); /*! * Get the beading at a certain node of the skeletal graph, or create one if diff --git a/tests/libslic3r/test_arachne_walls.cpp b/tests/libslic3r/test_arachne_walls.cpp index 2d8ee3bc03..4ca18400af 100644 --- a/tests/libslic3r/test_arachne_walls.cpp +++ b/tests/libslic3r/test_arachne_walls.cpp @@ -18,6 +18,7 @@ #include #include "libslic3r/Arachne/WallToolPaths.hpp" +#include "libslic3r/Arachne/SkeletalTrapezoidation.hpp" #include "libslic3r/Arachne/utils/ExtrusionLine.hpp" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategyFactory.hpp" #include "libslic3r/Arachne/BeadingStrategy/BeadingStrategy.hpp" @@ -265,3 +266,46 @@ TEST_CASE("Arachne widening keeps two beads in transition band (#14376)", "[Arac for (const coord_t w : beading.bead_widths) CHECK(w <= inner_width); } + +namespace { +// Exposes the protected static interpolate() for a focused unit test. +struct InterpolateProbe : SkeletalTrapezoidation { + using SkeletalTrapezoidation::interpolate; +}; +} // anonymous namespace + +// interpolate() indexes the merged beading with an index derived from `left`. The merged beading +// follows the thicker of left/right, so when the thicker side has fewer insets the index runs past +// its end. +TEST_CASE("Beading interpolation tolerates a thicker side with fewer insets", "[Arachne][Regression]") { + using Beading = BeadingStrategy::Beading; + + // Thicker side (right) has fewer insets, so the merged beading holds only 2 toolpath locations. + const coord_t w = scaled(0.42); + Beading left; + left.total_thickness = scaled(1.0); + left.bead_widths = { w, w, w, w }; + left.toolpath_locations = { scaled(0.1), scaled(0.3), scaled(0.5), scaled(0.7) }; + left.left_over = 0; + + Beading right; + right.total_thickness = scaled(2.0); + right.bead_widths = { w, w }; + right.toolpath_locations = { scaled(0.1), scaled(0.3) }; + right.left_over = 0; + + // Just past left's location [2] (0.5), so the derived index is 2, past the end of the 2-inset merged beading. + const coord_t switching_radius = scaled(0.6); + + Beading result; + REQUIRE_NOTHROW(result = InterpolateProbe::interpolate(left, 0.5, right, switching_radius)); + + // With the guard the adjustment is skipped, so the result is the plain interpolation. + const Beading expected = InterpolateProbe::interpolate(left, 0.5, right); + REQUIRE(result.toolpath_locations.size() == expected.toolpath_locations.size()); + REQUIRE(result.bead_widths.size() == expected.bead_widths.size()); + for (size_t i = 0; i < expected.toolpath_locations.size(); ++i) { + CHECK(result.toolpath_locations[i] == expected.toolpath_locations[i]); + CHECK(result.bead_widths[i] == expected.bead_widths[i]); + } +} From b37fa417421cb2c4676022bcfd1192d61d3ebc19 Mon Sep 17 00:00:00 2001 From: Mister Anderson <50129983+MisterAnderson91@users.noreply.github.com> Date: Wed, 8 Jul 2026 23:12:08 +1000 Subject: [PATCH 035/130] dedupe-issues.yml remove unsupported claude_args option (#14627) * dedupe-issues.yml remove unsupported claude_args option claude_args: is causing an error. Only calling for "--model" anyway, so replaced with model: option. * Merge branch 'main' into MisterAnderson91-dedupe-issues-yml-update --- .github/workflows/dedupe-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dedupe-issues.yml b/.github/workflows/dedupe-issues.yml index cb0a9c0931..a8c21edd01 100644 --- a/.github/workflows/dedupe-issues.yml +++ b/.github/workflows/dedupe-issues.yml @@ -27,7 +27,7 @@ jobs: with: prompt: "/dedupe ${{ github.repository }}/issues/${{ github.event.issue.number || inputs.issue_number }}" claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - claude_args: "--model claude-sonnet-4-5-20250929" + model: "claude-sonnet-4-5-20250929" claude_env: | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b58025575d334300e7631fe376665ce22ff09f21 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Wed, 8 Jul 2026 08:14:05 -0500 Subject: [PATCH 036/130] fix: isolate calibration temp paths per user (#14619) * fix: isolate calibration temp paths per user The calibration temp files under /calib were file-scope statics initialized before set_temporary_dir() runs at startup, so they kept using the shared system temp root and missed the per-user isolation added in #14607. On Linux every account shares /tmp, so the first user to calibrate owns /tmp/calib and later users fail to write there, the same cross-user collision #14607 fixed for model backups, STEP import, and part skip. Build the paths lazily from temporary_dir() instead, through a calib_temp_dir() accessor and a calib_temp_file() join helper. The base becomes /orcaslicer_/calib on Linux and is unchanged on Windows, where the temp dir is already per user. Also make StoreParams::path a std::string rather than a non-owning const char*. The calibration code had to keep a std::string alive solely to feed that pointer, and the field was uninitialized by default; owning the string removes the lifetime hazard for all three callers and makes the entry guard a reliable empty() check. Confined to the 3mf project exporter (three callers, two internal reads); no on-disk, format, or ABI impact. Follows up on #14607 per @Noisyfox's review suggestion. --- src/OrcaSlicer.cpp | 2 +- src/libslic3r/Format/bbs_3mf.cpp | 4 ++-- src/libslic3r/Format/bbs_3mf.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/Utils/CalibUtils.cpp | 39 ++++++++++++++++++++------------ 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 7e1341ac18..311451f774 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -7359,7 +7359,7 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla bool success = false; StoreParams store_params; - store_params.path = path.c_str(); + store_params.path = path; store_params.model = model; store_params.plate_data_list = partplate_data; store_params.project_presets = project_presets; diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 31519e4fbe..fd395135ae 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -5949,7 +5949,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_thumbnail_middle = iter->second; } boost::system::error_code ec; - std::string filename = std::string(store_params.path); + std::string filename = store_params.path; boost::filesystem::remove(filename + ".tmp", ec); bool result = _save_model_to_file(filename + ".tmp", *store_params.model, store_params.plate_data_list, store_params.project_presets, store_params.config, @@ -8988,7 +8988,7 @@ bool store_bbs_3mf(StoreParams& store_params) // All export should use "C" locales for number formatting. CNumericLocalesSetter locales_setter; - if (store_params.path == nullptr || store_params.model == nullptr) + if (store_params.path.empty() || store_params.model == nullptr) return false; _BBS_3MF_Exporter exporter; diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index df4f91f6e9..c16c423f66 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -226,7 +226,7 @@ typedef std::map PlateDataMaps; struct StoreParams { - const char* path; + std::string path; Model* model = nullptr; PlateDataPtrs plate_data_list; int export_plate_idx = -1; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 584386d984..a4a4b9a98e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -15742,7 +15742,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy std::vector project_presets = preset_bundle.get_current_project_embedded_presets(); StoreParams store_params; - store_params.path = path_u8.c_str(); + store_params.path = path_u8; store_params.model = &p->model; store_params.plate_data_list = plate_data_list; store_params.export_plate_idx = export_plate_idx; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 29d302c776..8e7de91318 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -7,6 +7,7 @@ #include "../GUI/PartPlate.hpp" #include "libslic3r/CutUtils.hpp" #include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" #include "slic3r/GUI/Jobs/BoostThreadWorker.hpp" @@ -27,11 +28,19 @@ const double MIN_PA_K_VALUE = 0.0; const double MAX_PA_K_VALUE = 2.0; std::unique_ptr CalibUtils::print_worker; -wxString wxstr_temp_dir = fs::path(fs::temp_directory_path() / "calib").wstring(); -static const std::string temp_dir = wxstr_temp_dir.utf8_string(); -static const std::string temp_gcode_path = temp_dir + "/temp.gcode"; -static const std::string path = temp_dir + "/test.3mf"; -static const std::string config_3mf_path = temp_dir + "/test_config.3mf"; + +// Built lazily so temporary_dir() is read on first use, after set_temporary_dir() +// has run at startup (it isolates the temp root per user to avoid cross-user collisions). +static const std::string& calib_temp_dir() +{ + static const std::string dir = temporary_dir() + "/calib"; + return dir; +} +static std::string calib_temp_file(const std::string& name) { return calib_temp_dir() + "/" + name; } + +static const std::string gcode_filename = "temp.gcode"; +static const std::string model_filename = "test.3mf"; +static const std::string config_filename = "test_config.3mf"; static std::string MachineBedTypeString[7] = { "auto", @@ -1599,7 +1608,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f part_plate->update_slice_result_valid_state(true); gcode_result->reset(); - fff_print->export_gcode(temp_gcode_path, gcode_result, nullptr); + fff_print->export_gcode(calib_temp_file(gcode_filename), gcode_result, nullptr); std::vector thumbnails; PlateDataPtrs plate_data_list; @@ -1618,7 +1627,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } for (auto plate_data : plate_data_list) { - plate_data->gcode_file = temp_gcode_path; + plate_data->gcode_file = calib_temp_file(gcode_filename); plate_data->is_sliced_valid = true; plate_data->printer_model_id = obj_->printer_type; FilamentInfo& filament_info = plate_data->slice_filaments_info.front(); @@ -1681,7 +1690,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } StoreParams store_params; - store_params.path = path.c_str(); + store_params.path = calib_temp_file(model_filename); store_params.model = model; store_params.plate_data_list = plate_data_list; store_params.config = &new_print_config; @@ -1695,7 +1704,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f bool success = Slic3r::store_bbs_3mf(store_params); store_params.strategy = SaveStrategy::Silence | SaveStrategy::SplitModel | SaveStrategy::WithSliceInfo | SaveStrategy::SkipAuxiliary; - store_params.path = config_3mf_path.c_str(); + store_params.path = calib_temp_file(config_filename); success = Slic3r::store_bbs_3mf(store_params); release_PlateData_list(plate_data_list); @@ -1784,9 +1793,9 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess PrintPrepareData job_data; job_data.is_from_plater = false; job_data.plate_idx = 0; - job_data._3mf_config_path = config_3mf_path; - job_data._3mf_path = path; - job_data._temp_path = temp_dir; + job_data._3mf_config_path = calib_temp_file(config_filename); + job_data._3mf_path = calib_temp_file(model_filename); + job_data._temp_path = calib_temp_dir(); PlateListData plate_data; plate_data.is_valid = true; @@ -1889,9 +1898,9 @@ void CalibUtils::send_to_print(const std::vector &calib_infos, wxStri PrintPrepareData job_data; job_data.is_from_plater = false; job_data.plate_idx = 0; - job_data._3mf_config_path = config_3mf_path; - job_data._3mf_path = path; - job_data._temp_path = temp_dir; + job_data._3mf_config_path = calib_temp_file(config_filename); + job_data._3mf_path = calib_temp_file(model_filename); + job_data._temp_path = calib_temp_dir(); PlateListData plate_data; plate_data.is_valid = true; From 781ecdc2c1e9a2daa45ced77e0b4415ffec56e00 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Wed, 8 Jul 2026 09:00:35 -0500 Subject: [PATCH 037/130] ci: run unit tests on Windows and macOS (#14443) * ci: run unit tests on Windows and macOS The Unit Tests CI job only ran on Linux, so platform-specific bugs invisible to a Linux build could land undetected (e.g. the MSVC-only NfpPlacer crash fixed in #14267). The full non-[NotWorking] suite already builds and passes on every shipped arch, so this wires them into CI. A reusable unit_tests.yml, called once per built arch, downloads that arch's test artifact and runs ctest. Each build leg builds the test executables and uploads them; a single publish_test_results job on Linux aggregates the JUnit results into one check. Coverage: Linux x86_64 + aarch64, Windows x64 + arm64, macOS arm64. macOS x86_64 is deferred (cross-built on arm64, needs Rosetta). - build_release_vs.bat: "tests" token enables BUILD_TESTS - build_release_macos.sh: -T builds and runs tests; ORCA_TESTS_BUILD_ONLY builds them without running (used by CI) - scripts/run_unit_tests.sh: parameterized test dir and build config Addresses #11273. * ci: bump actions/checkout to v7 in reusable unit_tests workflow Match the actions/checkout v6->v7 bump (#14517) that upstream applied to the inline test job this reusable workflow replaces. --- .github/workflows/build_all.yml | 93 +++++++++++++++++++------------- .github/workflows/build_orca.yml | 55 ++++++++++++++----- .github/workflows/unit_tests.yml | 73 +++++++++++++++++++++++++ build_release_macos.sh | 13 ++--- build_release_vs.bat | 10 +++- scripts/run_unit_tests.sh | 12 ++++- 6 files changed, 196 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/unit_tests.yml diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 376ef74b1f..49e6f58fd6 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -122,54 +122,73 @@ jobs: arch: universal macos-combine-only: true secrets: inherit - unit_tests: - name: Unit Tests - # Tests are built on the aarch64 leg by default (faster GitHub arm runner), - # so run them there; self-hosted builds them on the amd64 server instead. - runs-on: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04-arm' }} + # One test job per built arch, on the runner that built it. + unit_tests_linux_x86_64: + name: Linux x86_64 needs: build_linux if: ${{ !cancelled() && success() }} + uses: ./.github/workflows/unit_tests.yml + with: + os: ${{ vars.SELF_HOSTED && 'orca-lnx-server' || 'ubuntu-24.04' }} + artifact: ${{ github.sha }}-tests-linux-x86_64 + unit_tests_linux_aarch64: + name: Linux aarch64 + needs: build_linux + if: ${{ !cancelled() && success() }} + uses: ./.github/workflows/unit_tests.yml + with: + os: ubuntu-24.04-arm + artifact: ${{ github.sha }}-tests-linux-aarch64 + unit_tests_windows_x64: + name: Windows x64 + needs: build_windows + if: ${{ !cancelled() && success() }} + uses: ./.github/workflows/unit_tests.yml + with: + os: ${{ vars.SELF_HOSTED && 'orca-win-server' || 'windows-latest' }} + artifact: ${{ github.sha }}-tests-windows-x64 + unit_tests_windows_arm64: + name: Windows arm64 + needs: build_windows + if: ${{ !cancelled() && success() }} + uses: ./.github/workflows/unit_tests.yml + with: + os: windows-11-arm + artifact: ${{ github.sha }}-tests-windows-arm64 + test-dir: build-arm64/tests + unit_tests_macos_arm64: + name: macOS arm64 + needs: build_macos_arch + if: ${{ !cancelled() && success() }} + uses: ./.github/workflows/unit_tests.yml + with: + os: ${{ vars.SELF_HOSTED && 'orca-macos-arm64' || 'macos-14' }} + artifact: ${{ github.sha }}-tests-macos-arm64 + test-dir: build/arm64/tests + publish_test_results: + name: Publish Test Results + needs: [unit_tests_linux_x86_64, unit_tests_linux_aarch64, unit_tests_windows_x64, unit_tests_windows_arm64, unit_tests_macos_arm64] + if: ${{ !cancelled() }} + runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v7 - with: - sparse-checkout: | - .github - scripts - tests - - name: Apt-Install Dependencies - if: ${{ !vars.SELF_HOSTED }} - uses: ./.github/actions/apt-install-deps - - name: Restore Test Artifact + - name: Download Test Results uses: actions/download-artifact@v8 with: - name: ${{ github.sha }}-tests - - uses: lukka/get-cmake@latest - with: - cmakeVersion: "~4.3.0" # use most recent 4.3.x version - useLocalCache: true # <--= Use the local cache (default is 'false'). - useCloudCache: true - - name: Unpackage and Run Unit Tests - timeout-minutes: 20 - run: | - tar -xvf build_tests.tar - scripts/run_unit_tests.sh - - name: Upload Test Logs - uses: actions/upload-artifact@v7 - if: ${{ failure() }} - with: - name: unit-test-logs - path: build/tests/**/*.log + pattern: test-results-* + path: test-results + # Best-effort: a read-only token (e.g. fork PRs) can't write the check, so + # don't let a publish failure fail the run. The test jobs gate correctness. - name: Publish Test Results - if: always() + continue-on-error: true uses: EnricoMi/publish-unit-test-result-action@v2 with: - files: "ctest_results.xml" - - name: Delete Test Artifact + files: "test-results/**/*.xml" + - name: Delete Test Results if: success() uses: geekyeggo/delete-artifact@v6 with: - name: ${{ github.sha }}-tests + name: test-results-* + failOnError: false flatpak: name: "Flatpak" container: diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index ffe4c35f8d..21c65283a9 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -141,8 +141,26 @@ jobs: - name: Build slicer mac if: runner.os == 'macOS' && !inputs.macos-combine-only working-directory: ${{ github.workspace }} + # arm64 only: build the tests here; the unit_tests_macos job runs them. + env: + ORCA_TESTS_BUILD_ONLY: ${{ inputs.arch == 'arm64' && '1' || '' }} run: | - ./build_release_macos.sh -s -n -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15 + ./build_release_macos.sh -s -n -x ${{ !vars.SELF_HOSTED && '-1' || '' }} -a ${{ inputs.arch }} -t 10.15 ${{ inputs.arch == 'arm64' && '-T' || '' }} + + - name: Pack unit tests mac + if: runner.os == 'macOS' && !inputs.macos-combine-only && inputs.arch == 'arm64' + working-directory: ${{ github.workspace }} + run: tar -cvf build_tests.tar build/arm64/tests + + - name: Upload Test Artifact mac + if: runner.os == 'macOS' && !inputs.macos-combine-only && inputs.arch == 'arm64' + uses: actions/upload-artifact@v7 + with: + name: ${{ github.sha }}-tests-macos-arm64 + overwrite: true + path: build_tests.tar + retention-days: 5 + if-no-files-found: error - name: Pack macOS app bundle ${{ inputs.arch }} if: runner.os == 'macOS' && !inputs.macos-combine-only @@ -335,11 +353,28 @@ jobs: # env: # WindowsSdkDir: 'C:\Program Files (x86)\Windows Kits\10\' # WindowsSDKVersion: '10.0.26100.0\' + # "tests" builds the unit tests too; the unit_tests_windows_* jobs run them. run: | $arch = "${{ inputs.arch }}" - if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 } else { .\build_release_vs.bat slicer } + if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 tests } else { .\build_release_vs.bat slicer tests } shell: pwsh + - name: Pack unit tests Win + if: runner.os == 'Windows' + working-directory: ${{ github.workspace }} + shell: pwsh + run: tar -cvf build_tests.tar ${{ env.BUILD_DIR }}/tests + + - name: Upload Test Artifact Win + if: runner.os == 'Windows' + uses: actions/upload-artifact@v7 + with: + name: ${{ github.sha }}-tests-windows-${{ inputs.arch }} + overwrite: true + path: build_tests.tar + retention-days: 5 + if-no-files-found: error + # NSIS is x86-only; it runs (and the installer it emits runs) under ARM64's # x86 emulation, packaging the native arm64 payload from build-arm64. - name: Create installer Win @@ -452,26 +487,22 @@ jobs: if: runner.os == 'Linux' shell: bash run: | - # Build + tar the unit tests (-t) only on the leg that runs them: the - # aarch64 leg by default (faster GitHub arm runner), or amd64 when using - # self-hosted runners (no arm self-hosted server). unit_tests downloads - # this tarball. The profile validator is built with -s, so amd64 keeps it. - tests=${{ (!vars.SELF_HOSTED && inputs.arch == 'aarch64') || (vars.SELF_HOSTED && inputs.arch != 'aarch64') }} - if $tests; then flags=-istrlL; else flags=-isrlL; fi - ./build_linux.sh "$flags" + # Build + tar the unit tests (-t) on both Linux legs so each arch + # (x86_64 + aarch64) gets tested by its own unit_tests_linux_* job. + ./build_linux.sh -istrlL ./scripts/check_appimage_libs.sh ./build/package ./build/package/bin/orca-slicer appimage=./build/OrcaSlicer_Linux_AppImage${{ env.ubuntu-ver-str }}${{ env.arch_suffix }}_${{ env.ver }}.AppImage mv -n ./build/OrcaSlicer_Linux_V${{ env.ver_pure }}.AppImage "$appimage" chmod +x "$appimage" - if $tests; then tar -cvpf build_tests.tar build/tests; fi + tar -cvf build_tests.tar build/tests # Use tar because upload-artifacts won't always preserve directory structure # and doesn't preserve file permissions - name: Upload Test Artifact - if: runner.os == 'Linux' && ((!vars.SELF_HOSTED && inputs.arch == 'aarch64') || (vars.SELF_HOSTED && inputs.arch != 'aarch64')) + if: runner.os == 'Linux' uses: actions/upload-artifact@v7 with: - name: ${{ github.sha }}-tests + name: ${{ github.sha }}-tests-linux-${{ inputs.arch == 'aarch64' && 'aarch64' || 'x86_64' }} overwrite: true path: build_tests.tar retention-days: 5 diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml new file mode 100644 index 0000000000..0fe91c7440 --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,73 @@ +name: Unit Tests + +# Download a platform's test artifact, run ctest, and upload the JUnit +# results for aggregation. Called once per arch from build_all.yml. +on: + workflow_call: + inputs: + os: + required: true + type: string + artifact: + description: Test artifact uploaded by the build leg + required: true + type: string + test-dir: + description: Built tests dir; defaults to build/tests, override for arch-separated builds + required: false + type: string + default: build/tests + +jobs: + unit_tests: + # Static "Unit Tests"; the per-arch label is the caller's job name, so the + # graph shows e.g. "Windows x64 / Unit Tests". + name: Unit Tests + runs-on: ${{ inputs.os }} + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + # tests/data is referenced by absolute path (TEST_DATA_DIR). + sparse-checkout: | + .github + scripts + tests + - name: Apt-Install Dependencies + if: runner.os == 'Linux' && !vars.SELF_HOSTED + uses: ./.github/actions/apt-install-deps + - name: Restore Test Artifact + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.artifact }} + - uses: lukka/get-cmake@latest + with: + cmakeVersion: "~4.3.0" # use most recent 4.3.x version + useLocalCache: true + useCloudCache: true + - name: Unpackage and Run Unit Tests + timeout-minutes: 20 + shell: bash + run: | + tar -xvf build_tests.tar + # Multi-config generators (Windows/macOS) need a config; Linux is single-config. + scripts/run_unit_tests.sh "${{ inputs.test-dir }}" "${{ runner.os != 'Linux' && 'Release' || '' }}" + - name: Upload Test Logs + if: ${{ failure() }} + uses: actions/upload-artifact@v7 + with: + name: unit-test-logs-${{ inputs.artifact }} + path: ${{ inputs.test-dir }}/**/*.log + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v7 + with: + name: test-results-${{ inputs.artifact }} + path: ctest_results.xml + retention-days: 5 + if-no-files-found: warn + - name: Delete Test Artifact + if: success() + uses: geekyeggo/delete-artifact@v6 + with: + name: ${{ inputs.artifact }} diff --git a/build_release_macos.sh b/build_release_macos.sh index 8d417695ad..1a86d2c515 100755 --- a/build_release_macos.sh +++ b/build_release_macos.sh @@ -59,7 +59,7 @@ while getopts ":dpa:snt:xbc:i:1Tuh" opt; do echo " -c: Set CMake build configuration, default is Release" echo " -i: Add a prefix to ignore during CMake dependency discovery (repeatable), defaults to /opt/local:/usr/local:/opt/homebrew" echo " -1: Use single job for building" - echo " -T: Build and run tests" + echo " -T: Build and run tests (set ORCA_TESTS_BUILD_ONLY=1 to build without running)" exit 0 ;; * ) @@ -209,13 +209,10 @@ function build_slicer() { cmake --build . --config "$BUILD_CONFIG" --target "$SLICER_BUILD_TARGET" ) - if [ "1." == "$BUILD_TESTS". ]; then - echo "Running tests for $_ARCH..." - ( - set -x - cd "$PROJECT_BUILD_DIR" - ctest --build-config "$BUILD_CONFIG" --output-on-failure - ) + # -T also runs the tests; ORCA_TESTS_BUILD_ONLY=1 builds them without + # running, so CI can build here and run them in a dedicated job. + if [ "1." == "$BUILD_TESTS". ] && [ "1." != "$ORCA_TESTS_BUILD_ONLY". ]; then + "$PROJECT_DIR/scripts/run_unit_tests.sh" "build/$_ARCH/tests" "$BUILD_CONFIG" fi echo "Verify localization with gettext..." diff --git a/build_release_vs.bat b/build_release_vs.bat index 0c1334d5f7..3288beda4c 100644 --- a/build_release_vs.bat +++ b/build_release_vs.bat @@ -20,6 +20,12 @@ for %%a in (%*) do ( if "%%a"=="-x" set USE_NINJA=1 ) +@REM Check for unit-tests option ("tests") +set BUILD_TESTS=OFF +for %%a in (%*) do ( + if /I "%%a"=="tests" set BUILD_TESTS=ON +) + if "%USE_NINJA%"=="1" ( echo Using Ninja Multi-Config generator set CMAKE_GENERATOR="Ninja Multi-Config" @@ -145,10 +151,10 @@ cd %build_dir% echo on set CMAKE_POLICY_VERSION_MINIMUM=3.5 if "%USE_NINJA%"=="1" ( - cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% + cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target ALL_BUILD ) else ( - cmake .. -G %CMAKE_GENERATOR% -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% + cmake .. -G %CMAKE_GENERATOR% -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DBUILD_TESTS=%BUILD_TESTS% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target ALL_BUILD -- -m ) @echo off diff --git a/scripts/run_unit_tests.sh b/scripts/run_unit_tests.sh index bd9e969227..f6a01dd3e0 100755 --- a/scripts/run_unit_tests.sh +++ b/scripts/run_unit_tests.sh @@ -4,11 +4,21 @@ # It should only require the directories build/tests, scripts/, and tests/ to function, # and cmake (with ctest) installed. # (otherwise, update the workflow too, but try to avoid to keep things self-contained) +# +# Usage: run_unit_tests.sh [TEST_DIR] [BUILD_CONFIG] +# TEST_DIR directory containing the built tests (default: build/tests) +# BUILD_CONFIG configuration to run; required for multi-config generators +# (Windows/macOS), harmless/omitted for single-config (Linux). ROOT_DIR="$(dirname "$0")/.." cd "${ROOT_DIR}" || exit 1 +TEST_DIR="${1:-build/tests}" +BUILD_CONFIG="${2:-}" + # Run the whole suite, excluding tests tagged [NotWorking]. # --no-tests=error fails the job if the filter matches nothing (instead of passing green). -ctest --test-dir build/tests -LE "NotWorking" --no-tests=error --output-junit "$(pwd)/ctest_results.xml" --output-on-failure -j +args=(--test-dir "${TEST_DIR}" -LE "NotWorking" --no-tests=error --output-junit "$(pwd)/ctest_results.xml" --output-on-failure -j) +[ -n "${BUILD_CONFIG}" ] && args+=(--build-config "${BUILD_CONFIG}") +ctest "${args[@]}" From 237ef41b06a7a0a949173d7f926d56c227b85c82 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Thu, 9 Jul 2026 00:06:26 +0800 Subject: [PATCH 038/130] feat(libslic3r): multi-nozzle slicing engine for H2C/A2L Port BambuStudio's dual-nozzle slicing core: H2C-era config keys, filament-to-nozzle grouping with per-layer dynamic regrouping, filament/nozzle/hotend gcode placeholder vocabulary, multi-nozzle wipe tower pre-heat/pre-cool, the two-pass pre-cooling injector, and corexy farthest-point timelapse. --- src/libslic3r/AppConfig.cpp | 6 + src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/Extruder.hpp | 4 + src/libslic3r/FilamentGroup.cpp | 1273 ++++++++++++++------ src/libslic3r/FilamentGroup.hpp | 145 ++- src/libslic3r/FilamentGroupUtils.cpp | 61 + src/libslic3r/FilamentGroupUtils.hpp | 19 + src/libslic3r/Format/bbs_3mf.cpp | 165 ++- src/libslic3r/Format/bbs_3mf.hpp | 8 + src/libslic3r/GCode.cpp | 880 ++++++++++++-- src/libslic3r/GCode.hpp | 49 +- src/libslic3r/GCode/GCodeProcessor.cpp | 1194 +++++++++++++++++- src/libslic3r/GCode/GCodeProcessor.hpp | 327 +++++ src/libslic3r/GCode/TimelapsePosPicker.cpp | 57 +- src/libslic3r/GCode/TimelapsePosPicker.hpp | 6 + src/libslic3r/GCode/ToolOrderUtils.cpp | 731 ++++++++++- src/libslic3r/GCode/ToolOrderUtils.hpp | 117 +- src/libslic3r/GCode/ToolOrdering.cpp | 1029 +++++++++++++--- src/libslic3r/GCode/ToolOrdering.hpp | 31 +- src/libslic3r/GCode/WipeTower.cpp | 206 +++- src/libslic3r/GCode/WipeTower.hpp | 41 + src/libslic3r/GCodeWriter.cpp | 25 +- src/libslic3r/GCodeWriter.hpp | 7 +- src/libslic3r/MultiNozzleUtils.cpp | 922 ++++++++++++++ src/libslic3r/MultiNozzleUtils.hpp | 288 +++++ src/libslic3r/Preset.cpp | 24 +- src/libslic3r/Preset.hpp | 2 + src/libslic3r/PresetBundle.cpp | 47 +- src/libslic3r/PresetBundle.hpp | 24 + src/libslic3r/Print.cpp | 77 +- src/libslic3r/Print.hpp | 23 + src/libslic3r/PrintConfig.cpp | 440 ++++++- src/libslic3r/PrintConfig.hpp | 74 +- src/libslic3r/Utils.hpp | 3 + src/libslic3r/calib.hpp | 10 + src/libslic3r/utils.cpp | 13 + 36 files changed, 7622 insertions(+), 708 deletions(-) create mode 100644 src/libslic3r/MultiNozzleUtils.cpp create mode 100644 src/libslic3r/MultiNozzleUtils.hpp diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index c81e6c391c..8ff9dcea32 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -800,6 +800,10 @@ std::string AppConfig::load() preset_info.nozzle_volume_type = NozzleVolumeType(cali_it.value()["nozzle_volume_type"].get()); if (cali_it.value().contains("bed_type")) preset_info.bed_type = BedType(cali_it.value()["bed_type"].get()); + if (cali_it.value().contains("nozzle_pos_id")) + preset_info.nozzle_pos_id = cali_it.value()["nozzle_pos_id"].get(); + if (cali_it.value().contains("nozzle_sn")) + preset_info.nozzle_sn = cali_it.value()["nozzle_sn"].get(); cali_info.selected_presets.push_back(preset_info); } } @@ -957,6 +961,8 @@ void AppConfig::save() preset_json["extruder_id"] = filament_preset.extruder_id; preset_json["nozzle_volume_type"] = int(filament_preset.nozzle_volume_type); preset_json["bed_type"] = int(filament_preset.bed_type); + preset_json["nozzle_pos_id"] = filament_preset.nozzle_pos_id; + preset_json["nozzle_sn"] = filament_preset.nozzle_sn; preset_json["nozzle_diameter"] = filament_preset.nozzle_diameter; preset_json["filament_id"] = filament_preset.filament_id; preset_json["setting_id"] = filament_preset.setting_id; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 01c1a0636b..a7ebab0803 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -471,6 +471,8 @@ set(lisbslic3r_sources FilamentGroup.cpp FilamentGroupUtils.hpp FilamentGroupUtils.cpp + MultiNozzleUtils.hpp + MultiNozzleUtils.cpp GCode/ToolOrderUtils.hpp GCode/ToolOrderUtils.cpp FlushVolPredictor.hpp diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index 0d76ede8c9..a0b679add6 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -51,6 +51,10 @@ public: double retracted() const { return m_retracted; } // Get extra retraction planned after double restart_extra() const { return m_restart_extra; } + // Share-aware retracted-length readers (for extruders shared between filaments), consumed by GCodeWriter::get_extruder_retracted_length. + bool is_share_extruder() const { return m_share_extruder; } + double get_single_retracted_length() const { return m_retracted; } + double get_share_retracted_length() const { return m_share_retracted[extruder_id()]; } // Setters for the PlaceholderParser. // Set current extruder position. Only applicable with absolute extruder addressing. void set_position(double e) { m_E = e; } diff --git a/src/libslic3r/FilamentGroup.cpp b/src/libslic3r/FilamentGroup.cpp index 2a9b5b6037..f5b5564538 100644 --- a/src/libslic3r/FilamentGroup.cpp +++ b/src/libslic3r/FilamentGroup.cpp @@ -5,10 +5,15 @@ #include #include #include +#include namespace Slic3r { using namespace FilamentGroupUtils; + static constexpr long long ENUM_THRESHOLD = 10000; + static constexpr long long ENUM_EARLY_EXIT = 10000000; + constexpr uint32_t GOLDEN_RATIO_32 = 0x9e3779b9; + // clear the array and heap,save the groups in heap to the array static void change_memoryed_heaps_to_arrays(MemoryedGroupHeap& heap,const int total_filament_num,const std::vector& used_filaments, std::vector>& arrs) { @@ -36,88 +41,350 @@ namespace Slic3r return filament_merge_map; } - - std::vector calc_filament_group_for_tpu(const std::set& tpu_filaments, const int filament_nums, const int master_extruder_id) + static uint64_t fnv_hash_nozzle(int volume_type, int is_right_extruder, int loaded_filament = -1) { - std::vector ret(filament_nums); - for (size_t fidx = 0; fidx < filament_nums; ++fidx) { - if (tpu_filaments.count(fidx)) - ret[fidx] = master_extruder_id; - else - ret[fidx] = 1 - master_extruder_id; + constexpr uint64_t FNV_OFFSET_BASIS = 14695981039346656037ULL; + constexpr uint64_t FNV_PRIME = 1099511628211ULL; + constexpr uint64_t SALT_A = 0xA5A5A5A5A5A5A5A5ULL; + constexpr uint64_t SALT_B = 0x5A5A5A5A5A5A5A5AULL; + constexpr uint64_t SALT_C = 0x3C3C3C3C3C3C3C3CULL; + + uint64_t h = FNV_OFFSET_BASIS; + h ^= static_cast(volume_type) + SALT_A; + h *= FNV_PRIME; + h ^= static_cast(is_right_extruder) + SALT_B; + h *= FNV_PRIME; + if (loaded_filament >= 0) { + h ^= static_cast(loaded_filament) + SALT_C; + h *= FNV_PRIME; } - return ret; + + return h; } - bool can_swap_groups(const int extruder_id_0, const std::set& group_0, const int extruder_id_1, const std::set& group_1, const FilamentGroupContext& ctx) + static double evaluate_score(const double flush, const double time, const bool with_time = false) { + if (!with_time) return flush; + + double approx_density = 1.26; // g/cm^3 + double approx_flush_speed = 180; // s/g + double correction_factor = 2; + double flush_score = flush * approx_density * approx_flush_speed * correction_factor / 1000; + return flush_score + time; + } + + static double calc_change_time_for_group( + const std::vector& filament_change_seq, + const std::vector& nozzle_change_seq, + const std::vector& logical_filaments, + const std::vector& nozzle_list, + const MultiNozzleUtils::FilamentChangeTimeParams& time_params, + const std::vector& ams_preload_enabled, + const std::vector& group_of_filament) { - std::vector>extruder_unprintables(2); - { - std::vector> unprintable_filaments = ctx.model_info.unprintable_filaments; - if (unprintable_filaments.size() > 1) - remove_intersection(unprintable_filaments[0], unprintable_filaments[1]); + auto r = MultiNozzleUtils::simulate_filament_change_time( + logical_filaments, nozzle_list, filament_change_seq, + nozzle_change_seq, group_of_filament, time_params, + ams_preload_enabled); + return r.actual_time; + } - std::map>unplaceable_limts; - for (auto& group_id : { extruder_id_0,extruder_id_1 }) - for (auto f : unprintable_filaments[group_id]) - unplaceable_limts[f].emplace_back(group_id); + static double full_evaluate( + const std::vector& used_filaments, + const std::vector& filament_nozzle_map, + const FilamentGroupContext& ctx, + std::optional&)>> get_custom_seq = std::nullopt, + int* out_flush = nullptr) + { + auto group_res = MultiNozzleUtils::LayeredNozzleGroupResult::create(filament_nozzle_map, ctx.nozzle_info.nozzle_list, used_filaments); + if (!group_res) { + if (out_flush) *out_flush = 0; + return 0.0; + } - for (auto& elem : unplaceable_limts) - sort_remove_duplicates(elem.second); - - for (auto& elem : unplaceable_limts) { - for (auto& eid : elem.second) { - if (eid == extruder_id_0) { - extruder_unprintables[0].insert(elem.first); - } - if (eid == extruder_id_1) { - extruder_unprintables[1].insert(elem.first); + MultiNozzleUtils::NozzleStatusRecorder initial_status; + for (auto& [nozzle_id, filament_id] : ctx.nozzle_info.nozzle_status) { + if (filament_id >= 0) { + int extruder_id = 0; + for (const auto& nozzle : ctx.nozzle_info.nozzle_list) { + if (nozzle.group_id == nozzle_id) { + extruder_id = nozzle.extruder_id; + break; } } + initial_status.set_nozzle_status(nozzle_id, filament_id, extruder_id); } } - // check printable limits - for (auto fid : group_0) { - if (extruder_unprintables[1].count(fid) > 0) - return false; + std::vector> filament_sequences; + int flush = reorder_filaments_for_multi_nozzle_extruder( + used_filaments, + *group_res, + ctx.model_info.layer_filaments, + ctx.model_info.flush_matrix, + get_custom_seq ? *get_custom_seq : std::function&)>{}, + &filament_sequences, + initial_status + ); + + if (out_flush) *out_flush = flush; + + double change_time = 0.0; + if (!filament_sequences.empty()) { + std::vector filament_change_seq; + std::vector nozzle_change_seq; + int prev_fil = -1, prev_nozzle = -1; + for (const auto& layer_seq : filament_sequences) { + for (unsigned int fil : layer_seq) { + auto nozzle_info = group_res->get_first_nozzle_for_filament(fil); + if (!nozzle_info) continue; + int nid = nozzle_info->group_id; + if ((int)fil == prev_fil && nid == prev_nozzle) continue; + filament_change_seq.push_back(static_cast(fil)); + nozzle_change_seq.push_back(nid); + prev_fil = (int)fil; + prev_nozzle = nid; + } + } + + std::vector logical_filaments(used_filaments.begin(), used_filaments.end()); + std::vector group_of_filament(used_filaments.size(), 0); + for (size_t fi = 0; fi < used_filaments.size(); ++fi) { + int nozzle_id = filament_nozzle_map[used_filaments[fi]]; + if (nozzle_id >= 0 && nozzle_id < (int)ctx.nozzle_info.nozzle_list.size()) + group_of_filament[fi] = ctx.nozzle_info.nozzle_list[nozzle_id].extruder_id; + } + change_time = calc_change_time_for_group( + filament_change_seq, + nozzle_change_seq, + logical_filaments, + ctx.nozzle_info.nozzle_list, + ctx.speed_info.change_time_params, + ctx.speed_info.ams_preload_enabled, + group_of_filament + ); } - for (auto fid : group_1) { - if (extruder_unprintables[0].count(fid) > 0) - return false; + double print_time = 0.0; + if (ctx.speed_info.group_with_time) { + TimeEvaluator time_evaluator(ctx.speed_info); + print_time = time_evaluator.get_estimated_time(filament_nozzle_map); } - // check extruder capacity ,if result before exchange meets the constraints and the result after exchange does not meet the constraints, return false - if (ctx.machine_info.max_group_size[extruder_id_0] >= group_0.size() && ctx.machine_info.max_group_size[extruder_id_1] >= group_1.size() && (ctx.machine_info.max_group_size[extruder_id_0] < group_1.size() || ctx.machine_info.max_group_size[extruder_id_1] < group_0.size())) - return false; - - return true; + return evaluate_score(flush, change_time + print_time, true); } - - // only support extruder nums with 2, try to swap the master extruder id with the other extruder id - std::vector optimize_group_for_master_extruder(const std::vector& used_filaments,const FilamentGroupContext& ctx, std::vector& filament_map) + static long long estimate_dedup_enum_count(int k, int n, const FilamentGroupContext& ctx) { - std::vector ret = filament_map; - std::unordered_map> groups; - for (size_t idx = 0; idx < used_filaments.size(); ++idx) { - int filament_id = used_filaments[idx]; - int group_id = ret[filament_id]; - groups[group_id].insert(filament_id); + if (n <= 0 || k <= 0) return 0; + + long long total = 1; + for (int i = 0; i < n; ++i) { + total *= k; + if (total > ENUM_EARLY_EXIT) return total; } - int none_master_extruder_id = 1 - ctx.machine_info.master_extruder_id; - assert(0 <= none_master_extruder_id && none_master_extruder_id <= 1); + if (k <= 1) return total; - if (can_swap_groups(none_master_extruder_id, groups[none_master_extruder_id], ctx.machine_info.master_extruder_id, groups[ctx.machine_info.master_extruder_id], ctx) - && groups[none_master_extruder_id].size()>groups[ctx.machine_info.master_extruder_id].size()) { - for (auto fid : groups[none_master_extruder_id]) - ret[fid] = ctx.machine_info.master_extruder_id; - for (auto fid : groups[ctx.machine_info.master_extruder_id]) - ret[fid] = none_master_extruder_id; + int dedup_factor = 1; + std::map nozzle_type_count; + for (const auto& nozzle : ctx.nozzle_info.nozzle_list) { + auto it = ctx.nozzle_info.nozzle_status.find(nozzle.group_id); + int loaded_filament = (it != ctx.nozzle_info.nozzle_status.end()) ? it->second : -1; + uint64_t hash = fnv_hash_nozzle(nozzle.volume_type, nozzle.group_id > 0, loaded_filament); + nozzle_type_count[hash]++; } - return ret; + + for (auto& [hash, count] : nozzle_type_count) { + int factorial = 1; + for (int i = 2; i <= count; ++i) factorial *= i; + dedup_factor *= factorial; + } + + return total / std::max(dedup_factor, 1); + } + + std::vector FilamentGroup::calc_group_by_enum( + int k, + const std::vector& used_filaments, + const std::unordered_map>& unplaceable_limits, + int* cost) + { + static constexpr int UNPLACEABLE_LIMIT_REWARD = 10000; + static constexpr int MAX_SIZE_LIMIT_REWARD = 5000; + static constexpr int SUPPORT_PREFER_REWARD = 100; + static constexpr int BEST_FIT_LIMIT_REWARD = 10; + + int n = (int)used_filaments.size(); + + std::vector> candidates(n); + for (int i = 0; i < n; i++) { + std::unordered_set group_set; + if (auto it = unplaceable_limits.find(i); it != unplaceable_limits.end()) { + for (int g = 0; g < k; g++) group_set.insert(g); + for (int g : it->second) group_set.erase(g); + } else { + for (int g = 0; g < k; g++) group_set.insert(g); + } + candidates[i].assign(group_set.begin(), group_set.end()); + } + + auto vector_equal = [](const std::vector& a, const std::vector& b) -> bool { + if (a.size() != b.size()) return false; + for (size_t i = 0; i < a.size(); i++) { + if (a[i] != b[i]) return false; + } + return true; + }; + auto vector_hash = [](const std::vector& v) -> size_t { + size_t h = 0; + for (auto val : v) { h ^= val + GOLDEN_RATIO_32 + (h << 6) + (h >> 2); } + return h; + }; + std::unordered_set, decltype(vector_hash), decltype(vector_equal)> group_set(0, vector_hash, vector_equal); + std::vector group_hashs; + + std::vector nozzles_hash(k); + for (const auto& nozzle : ctx.nozzle_info.nozzle_list) { + if (nozzle.group_id < k) { + auto it = ctx.nozzle_info.nozzle_status.find(nozzle.group_id); + int loaded_filament = (it != ctx.nozzle_info.nozzle_status.end()) ? it->second : -1; + nozzles_hash[nozzle.group_id] = fnv_hash_nozzle(nozzle.volume_type, nozzle.group_id > 0, loaded_filament); + } + } + + std::vector best_full_map(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id); + double best_score = std::numeric_limits::max(); + int best_prefer_level = 0; + int best_flush = 0; + + const long long total = (long long)std::pow(k, n); + for (long long mask = 0; mask < total; mask++) { + long long num = mask; + std::unordered_map> nozzles_filaments; + std::vector groups_count(k, 0); + std::vector used_labels(n, 0); + + for (int i = 0; i < n; i++) { + int g_id = num % k; + num /= k; + used_labels[i] = g_id; + nozzles_filaments[g_id].emplace_back(i); + groups_count[g_id]++; + } + + // Hash dedup + group_hashs.clear(); + for (auto& nf : nozzles_filaments) { + uint64_t filament_mask = 0; + for (int filament : nf.second) filament_mask |= (1ULL << filament); + size_t gh = nozzles_hash[nf.first]; + gh ^= (std::hash{}(filament_mask) + GOLDEN_RATIO_32 + (gh << 6) + (gh >> 2)); + group_hashs.emplace_back(gh); + } + std::sort(group_hashs.begin(), group_hashs.end()); + if (group_set.find(group_hashs) != group_set.end()) continue; + group_set.insert(group_hashs); + + // Prefer level + int prefer_level = 0; + int placeable_count = 0; + for (int i = 0; i < n; i++) { + if (std::find(candidates[i].begin(), candidates[i].end(), used_labels[i]) != candidates[i].end()) + placeable_count++; + } + prefer_level += placeable_count * UNPLACEABLE_LIMIT_REWARD; + + bool size_ok = true; + for (int g = 0; g < k; g++) { + if (g < (int)ctx.machine_info.max_group_size.size() && groups_count[g] > ctx.machine_info.max_group_size[g]) + size_ok = false; + } + if (size_ok) + prefer_level += MAX_SIZE_LIMIT_REWARD; + + if (ctx.group_info.strategy == FGStrategy::BestFit) { + bool all_full = true; + for (int g = 0; g < k; g++) { + if (g < (int)ctx.machine_info.max_group_size.size() && groups_count[g] < ctx.machine_info.max_group_size[g]) + all_full = false; + } + if (all_full) + prefer_level += BEST_FIT_LIMIT_REWARD; + } + + for (int g = 0; g < k; g++) { + if (g < (int)ctx.machine_info.prefer_non_model_filament.size() && ctx.machine_info.prefer_non_model_filament[g]) { + for (int fidx : nozzles_filaments[g]) { + if (ctx.model_info.filament_info[used_filaments[fidx]].usage_type == SupportOnly) + prefer_level += SUPPORT_PREFER_REWARD; + } + } + } + + // Build full map and evaluate + std::vector full_map(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id); + for (int i = 0; i < n; ++i) + full_map[used_filaments[i]] = used_labels[i]; + + int flush_vol = 0; + double score = full_evaluate(used_filaments, full_map, ctx, get_custom_seq, &flush_vol); + + int master_ex_id = ctx.machine_info.master_extruder_id; + if (master_ex_id < k && groups_count[master_ex_id] < (int)(used_filaments.size() + 1) / 2) + score += ABSOLUTE_FLUSH_GAP_TOLERANCE; + + if (prefer_level > best_prefer_level || (prefer_level == best_prefer_level && score < best_score)) { + best_score = score; + best_prefer_level = prefer_level; + best_full_map = full_map; + best_flush = flush_vol; + } + + MemoryedGroup mg(used_labels, score, prefer_level); + update_memoryed_groups(mg, ctx.group_info.max_gap_threshold, m_memoryed_heap); + } + + if (cost) *cost = best_flush; + return best_full_map; + } + + std::vector FilamentGroup::calc_group_by_kmedoids( + int k, + const std::vector& used_filaments, + const std::unordered_map>& unplaceable_limits, + int* cost, + int timeout_ms) + { + auto distance_evaluator = std::make_shared(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); + PAM.set_unplacable_limits(unplaceable_limits); + PAM.set_memory_threshold(ctx.group_info.max_gap_threshold); + + std::vector, int>> cluster_size_limit; + for (auto& [extruder_id, nozzles] : ctx.nozzle_info.extruder_nozzle_list) { + std::pair, int> clusters; + clusters.first = std::set(nozzles.begin(), nozzles.end()); + clusters.second = ctx.machine_info.max_group_size.at(extruder_id); + cluster_size_limit.emplace_back(clusters); + } + PAM.set_cluster_group_size(cluster_size_limit); + + PAM.do_clustering(ctx, timeout_ms, 30); + + m_memoryed_heap = PAM.get_memoryed_groups(); + + auto labels = PAM.get_cluster_labels(); + std::vector full_map(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id); + for (int i = 0; i < (int)labels.size(); ++i) + full_map[used_filaments[i]] = labels[i]; + + if (cost) { + int flush_vol = 0; + full_evaluate(used_filaments, full_map, ctx, get_custom_seq, &flush_vol); + *cost = flush_vol; + } + + return full_map; } /** @@ -128,20 +395,26 @@ namespace Slic3r * considered valid. * * @param map_lists Group list with similar flush count + * @param nozzle_lists nozzle_id -> extruder_id * @param used_filaments Idx of used filaments * @param used_filament_info Information of filaments used * @param machine_filament_info Information of filaments loaded in printer * @param color_threshold Threshold for considering colors to be similar * @return The group that best fits the filament distribution in AMS */ - std::vector select_best_group_for_ams(const std::vector>& map_lists, + std::vector select_best_group_for_ams(const std::vector>& filament_to_nozzles, + const std::vector& nozzle_list, const std::vector& used_filaments, - const std::vector& used_filament_info, + const std::vector& used_filament_info, const std::vector>& machine_filament_info_, + const bool has_filament_switcher, const double color_threshold) { using namespace FlushPredict; + if (has_filament_switcher) + return filament_to_nozzles.size() ? filament_to_nozzles.front() : std::vector(); + const int fail_cost = 9999; // these code is to make we machine filament info size is 2 @@ -151,12 +424,13 @@ namespace Slic3r int best_cost = std::numeric_limits::max(); std::vectorbest_map; - for (auto& map : map_lists) { + for (auto &filament_to_nozzle : filament_to_nozzles) { std::vector> group_filaments(2); std::vector>group_colors(2); for (size_t i = 0; i < used_filaments.size(); ++i) { - int target_group = map[used_filaments[i]] == 0 ? 0 : 1; + auto &nozzle = nozzle_list[filament_to_nozzle[used_filaments[i]]]; + int target_group = nozzle.extruder_id == 0 ? 0 : 1; group_colors[target_group].emplace_back(used_filament_info[i].color); group_filaments[target_group].emplace_back(i); } @@ -211,7 +485,7 @@ namespace Slic3r if (best_map.empty() || group_cost < best_cost) { best_cost = group_cost; - best_map = map; + best_map = filament_to_nozzle; } } @@ -228,7 +502,7 @@ namespace Slic3r return; } double gap_rate = (double)std::abs(elem.cost - best.cost) / (double)best.cost; - if (gap_rate < gap_threshold) + if (gap_rate <= gap_threshold) heap.push(elem); }; @@ -271,11 +545,11 @@ namespace Slic3r for (const auto& f : lf) used_filaments_set.insert(f); std::vectorused_filaments(used_filaments_set.begin(), used_filaments_set.end()); - std::sort(used_filaments.begin(), used_filaments.end()); + sort_remove_duplicates(used_filaments); return used_filaments; } - FlushDistanceEvaluator::FlushDistanceEvaluator(const FlushMatrix& flush_matrix, const std::vector& used_filaments, const std::vector>& layer_filaments, double p) + FlushDistanceEvaluator::FlushDistanceEvaluator(const std::vector& flush_matrix, const std::vector& used_filaments, const std::vector>& layer_filaments, double p) { //calc pair counts std::vector>count_matrix(used_filaments.size(), std::vector(used_filaments.size())); @@ -296,200 +570,358 @@ namespace Slic3r } } - m_distance_matrix.resize(used_filaments.size(), std::vector(used_filaments.size())); + m_distance_matrix.resize(flush_matrix.size(), std::vector>(used_filaments.size(), std::vector(used_filaments.size()))); for (size_t i = 0; i < used_filaments.size(); ++i) { for (size_t j = 0; j < used_filaments.size(); ++j) { - if (i == j) - m_distance_matrix[i][j] = 0; - else { + for (size_t k = 0; k < flush_matrix.size(); k++) { + if (i == j) + m_distance_matrix[k][i][j] = 0; + else { //TODO: check m_flush_matrix - float max_val = std::max(flush_matrix[used_filaments[i]][used_filaments[j]], flush_matrix[used_filaments[j]][used_filaments[i]]); - float min_val = std::min(flush_matrix[used_filaments[i]][used_filaments[j]], flush_matrix[used_filaments[j]][used_filaments[i]]); - m_distance_matrix[i][j] = (max_val * p + min_val * (1 - p)) * count_matrix[i][j]; - } - } - } - } - - double FlushDistanceEvaluator::get_distance(int idx_a, int idx_b) const - { - assert(0 <= idx_a && idx_a < m_distance_matrix.size()); - assert(0 <= idx_b && idx_b < m_distance_matrix.size()); - - return m_distance_matrix[idx_a][idx_b]; - } - - std::vector KMediods2::cluster_small_data(const std::map& unplaceable_limits, const std::vector& group_size) - { - std::vectorlabels(m_elem_count, -1); - std::vectornew_group_size = group_size; - - for (auto& [elem, center] : unplaceable_limits) { - if (labels[elem] == -1) { - int gid = 1 - center; - labels[elem] = gid; - new_group_size[gid] -= 1; - } - } - - for (auto& label : labels) { - if (label == -1) { - int gid = -1; - for (size_t idx = 0; idx < new_group_size.size(); ++idx) { - if (new_group_size[idx] > 0) { - gid = idx; - break; + float max_val = std::max(flush_matrix[k][used_filaments[i]][used_filaments[j]], flush_matrix[k][used_filaments[j]][used_filaments[i]]); + float min_val = std::min(flush_matrix[k][used_filaments[i]][used_filaments[j]], flush_matrix[k][used_filaments[j]][used_filaments[i]]); + m_distance_matrix[k][i][j] = (max_val * p + min_val * (1 - p)) * (std::max(count_matrix[i][j], 1)); } } - if (gid != -1) { - label = gid; - new_group_size[gid] -= 1; - } - else { - label = m_default_group_id; - } } } - - return labels; } - std::vector KMediods2::assign_cluster_label(const std::vector& center, const std::map& unplaceable_limtis, const std::vector& group_size, const FGStrategy& strategy) + double FlushDistanceEvaluator::get_distance(int idx_a, int idx_b, int extruder_id) const { - struct Comp { - bool operator()(const std::pair& a, const std::pair& b) { - return a.second > b.second; - } - }; + assert(0 <= idx_a && idx_a < m_distance_matrix[extruder_id].size()); + assert(0 <= idx_b && idx_b < m_distance_matrix[extruder_id].size()); - std::vector>groups(2); - std::vectornew_max_group_size = group_size; - // store filament idx and distance gap between center 0 and center 1 - std::priority_queue, std::vector>, Comp>min_heap; - - for (int i = 0; i < m_elem_count; ++i) { - if (auto it = unplaceable_limtis.find(i); it != unplaceable_limtis.end()) { - int gid = it->second; - assert(gid == 0 || gid == 1); - groups[1 - gid].insert(i); // insert to group - new_max_group_size[1 - gid] = std::max(new_max_group_size[1 - gid] - 1, 0); // decrease group_size - continue; - } - int distance_to_0 = m_evaluator->get_distance(i, center[0]); - int distance_to_1 = m_evaluator->get_distance(i, center[1]); - min_heap.push({ i,distance_to_0 - distance_to_1 }); - } - - bool have_enough_size = (min_heap.size() <= (new_max_group_size[0] + new_max_group_size[1])); - - if (have_enough_size || strategy == FGStrategy::BestFit) { - while (!min_heap.empty()) { - auto top = min_heap.top(); - min_heap.pop(); - if (groups[0].size() < new_max_group_size[0] && (top.second <= 0 || groups[1].size() >= new_max_group_size[1])) - groups[0].insert(top.first); - else if (groups[1].size() < new_max_group_size[1] && (top.second > 0 || groups[0].size() >= new_max_group_size[0])) - groups[1].insert(top.first); - else { - if (top.second <= 0) - groups[0].insert(top.first); - else - groups[1].insert(top.first); - } - } - } - else { - while (!min_heap.empty()) { - auto top = min_heap.top(); - min_heap.pop(); - if (top.second <= 0) - groups[0].insert(top.first); - else - groups[1].insert(top.first); - } - } - - std::vectorlabels(m_elem_count); - for (auto& f : groups[0]) - labels[f] = 0; - for (auto& f : groups[1]) - labels[f] = 1; - - return labels; + return m_distance_matrix[extruder_id][idx_a][idx_b]; } - int KMediods2::calc_cost(const std::vector& labels, const std::vector& medoids) + double TimeEvaluator::get_estimated_time(const std::vector& filament_map) const { + double time = 0; + for(auto &elem : m_speed_info.filament_print_time){ + int filament_idx = elem.first; + auto extruder_time = elem.second; + int filament_extruder_id = filament_map[filament_idx]; + time += extruder_time[filament_extruder_id]; + } + return time; + } + + + + void KMediods::set_cluster_group_size(const std::vector, int>> &cluster_group_size) + { + m_cluster_group_size = cluster_group_size; + m_nozzle_to_extruder.resize(m_k, 0); + for (int i = 0; i < m_cluster_group_size.size(); i++) { + for (auto nozzle_id : m_cluster_group_size[i].first) m_nozzle_to_extruder[nozzle_id] = i; + } + } + + int KMediods::calc_cost(const std::vector& cluster_labels, const std::vector& cluster_centers,int cluster_id) + { + assert(m_evaluator); int total_cost = 0; - for (int i = 0; i < m_elem_count; ++i) - total_cost += m_evaluator->get_distance(i, medoids[labels[i]]); + + std::vector> nozzle_cost(m_k,{0,0.0}); + std::vector nozzle_filaments(m_k, 0); + for (int i = 0; i < m_elem_count; ++i) { + if (cluster_id != -1 && cluster_labels[i] != cluster_id) + continue; + if (cluster_centers[cluster_labels[i]] == -1) + continue; + + nozzle_filaments[cluster_labels[i]]++; + for (int j = i + 1; j < m_elem_count; ++j) { + int nozzle_i = cluster_labels[i]; + int nozzle_j = cluster_labels[j]; + if (nozzle_i == nozzle_j) { + nozzle_cost[nozzle_i].first++; + nozzle_cost[nozzle_j].second += m_evaluator->get_distance(i, j, m_nozzle_to_extruder[nozzle_i]); + } + } + } + for (size_t i = 0; i < nozzle_cost.size(); ++i) { + if (nozzle_filaments[i] > 0 && nozzle_cost[i].second > 0) + total_cost += nozzle_cost[i].second / nozzle_cost[i].first * (nozzle_filaments[i] - 1); + } + return total_cost; } - void KMediods2::do_clustering(const FGStrategy& g_strategy, int timeout_ms) + bool KMediods::have_enough_size(const std::vector& cluster_size, const std::vector, int>>& cluster_group_size,int elem_count) + { + bool have_enough_size = true; + std::optionalcluster_sum; + std::optionalcluster_group_sum; + + if (!cluster_size.empty()) + cluster_sum = std::accumulate(cluster_size.begin(), cluster_size.end(), 0); + if (!cluster_group_size.empty()) + cluster_group_sum = std::accumulate(cluster_group_size.begin(), cluster_group_size.end(), 0, [](int a, const std::pair, int>& p) {return a + p.second; }); + if (cluster_sum.has_value()) + have_enough_size &= (cluster_sum >= elem_count); + if (cluster_group_sum.has_value()) + have_enough_size &= (cluster_group_sum >= elem_count); + return have_enough_size; + } + + + // make sure each cluster has at least one element + std::vector KMediods::init_cluster_center(const std::unordered_map>& placeable_limits, const std::unordered_map>& unplaceable_limits,const std::vector& cluster_size,const std::vector,int>>& cluster_group_size, int seed) + { + // max flow network + std::vector l_nodes(m_elem_count); // represent the filament idx, to be shuffled + std::vector r_nodes(m_k); // represent the group idx + std::iota(l_nodes.begin(), l_nodes.end(), 0); + std::iota(r_nodes.begin(), r_nodes.end(), 0); + + std::unordered_map> shuffled_placeable_limits; + std::unordered_map> shuffled_unplaceable_limits; + // shuffle the filaments and transfer placeable,unplaceable limits + { + std::mt19937 rng(seed); + std::shuffle(l_nodes.begin(), l_nodes.end(), rng); + + std::unordered_mapidx_transfer; + for (size_t idx = 0; idx < l_nodes.size(); ++idx){ + int new_idx = std::find(l_nodes.begin(),l_nodes.end(), idx) - l_nodes.begin(); + idx_transfer[idx] = new_idx; + } + for (auto& elem : placeable_limits) + shuffled_placeable_limits[idx_transfer[elem.first]] = elem.second; + for (auto& elem : unplaceable_limits) + shuffled_unplaceable_limits[idx_transfer[elem.first]] = elem.second; + } + + + MaxFlowSolver M(l_nodes, r_nodes, shuffled_placeable_limits, shuffled_unplaceable_limits); + auto ret = M.solve(); + + // A remaining -1 means some filaments cannot be placed under the limit. We ignore the -1 here since we + // are deciding the cluster center; the -1 can be handled in later steps. + std::vector cluster_center(m_k, -1); + for (size_t idx = 0; idx < ret.size(); ++idx) { + if (ret[idx] != -1) { + cluster_center[ret[idx]] = l_nodes[idx]; + } + } + + return cluster_center; + } + + std::vector KMediods::assign_cluster_label(const std::vector& center, const std::unordered_map>& placeable_limits, const std::unordered_map>& unplaceable_limits, const std::vector& cluster_size, const std::vector, int>>& cluster_group_size) + { + std::vector labels(m_elem_count, -1); + std::vector l_nodes(m_elem_count); + std::vector r_nodes(m_k); + std::iota(l_nodes.begin(), l_nodes.end(), 0); + std::iota(r_nodes.begin(), r_nodes.end(), 0); + + std::vector> distance_matrix(m_elem_count, std::vector(m_k)); + for (int i = 0; i < m_elem_count; ++i) { + for (int j = 0; j < m_k; ++j) { + if (center[j] == -1) + distance_matrix[i][j] = static_cast(MaxFlowGraph::MCMF_MAX_EDGE_COST); + else + distance_matrix[i][j] = m_evaluator->get_distance(i, center[j], m_nozzle_to_extruder[j]); + } + } + + // only consider the size limit if the group can contain all of the filaments + std::vector r_nodes_capacity = {}; + std::vector, int>> r_nodes_group_capacity = {}; + if (have_enough_size(cluster_size, cluster_group_size, m_elem_count)) { + r_nodes_capacity = cluster_size; + r_nodes_group_capacity = cluster_group_size; + } + else { + // TODO: throw exception here? + // adjust group size to elem count if the group cannot contain all of the filaments + r_nodes_capacity = std::vector(m_k, m_elem_count); + } + std::vector l_nodes_capacity(l_nodes.size(),1); + //for (size_t idx = 0; idx < center.size(); ++idx) + // if (center[idx] != -1) + // l_nodes_capacity[center[idx]] = 0; + + + // Each group can receive up to m_elem_count materials at most, so the flow from r_nodes to sink is adjusted to m_elem_count. + MinFlushFlowSolver M(distance_matrix, l_nodes, r_nodes, placeable_limits, unplaceable_limits, l_nodes_capacity, r_nodes_capacity, r_nodes_group_capacity); + auto ret = M.solve(); + + for (size_t idx = 0; idx < ret.size(); ++idx) { + if (ret[idx] != MaxFlowGraph::INVALID_ID) { + labels[l_nodes[idx]] = r_nodes[ret[idx]]; + } + } + + for (size_t idx = 0; idx < center.size(); ++idx) + if (center[idx] != -1) + assert(labels[center[idx]] == idx); + + //for (size_t idx = 0; idx < center.size(); ++idx) { + // if (center[idx] != -1) { + // labels[center[idx]] = idx; + // } + //} + + // If there are materials that have not been grouped in the last step, assign them to a valid group. + for (size_t idx = 0; idx < labels.size(); ++idx) { + if (labels[idx] == -1) { + int fallback = m_default_group_id; + auto it = unplaceable_limits.find(static_cast(idx)); + if (it != unplaceable_limits.end()) { + for (int nid = 0; nid < m_k; ++nid) { + if (std::find(it->second.begin(), it->second.end(), nid) == it->second.end()) { + fallback = nid; + break; + } + } + } + labels[idx] = fallback; + } + } + + return labels; + } + + /* + 1.Select initial medoids randomly + 2.Iterate while the cost decreases: + 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) { FlushTimeMachine T; T.time_machine_start(); - if (m_elem_count < m_k) { - m_cluster_labels = cluster_small_data(m_unplaceable_limits, m_max_cluster_size); - { - std::vectorcluster_center(m_k, -1); - for (size_t idx = 0; idx < m_cluster_labels.size(); ++idx) { - if (cluster_center[m_cluster_labels[idx]] == -1) - cluster_center[m_cluster_labels[idx]] = idx; - } - MemoryedGroup g(m_cluster_labels, calc_cost(m_cluster_labels, cluster_center), 1); - update_memoryed_groups(g, memory_threshold, memoryed_groups); - } - return; - } + const std::vector used_filaments = collect_sorted_used_filaments(context.model_info.layer_filaments); - std::vectorbest_labels; - int best_cost = std::numeric_limits::max(); + auto build_full_map = [&](const std::vector& labels) -> std::vector { + std::vector full_map(context.group_info.total_filament_num, m_default_group_id); + for (int i = 0; i < (int)labels.size(); ++i) + full_map[used_filaments[i]] = labels[i]; + return full_map; + }; - for (int center_0 = 0; center_0 < m_elem_count; ++center_0) { - if (auto iter = m_unplaceable_limits.find(center_0); iter != m_unplaceable_limits.end() && iter->second == 0) - continue; - for (int center_1 = 0; center_1 < m_elem_count; ++center_1) { - if (center_0 == center_1) - continue; - if (auto iter = m_unplaceable_limits.find(center_1); iter != m_unplaceable_limits.end() && iter->second == 1) - continue; + auto evaluate_labels = [&](const std::vector& labels) -> double { + auto full_map = build_full_map(labels); + return full_evaluate(used_filaments, full_map, context); + }; - std::vectornew_centers = { center_0,center_1 }; - std::vectornew_labels = assign_cluster_label(new_centers, m_unplaceable_limits, m_max_cluster_size, g_strategy); + std::vector best_cluster_centers = std::vector(m_k, 0); + std::vector best_cluster_labels = std::vector(m_elem_count, m_default_group_id); + double best_cluster_cost = std::numeric_limits::max(); + int retry_count = 0; - int new_cost = calc_cost(new_labels, new_centers); - if (new_cost < best_cost) { - best_cost = new_cost; - best_labels = new_labels; + while (retry_count < retry && T.time_machine_end() < timeout_ms) { + std::vector curr_cluster_centers = init_cluster_center(m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size, retry_count); + std::vector 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); + + MemoryedGroup g(curr_cluster_labels, curr_cluster_cost, 1); + update_memoryed_groups(g, memory_threshold, memoryed_groups); + + bool mediods_changed = true; + while (mediods_changed && T.time_machine_end() < timeout_ms) { + mediods_changed = false; + double best_swap_cost = curr_cluster_cost; + int best_swap_cluster = -1; + int best_swap_elem = -1; + + for (size_t cluster_id = 0; cluster_id < m_k; ++cluster_id) { + if (curr_cluster_centers[cluster_id] == -1) continue; + for (int elem = 0; elem < m_elem_count; ++elem) { + if (std::find(curr_cluster_centers.begin(), curr_cluster_centers.end(), elem) != curr_cluster_centers.end() || + std::find(m_unplaceable_limits[cluster_id].begin(), m_unplaceable_limits[cluster_id].end(), elem) != m_unplaceable_limits[cluster_id].end()) + continue; + std::vector tmp_centers = curr_cluster_centers; + tmp_centers[cluster_id] = elem; + std::vector tmp_labels = assign_cluster_label(tmp_centers, m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size); + double tmp_cost = evaluate_labels(tmp_labels); + + if (tmp_cost < best_swap_cost) { + best_swap_cost = tmp_cost; + best_swap_cluster = cluster_id; + best_swap_elem = elem; + mediods_changed = true; + } + } } - { - MemoryedGroup g(new_labels,new_cost,1); + if (mediods_changed) { + curr_cluster_centers[best_swap_cluster] = best_swap_elem; + curr_cluster_labels = assign_cluster_label(curr_cluster_centers, m_placeable_limits, m_unplaceable_limits, m_max_cluster_size, m_cluster_group_size); + curr_cluster_cost = evaluate_labels(curr_cluster_labels); + + MemoryedGroup g(curr_cluster_labels, curr_cluster_cost, 1); update_memoryed_groups(g, memory_threshold, memoryed_groups); } - - if (T.time_machine_end() > timeout_ms) - break; } - if (T.time_machine_end() > timeout_ms) - break; + + if (curr_cluster_cost < best_cluster_cost) { + best_cluster_centers = curr_cluster_centers; + best_cluster_cost = curr_cluster_cost; + best_cluster_labels = curr_cluster_labels; + } + retry_count += 1; } - this->m_cluster_labels = best_labels; + m_cluster_labels = best_cluster_labels; } std::vector FilamentGroup::calc_min_flush_group(int* cost) { auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments); - int used_filament_num = used_filaments.size(); + int n = (int)used_filaments.size(); + int k = (int)ctx.nozzle_info.nozzle_list.size(); - if (used_filament_num < 10) - return calc_min_flush_group_by_enum(used_filaments, cost); + std::unordered_map> unplaceable_limits; + extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unplaceable_limits); + unplaceable_limits = rebuild_nozzle_unprintables(used_filaments, unplaceable_limits, ctx.group_info.filament_volume_map); + + m_memoryed_heap = MemoryedGroupHeap(); + std::vector result; + + long long estimated = estimate_dedup_enum_count(k, n, ctx); + if (estimated < ENUM_THRESHOLD) + result = calc_group_by_enum(k, used_filaments, unplaceable_limits, cost); else - return calc_min_flush_group_by_pam2(used_filaments, cost, 500); + result = calc_group_by_kmedoids(k, used_filaments, unplaceable_limits, cost, 3000); + + change_memoryed_heaps_to_arrays(m_memoryed_heap, ctx.group_info.total_filament_num, used_filaments, m_memoryed_groups); + + return result; + } + + std::map FilamentGroup::rebuild_unprintables(const std::vector& used_filaments, const std::map& extruder_unprintables) + { + std::map ret; + for (int f_idx = 0; f_idx < used_filaments.size(); f_idx++) { + int unprintable_ext = -1; + if (extruder_unprintables.find(f_idx) != extruder_unprintables.end()) { + unprintable_ext = extruder_unprintables.at(f_idx); + } + + bool multi_unprintable = false; + auto unprintable_volumes = ctx.model_info.unprintable_volumes[used_filaments[f_idx]]; + for (int nozzle_idx = 0; nozzle_idx != ctx.nozzle_info.nozzle_list.size(); nozzle_idx++) { + auto nozzle_info = ctx.nozzle_info.nozzle_list[nozzle_idx]; + + if (unprintable_volumes.count(nozzle_info.volume_type)) { + if (unprintable_ext == -1) + unprintable_ext = nozzle_info.extruder_id; + else if (unprintable_ext != nozzle_info.extruder_id) + multi_unprintable = true; + } + } + + if (!multi_unprintable && unprintable_ext != -1) ret[f_idx] = unprintable_ext; + + } + return ret; } std::unordered_map> FilamentGroup::try_merge_filaments() @@ -577,6 +1009,11 @@ namespace Slic3r std::vector FilamentGroup::calc_filament_group(int* cost) { + /*auto extruder_variant_list = ctx.nozzle_info.extruder_nozzle_list; + for (auto nozzle : ctx.nozzle_info.nozzle_list) + if (nozzle.volume_type == NozzleVolumeType::nvtTPUHighFlow) + return calc_filament_group_for_tpu(cost);*/ + try { if (FGMode::MatchMode == ctx.group_info.mode) return calc_filament_group_for_match(cost); @@ -584,18 +1021,16 @@ namespace Slic3r catch (const FilamentGroupException& e) { } - auto merged_map = try_merge_filaments(); - rebuild_context(merged_map); - auto filamnet_map = calc_filament_group_for_flush(cost); - return seperate_merged_filaments(filamnet_map, merged_map); + return calc_filament_group_for_flush(cost); } std::vector FilamentGroup::calc_filament_group_for_match(int* cost) { using namespace FlushPredict; + constexpr int SupportPreferScore = 3; auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments); - std::vector used_filament_list; + std::vector used_filament_list; for (auto f : used_filaments) used_filament_list.emplace_back(ctx.model_info.filament_info[f]); @@ -613,6 +1048,7 @@ namespace Slic3r std::map unprintable_limit_indices; // key stores filament idx in used_filament, value stores unprintable extruder extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unprintable_limit_indices); + unprintable_limit_indices = rebuild_unprintables(used_filaments, unprintable_limit_indices); std::vector> color_dist_matrix(used_filament_list.size(), std::vector(machine_filament_list.size())); for (size_t i = 0; i < used_filament_list.size(); ++i) { @@ -652,19 +1088,17 @@ namespace Slic3r return unlink_limits; }; - auto optimize_map_to_machine_filament = [&](const std::vector& map_to_machine_filament, const std::vector& l_nodes, const std::vector& r_nodes, std::vector& filament_map, bool consider_capacity) { + auto optimize_map_to_machine_filament = [&](const std::vector& map_to_machine_filament, const std::vector& l_nodes, const std::vector& r_nodes, std::vector& filament_map) { std::vector ungrouped_filaments; std::vector filaments_to_optimize; auto map_filament_to_machine_filament = [&](int filament_idx, int machine_filament_idx) { auto& machine_filament = machine_filament_list[machine_filament_idx]; - machine_filament_capacity[machine_filament_idx] = std::max(0, machine_filament_capacity[machine_filament_idx] - 1); // decrease machine filament capacity filament_map[used_filaments[filament_idx]] = machine_filament.extruder_id; // set extruder id to filament map extruder_filament_count[machine_filament.extruder_id] += 1; // increase filament count in extruder }; auto unmap_filament_to_machine_filament = [&](int filament_idx, int machine_filament_idx) { auto& machine_filament = machine_filament_list[machine_filament_idx]; - machine_filament_capacity[machine_filament_idx] += 1; // increase machine filament capacity extruder_filament_count[machine_filament.extruder_id] -= 1; // increase filament count in extruder }; @@ -684,25 +1118,63 @@ namespace Slic3r // try to optimize the result for (auto idx : filaments_to_optimize) { int filament_idx = l_nodes[idx]; + bool is_support_filament = used_filament_list[filament_idx].usage_type == FilamentUsageType::SupportOnly; int old_machine_filament_idx = r_nodes[map_to_machine_filament[idx]]; auto& old_machine_filament = machine_filament_list[old_machine_filament_idx]; - int curr_gap = std::abs(extruder_filament_count[0] - extruder_filament_count[1]); unmap_filament_to_machine_filament(filament_idx, old_machine_filament_idx); auto optional_filaments = machine_filament_set[old_machine_filament]; - auto iter = optional_filaments.begin(); - for (; iter != optional_filaments.end(); ++iter) { - int new_extruder_id = machine_filament_list[*iter].extruder_id; - int new_gap = std::abs(extruder_filament_count[new_extruder_id] + 1 - extruder_filament_count[1 - new_extruder_id]); - if (new_gap < curr_gap && (!consider_capacity || machine_filament_capacity[*iter] > 0)) { - map_filament_to_machine_filament(filament_idx, *iter); - break; + + // Phase 1: collect all candidates and compute their preference scores + std::vector> valid_candidates; // available machine-filament idx and its score + for (auto machine_filament : optional_filaments) { + int new_extruder_id = machine_filament_list[machine_filament].extruder_id; + + // preference score for this assignment + int preference_score = 0; + bool new_extruder_prefer_support = ctx.machine_info.prefer_non_model_filament[new_extruder_id]; + + // reward a support filament assigned to a support-preferring nozzle + if (is_support_filament && new_extruder_prefer_support) { + preference_score += SupportPreferScore; + } + + valid_candidates.emplace_back(machine_filament, preference_score); + } + // Phase 2: determine the best preference score + int best_preference_score = 0; + for (const auto& candidate : valid_candidates) { + if (candidate.second >= best_preference_score) { + best_preference_score = candidate.second; } } - if (iter == optional_filaments.end()) + // Phase 3: among candidates with the best preference score, pick the most load-balanced one + int best_candidate = -1; + int best_gap = std::numeric_limits::max(); + + for (const auto& candidate : valid_candidates) { + // only consider candidates with the best preference score + int machine_filament = candidate.first; + int score = candidate.second; + if (score == best_preference_score) { + int new_extruder_id = machine_filament_list[machine_filament].extruder_id; + int new_gap = std::abs(extruder_filament_count[new_extruder_id] + 1 - extruder_filament_count[1 - new_extruder_id]); + + // among equal-preference candidates, pick the one giving the most balanced load + if (new_gap < best_gap) { + best_gap = new_gap; + best_candidate = machine_filament; + } + } + } + // apply the best choice + if (best_candidate != -1) { + map_filament_to_machine_filament(filament_idx, best_candidate); + } else { map_filament_to_machine_filament(filament_idx, old_machine_filament_idx); + } } return ungrouped_filaments; }; @@ -718,7 +1190,7 @@ namespace Slic3r { MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, unlink_limits_full); - ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes,group,false); + ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes,group); if (ungrouped_filaments.empty()) return group; } @@ -731,7 +1203,7 @@ namespace Slic3r }); MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, unlink_limits); - ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group,false); + ungrouped_filaments = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group); if (ungrouped_filaments.empty()) return group; } @@ -740,7 +1212,7 @@ namespace Slic3r { l_nodes = ungrouped_filaments; MatchModeGroupSolver s(color_dist_matrix, l_nodes, r_nodes, machine_filament_capacity, {}); - auto ret = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group,false); + auto ret = optimize_map_to_machine_filament(s.solve(), l_nodes, r_nodes, group); for (size_t idx = 0; idx < ret.size(); ++idx) { if (ret[idx] == MaxFlowGraph::INVALID_ID) assert(false); @@ -760,140 +1232,253 @@ namespace Slic3r std::vector> memoryed_maps = this->m_memoryed_groups; memoryed_maps.insert(memoryed_maps.begin(), ret); - std::vector optimized_ret = optimize_group_for_master_extruder(used_filaments, ctx, ret); - if (optimized_ret != ret) - memoryed_maps.insert(memoryed_maps.begin(), optimized_ret); - std::vector used_filament_info; for (auto f : used_filaments) { used_filament_info.emplace_back(ctx.model_info.filament_info[f]); } - ret = select_best_group_for_ams(memoryed_maps, used_filaments, used_filament_info, ctx.machine_info.machine_filament_info); + ret = select_best_group_for_ams(memoryed_maps, ctx.nozzle_info.nozzle_list, used_filaments, used_filament_info, ctx.machine_info.machine_filament_info, ctx.group_info.has_filament_switcher); return ret; } + std::vector FilamentGroup::calc_filament_group_for_tpu(int *cost) { + + auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments); + std::vector used_filament_list; + for (auto f : used_filaments) + used_filament_list.emplace_back(ctx.model_info.filament_info[f]); + + std::vector> print_time_matrix(used_filaments.size(), std::vector(ctx.nozzle_info.extruder_nozzle_list.size())); + for (int i = 0; i < used_filaments.size(); ++i){ + for (int j = 0; j < ctx.nozzle_info.extruder_nozzle_list.size(); ++j){ + print_time_matrix[i][j] = ctx.speed_info.filament_print_time[used_filaments[i]][j]; + if (ctx.nozzle_info.nozzle_list[j].volume_type == nvtTPUHighFlow) // when both TPU High Flow and other nozzle types exist, prefer assigning filament to the TPU High Flow nozzle + print_time_matrix[i][j] *= 0.9; + } + } + + std::vector l_nodes(used_filaments.size()); + std::iota(l_nodes.begin(), l_nodes.end(), 0); + std::vector r_nodes(ctx.nozzle_info.extruder_nozzle_list.size()); + std::iota(r_nodes.begin(), r_nodes.end(), 0); + std::vector machine_filament_capacity({int(used_filaments.size()), int(used_filaments.size())}); + + std::map unprintable_limit_indices; // key stores filament idx in used_filament, value stores unprintable extruder + extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unprintable_limit_indices); + unprintable_limit_indices = rebuild_unprintables(used_filaments, unprintable_limit_indices); + + std::unordered_map> unlink_limits(used_filaments.size()); + for (int i = 0; i < used_filaments.size(); i++) { + auto iter = unprintable_limit_indices.find(i); + if (iter == unprintable_limit_indices.end() || iter->second < 0 || iter->second >= 2) continue; + unlink_limits[i].emplace_back(iter->second); + } + + MatchModeGroupSolver s(print_time_matrix, l_nodes, r_nodes, machine_filament_capacity, unlink_limits); + auto ret = s.solve(); + for (size_t idx = 0; idx < ret.size(); ++idx) { + if (ret[idx] == MaxFlowGraph::INVALID_ID) { + assert(false); + ret[idx] = 1; + } + } + std::vector group(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id); + for (int i = 0; i < ret.size(); ++i) group[used_filaments[i]] = ret[i]; + return group; + } // sorted used_filaments - std::vector FilamentGroup::calc_min_flush_group_by_enum(const std::vector& used_filaments, int* cost) + + std::unordered_map> FilamentGroup::rebuild_nozzle_unprintables(const std::vector& used_filaments, const std::unordered_map>& extruder_unprintables, const std::vector& filament_volume_map) { - static constexpr int UNPLACEABLE_LIMIT_REWARD = 100; // reward value if the group result follows the unprintable limit - static constexpr int MAX_SIZE_LIMIT_REWARD = 10; // reward value if the group result follows the max size per extruder - static constexpr int BEST_FIT_LIMIT_REWARD = 1; // reward value if the group result try to fill the max size per extruder + std::unordered_map> nozzle_unprintables; - MemoryedGroupHeap memoryed_groups; + for(size_t fidx = 0 ;fidx unexpected_extruders; + if(extruder_unprintables.find(fidx) != extruder_unprintables.end()){ + unexpected_extruders = extruder_unprintables.at(fidx); + } - auto bit_count_one = [](uint64_t n) - { - int count = 0; - while (n != 0) - { - n &= n - 1; - count++; + auto unprintable_volumes = ctx.model_info.unprintable_volumes[used_filaments[fidx]]; + + std::vector unprintable_nozzles; + for(size_t nozzle_idx =0 ;nozzle_idx < ctx.nozzle_info.nozzle_list.size(); ++nozzle_idx){ + auto nozzle_info = ctx.nozzle_info.nozzle_list[nozzle_idx]; + + if(std::find(unexpected_extruders.begin(), unexpected_extruders.end(), nozzle_info.extruder_id)!= unexpected_extruders.end() || (expected_volume!=nvtHybrid && expected_volume != nozzle_info.volume_type) || + (unprintable_volumes.count(nozzle_info.volume_type) != 0)) + unprintable_nozzles.push_back(nozzle_idx); + } + if(unprintable_nozzles.empty()) + continue; + + sort_remove_duplicates(unprintable_nozzles); + nozzle_unprintables[fidx] = unprintable_nozzles; + } + + return nozzle_unprintables; + } + + + std::vector calc_filament_group_for_match_multi_nozzle(const FilamentGroupContext& ctx) + { + FilamentGroup fg1(ctx); + auto filament_extruder_map = fg1.calc_filament_group_for_match(); + + FilamentGroupContext new_ctx = ctx; + auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments); + for(size_t idx = 0; idx < used_filaments.size(); ++idx) + new_ctx.model_info.unprintable_filaments[1 - filament_extruder_map[used_filaments[idx]]].insert(used_filaments[idx]); + new_ctx.machine_info.max_group_size.assign(new_ctx.machine_info.max_group_size.size(), std::numeric_limits::max()); + FilamentGroup fg(new_ctx); + return fg.calc_filament_group_for_flush(); + } + + std::vector plan_filament_nozzle_mapping_and_order(const FilamentGroupContext &ctx) + { + std::vector res; + + // right nodes: nozzles + std::vector r_nodes(ctx.nozzle_info.nozzle_list.size(), -1); + auto initial_nozzle = ctx.nozzle_info.nozzle_status; + for (int r_id = 0; r_id < r_nodes.size(); r_id++) { if (initial_nozzle.count(r_id)) r_nodes[r_id] = initial_nozzle[r_id]; } + + std::vector r_nodes_group(ctx.nozzle_info.nozzle_list.size(), -1); + for (auto &nozzle_info : ctx.nozzle_info.nozzle_list) { r_nodes_group[nozzle_info.group_id] = nozzle_info.extruder_id; } + + int layer_nums = ctx.model_info.layer_filaments.size(); + auto &flush_matrix = ctx.model_info.flush_matrix; + + int prev_layer_last_nozzle_id = -1; + bool used_prev_layer_last_nozzle = false; + + // per-layer filament->nozzle matching + std::vector layer_fil_nozzle_match(ctx.model_info.filament_info.size(), 0); + for (int i = 0; i < layer_nums; i++) { + // left nodes: filaments, deduplicated + const auto &layer_filaments = ctx.model_info.layer_filaments[i]; + std::vector l_nodes(layer_filaments.begin(), layer_filaments.end()); + std::sort(l_nodes.begin(), l_nodes.end()); + l_nodes.erase(std::unique(l_nodes.begin(), l_nodes.end()), l_nodes.end()); + + if (l_nodes.empty()) { + res.emplace_back(FilamentPlanRes{{}, {}}); + continue; + } + + // per-layer queue of filaments used within each nozzle + std::vector> nozzle_fil_deq(r_nodes.size()); + + // build a reverse map from nozzle-loaded filament to nozzle index to speed lookups from O(n) to O(1) + std::unordered_map filament_to_nozzle; + filament_to_nozzle.reserve(r_nodes.size()); + for (size_t noz_id = 0; noz_id < r_nodes.size(); ++noz_id) { + if (r_nodes[noz_id] >= 0) { filament_to_nozzle[r_nodes[noz_id]] = noz_id; } + } + + const int epochs = std::ceil(double(l_nodes.size()) / r_nodes.size()); + for (int j = 0; j < epochs; j++) { + // 1. filter out filaments already matching the state loaded in a nozzle + std::vector remaining_l_nodes; + std::vector remaining_r_nodes; + std::vector remaining_r_nodes_to_origin; + std::vector used_r_nodes(r_nodes.size(), false); + + remaining_l_nodes.reserve(l_nodes.size()); + remaining_r_nodes.reserve(r_nodes.size()); + remaining_r_nodes_to_origin.reserve(r_nodes.size()); + + for (int f_id : l_nodes) { + auto it = filament_to_nozzle.find(f_id); + if (it != filament_to_nozzle.end()) { + size_t noz_id = it->second; + layer_fil_nozzle_match[f_id] = noz_id; + nozzle_fil_deq[noz_id].push_back(f_id); + used_prev_layer_last_nozzle = (noz_id == prev_layer_last_nozzle_id); + used_r_nodes[noz_id] = true; + } else { + remaining_l_nodes.emplace_back(f_id); + } } - return count; - }; + l_nodes = std::move(remaining_l_nodes); - std::mapunplaceable_limit_indices; - extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unplaceable_limit_indices); + for (int r_id = 0; r_id < r_nodes.size(); r_id++) { + if (!used_r_nodes[r_id]) { + remaining_r_nodes.emplace_back(r_nodes[r_id]); + remaining_r_nodes_to_origin.emplace_back(r_id); + } + } - int used_filament_num = used_filaments.size(); - uint64_t max_group_num = (static_cast(1) << used_filament_num); - - int best_cost = std::numeric_limits::max(); - std::vectorbest_label; - int best_prefer_level = 0; - - for (uint64_t i = 0; i < max_group_num; ++i) { - std::vector>groups(2); - for (int j = 0; j < used_filament_num; ++j) { - if (i & (static_cast(1) << j)) - groups[1].insert(j); - else - groups[0].insert(j); + // 2. run min-cost flow on the remaining nodes + GroupMinCostFlowSolver s(flush_matrix, l_nodes, remaining_r_nodes, r_nodes_group); + auto match = s.solve(); + int write = 0; + for (int l_id = 0; l_id < l_nodes.size(); l_id++) { + if (match[l_id] >= 0 && match[l_id] < remaining_r_nodes.size()) { + int noz_id = remaining_r_nodes_to_origin[match[l_id]]; + int filament_id = l_nodes[l_id]; + layer_fil_nozzle_match[filament_id] = noz_id; + r_nodes[noz_id] = filament_id; + nozzle_fil_deq[noz_id].push_back(filament_id); + // update the reverse map + filament_to_nozzle[filament_id] = noz_id; + } else { + l_nodes[write++] = l_nodes[l_id]; + } + } + l_nodes.resize(write); } - int prefer_level = 0; - - if (check_printable(groups, unplaceable_limit_indices)) - prefer_level += UNPLACEABLE_LIMIT_REWARD; - if (groups[0].size() <= ctx.machine_info.max_group_size[0] && groups[1].size() <= ctx.machine_info.max_group_size[1]) - prefer_level += MAX_SIZE_LIMIT_REWARD; - if (FGStrategy::BestFit == ctx.group_info.strategy && groups[0].size() >= ctx.machine_info.max_group_size[0] && groups[1].size() >= ctx.machine_info.max_group_size[1]) - prefer_level += BEST_FIT_LIMIT_REWARD; - - std::vectorfilament_maps(used_filament_num); - for (int i = 0; i < used_filament_num; ++i) { - if (groups[0].find(i) != groups[0].end()) - filament_maps[i] = 0; - if (groups[1].find(i) != groups[1].end()) - filament_maps[i] = 1; + // order the filaments within the layer + int start_extruder = 0; + int start_nozzle = 0; + if (used_prev_layer_last_nozzle) { + start_extruder = ctx.nozzle_info.nozzle_list[prev_layer_last_nozzle_id].extruder_id; + start_nozzle = prev_layer_last_nozzle_id; } - int total_cost = reorder_filaments_for_minimum_flush_volume( - used_filaments, - filament_maps, - ctx.model_info.layer_filaments, - ctx.model_info.flush_matrix, - get_custom_seq, - nullptr - ); - - if (prefer_level > best_prefer_level || (prefer_level == best_prefer_level && total_cost < best_cost)) { - best_prefer_level = prefer_level; - best_cost = total_cost; - best_label = filament_maps; + std::deque used_nozzle_deq; + for (int m = 0; m < ctx.nozzle_info.extruder_nozzle_list.size(); m++) { + int cur_extruder = (m + start_extruder) % ctx.nozzle_info.extruder_nozzle_list.size(); + for (auto noz_id : ctx.nozzle_info.extruder_nozzle_list.at(cur_extruder)) { + if (nozzle_fil_deq[noz_id].empty()) continue; + if (noz_id == start_nozzle) + used_nozzle_deq.push_front(noz_id); + else + used_nozzle_deq.push_back(noz_id); + } } - { - MemoryedGroup mg(filament_maps, total_cost, prefer_level); - update_memoryed_groups(mg, ctx.group_info.max_gap_threshold, memoryed_groups); + std::vector layer_fil_order; + for (auto noz_id : used_nozzle_deq) { + auto deq = nozzle_fil_deq[noz_id]; + layer_fil_order.reserve(layer_fil_order.size() + deq.size()); + layer_fil_order.insert(layer_fil_order.end(), deq.begin(), deq.end()); + + prev_layer_last_nozzle_id = noz_id; } + + FilamentPlanRes layer_pan{layer_fil_order, layer_fil_nozzle_match}; + res.emplace_back(layer_pan); } - if (cost) - *cost = best_cost; - - std::vector filament_labels(ctx.group_info.total_filament_num, 0); - for (size_t i = 0; i < best_label.size(); ++i) - filament_labels[used_filaments[i]] = best_label[i]; - - - change_memoryed_heaps_to_arrays(memoryed_groups, ctx.group_info.total_filament_num, used_filaments, m_memoryed_groups); - - return filament_labels; + return res; } - // sorted used_filaments - std::vector FilamentGroup::calc_min_flush_group_by_pam2(const std::vector& used_filaments, int* cost, int timeout_ms) + std::vector calc_filament_group_for_manual_multi_nozzle(const std::vector& filament_map_manual, const FilamentGroupContext& ctx) { - std::vectorfilament_labels_ret(ctx.group_info.total_filament_num, ctx.machine_info.master_extruder_id); + FilamentGroupContext new_ctx = ctx; + auto used_filaments = collect_sorted_used_filaments(ctx.model_info.layer_filaments); + for(size_t idx = 0; idx < used_filaments.size(); ++idx) + new_ctx.model_info.unprintable_filaments[1 - filament_map_manual[used_filaments[idx]]].insert(used_filaments[idx]); - std::mapunplaceable_limits; - extract_unprintable_limit_indices(ctx.model_info.unprintable_filaments, used_filaments, unplaceable_limits); - - auto distance_evaluator = std::make_shared(ctx.model_info.flush_matrix[0], used_filaments, ctx.model_info.layer_filaments); - KMediods2 PAM((int)used_filaments.size(), distance_evaluator, ctx.machine_info.master_extruder_id); - PAM.set_max_cluster_size(ctx.machine_info.max_group_size); - PAM.set_unplaceable_limits(unplaceable_limits); - PAM.set_memory_threshold(ctx.group_info.max_gap_threshold); - PAM.do_clustering(ctx.group_info.strategy, timeout_ms); - - std::vectorfilament_labels = PAM.get_cluster_labels(); - - { - auto memoryed_groups = PAM.get_memoryed_groups(); - change_memoryed_heaps_to_arrays(memoryed_groups, ctx.group_info.total_filament_num, used_filaments, m_memoryed_groups); - } - - if (cost) - *cost = reorder_filaments_for_minimum_flush_volume(used_filaments, filament_labels, ctx.model_info.layer_filaments, ctx.model_info.flush_matrix, std::nullopt, nullptr); - - for (int i = 0; i < filament_labels.size(); ++i) - filament_labels_ret[used_filaments[i]] = filament_labels[i]; - return filament_labels_ret; + new_ctx.machine_info.max_group_size.assign(new_ctx.machine_info.max_group_size.size(), std::numeric_limits::max()); + FilamentGroup fg(new_ctx); + return fg.calc_filament_group_for_flush(); } + } diff --git a/src/libslic3r/FilamentGroup.hpp b/src/libslic3r/FilamentGroup.hpp index ce1aedfbb4..828b673b38 100644 --- a/src/libslic3r/FilamentGroup.hpp +++ b/src/libslic3r/FilamentGroup.hpp @@ -13,7 +13,8 @@ const static int DEFAULT_CLUSTER_SIZE = 16; -const static int ABSOLUTE_FLUSH_GAP_TOLERANCE = 5; +const static int ABSOLUTE_FLUSH_GAP_TOLERANCE = 10; + namespace Slic3r { @@ -52,12 +53,12 @@ namespace Slic3r struct MemoryedGroup { MemoryedGroup() = default; - MemoryedGroup(const std::vector& group_, const int cost_, const int prefer_level_) :group(group_), cost(cost_), prefer_level(prefer_level_) {} + MemoryedGroup(const std::vector& group_, const double cost_, const int prefer_level_) :group(group_), cost(cost_), prefer_level(prefer_level_) {} bool operator>(const MemoryedGroup& other) const { return prefer_level < other.prefer_level || (prefer_level == other.prefer_level && cost > other.cost); } - int cost{ 0 }; + double cost{ 0 }; int prefer_level{ 0 }; std::vectorgroup; }; @@ -75,6 +76,7 @@ namespace Slic3r std::vector filament_info; std::vector filament_ids; std::vector> unprintable_filaments; + std::map> unprintable_volumes; } model_info; struct GroupInfo { @@ -82,40 +84,64 @@ namespace Slic3r double max_gap_threshold; FGMode mode; FGStrategy strategy; - bool ignore_ext_filament; //wai gua filament + bool ignore_ext_filament; + bool has_filament_switcher = false; + std::vector filament_volume_map; } group_info; struct MachineInfo { std::vector max_group_size; std::vector> machine_filament_info; - std::vector, int>> extruder_group_size; + std::vector prefer_non_model_filament; int master_extruder_id; } machine_info; + + struct SpeedInfo{ + std::unordered_map> filament_print_time; + double extruder_change_time; + double filament_change_time; + bool group_with_time; + MultiNozzleUtils::FilamentChangeTimeParams change_time_params; + std::vector ams_preload_enabled; + } speed_info; + + struct NozzleInfo { + std::map> extruder_nozzle_list; + std::vector nozzle_list; + std::unordered_map nozzle_status; + } nozzle_info; }; - std::vector select_best_group_for_ams(const std::vector>& map_lists, + std::vector select_best_group_for_ams(const std::vector> &filament_to_nozzles, + const std::vector& nozzle_list, const std::vector& used_filaments, const std::vector& used_filament_info, const std::vector>& machine_filament_info, + const bool has_filament_switcher = false, const double color_delta_threshold = 20); - std::vector optimize_group_for_master_extruder(const std::vector& used_filaments, const FilamentGroupContext& ctx, const std::vector& filament_map); - - bool can_swap_groups(const int extruder_id_0, const std::set& group_0, const int extruder_id_1, const std::set& group_1, const FilamentGroupContext& ctx); - - std::vector calc_filament_group_for_tpu(const std::set& tpu_filaments, const int filament_nums, const int master_extruder_id); class FlushDistanceEvaluator { public: - FlushDistanceEvaluator(const FlushMatrix& flush_matrix,const std::vector&used_filaments,const std::vector>& layer_filaments, double p = 0.65); + FlushDistanceEvaluator(const std::vector& flush_matrix,const std::vector&used_filaments,const std::vector>& layer_filaments, double p = 0.65); ~FlushDistanceEvaluator() = default; - double get_distance(int idx_a, int idx_b) const; + double get_distance(int idx_a, int idx_b, int extruder_id) const; private: - std::vector>m_distance_matrix; + std::vector>>m_distance_matrix; }; + + class TimeEvaluator + { + public: + TimeEvaluator(const FilamentGroupContext::SpeedInfo& speed_info) : m_speed_info(speed_info) {} + double get_estimated_time(const std::vector& filament_map) const; + private: + FilamentGroupContext::SpeedInfo m_speed_info; + }; + class FilamentGroup { using MemoryedGroup = FilamentGroupUtils::MemoryedGroup; @@ -129,11 +155,17 @@ namespace Slic3r public: std::vector calc_filament_group_for_match(int* cost = nullptr); std::vector calc_filament_group_for_flush(int* cost = nullptr); - + std::vector calc_filament_group_for_tpu(int* cost = nullptr); private: std::vector calc_min_flush_group(int* cost = nullptr); - std::vector calc_min_flush_group_by_enum(const std::vector& used_filaments, int* cost = nullptr); - std::vector calc_min_flush_group_by_pam2(const std::vector& used_filaments, int* cost = nullptr, int timeout_ms = 300); + + std::vector calc_group_by_enum(int k, const std::vector& used_filaments, + const std::unordered_map>& unplaceable_limits, int* cost = nullptr); + std::vector calc_group_by_kmedoids(int k, const std::vector& used_filaments, + const std::unordered_map>& unplaceable_limits, int* cost = nullptr, int timeout_ms = 500); + + std::map rebuild_unprintables(const std::vector& used_filaments, const std::map& extruder_unprintables); + std::unordered_map> rebuild_nozzle_unprintables(const std::vector& used_filaments, const std::unordered_map>& extruder_unprintables, const std::vector& filament_volume_map); std::unordered_map> try_merge_filaments(); void rebuild_context(const std::unordered_map>& merged_filaments); @@ -141,57 +173,78 @@ namespace Slic3r private: FilamentGroupContext ctx; + MemoryedGroupHeap m_memoryed_heap; std::vector> m_memoryed_groups; - public: std::optional&)>> get_custom_seq; }; - class KMediods2 + std::vector calc_filament_group_for_manual_multi_nozzle(const std::vector& filament_map_manual,const FilamentGroupContext& ctx); + + std::vector calc_filament_group_for_match_multi_nozzle(const FilamentGroupContext& ctx); + + struct FilamentPlanRes { + std::vector fil_order; + std::vector fil_nozzle_match; + }; + + std::vector plan_filament_nozzle_mapping_and_order(const FilamentGroupContext& ctx); + + + class KMediods + { + protected: using MemoryedGroupHeap = FilamentGroupUtils::MemoryedGroupHeap; using MemoryedGroup = FilamentGroupUtils::MemoryedGroup; - - enum INIT_TYPE - { - Random = 0, - Farthest - }; public: - KMediods2(const int elem_count, const std::shared_ptr& evaluator, int default_group_id = 0) : - m_evaluator{ evaluator }, - m_elem_count{ elem_count }, - m_default_group_id{ default_group_id } - { - m_max_cluster_size = std::vector(m_k, DEFAULT_CLUSTER_SIZE); + KMediods(const int k, const int elem_count, const std::shared_ptr& evaluator, int default_group_id = 0) { + m_k = k; + m_evaluator = evaluator; + m_max_cluster_size = std::vector(k, DEFAULT_CLUSTER_SIZE); + m_elem_count = elem_count; + m_default_group_id = default_group_id; } - // set max group size void set_max_cluster_size(const std::vector& group_size) { m_max_cluster_size = group_size; } - // key stores elem idx, value stores the cluster id that elem cnanot be placed - void set_unplaceable_limits(const std::map& placeable_limits) { m_unplaceable_limits = placeable_limits; } + void set_cluster_group_size(const std::vector,int>>& cluster_group_size); - void do_clustering(const FGStrategy& g_strategy,int timeout_ms = 100); + // key stores elem, value stores the cluster id that the elem must be placed + void set_placable_limits(const std::unordered_map>& placable_limits) { m_placeable_limits = placable_limits; } + + // key stores elem, value stores the cluster id that the elem cannot be placed + void set_unplacable_limits(const std::unordered_map>& unplacable_limits) { m_unplaceable_limits = unplacable_limits; } void set_memory_threshold(double threshold) { memory_threshold = threshold; } MemoryedGroupHeap get_memoryed_groups()const { return memoryed_groups; } - std::vectorget_cluster_labels()const { return m_cluster_labels; } + void do_clustering(const FilamentGroupContext& context, int timeout_ms = 100, int retry = 10); + std::vector get_cluster_labels()const { return m_cluster_labels; } - private: - std::vectorcluster_small_data(const std::map& unplaceable_limits, const std::vector& group_size); - std::vectorassign_cluster_label(const std::vector& center, const std::map& unplaceable_limits, const std::vector& group_size, const FGStrategy& strategy); - int calc_cost(const std::vector& labels, const std::vector& medoids); protected: - FilamentGroupUtils::MemoryedGroupHeap memoryed_groups; - std::shared_ptr m_evaluator; - std::mapm_unplaceable_limits; - std::vectorm_cluster_labels; - std::vectorm_max_cluster_size; + bool have_enough_size(const std::vector& cluster_size, const std::vector, int>>& cluster_group_size,int elem_count); + // calculate cluster distance + int calc_cost(const std::vector& clusters, const std::vector& cluster_centers, int cluster_id = -1); - const int m_k = 2; + // get initial cluster center + std::vectorinit_cluster_center(const std::unordered_map>& placeable_limits, const std::unordered_map>& unplaceable_limits, const std::vector& cluster_size, const std::vector, int>>& cluster_group_size, int seed); + // assign each elem to the cluster + std::vector assign_cluster_label(const std::vector& center, const std::unordered_map>& placeable_limits, const std::unordered_map>& unplaceable_limits, const std::vector& group_size, const std::vector, int>>& cluster_group_size); + + protected: + MemoryedGroupHeap memoryed_groups; + std::shared_ptrm_evaluator; + std::unordered_map> m_unplaceable_limits; // key: filament, value: nozzle ids it cannot be assigned to + std::unordered_map> m_placeable_limits; // key: filament, value: nozzle ids it must be assigned to + std::vectorm_max_cluster_size; // max number of filaments each nozzle can hold + std::vectorm_cluster_labels; // assignment result, resolved down to nozzle id + std::vector,int>> m_cluster_group_size; + std::vector m_nozzle_to_extruder; + + + int m_k; int m_elem_count; int m_default_group_id{ 0 }; double memory_threshold{ 0 }; diff --git a/src/libslic3r/FilamentGroupUtils.cpp b/src/libslic3r/FilamentGroupUtils.cpp index 1b16a1337f..13c9603e0a 100644 --- a/src/libslic3r/FilamentGroupUtils.cpp +++ b/src/libslic3r/FilamentGroupUtils.cpp @@ -274,5 +274,66 @@ namespace FilamentGroupUtils } return true; } + + int get_estimate_extruder_change_count(const std::vector> &layer_filaments, const MultiNozzleUtils::LayeredNozzleGroupResult &extruder_nozzle_info) + { + int ret = 0; + for (size_t layer_id = 0; layer_id < layer_filaments.size(); ++layer_id) { + int extruder_count = extruder_nozzle_info.get_used_extruders(layer_id).size(); + ret += (extruder_count - 1); + } + return ret; + } + + int get_estimate_nozzle_change_count(const std::vector> &layer_filaments, const MultiNozzleUtils::LayeredNozzleGroupResult &extruder_nozzle_info) + { + int ret = 0; + for (size_t layer_id = 0; layer_id < layer_filaments.size(); ++layer_id) { + auto extruder_list = extruder_nozzle_info.get_used_extruders(layer_id); + for (auto extruder_id : extruder_list) { + int nozzle_count = extruder_nozzle_info.get_used_nozzles_in_extruder(extruder_id, layer_id).size(); + if (nozzle_count > 1) ret += (nozzle_count - 1); + } + } + return ret; + } + + std::pair get_estimate_extruder_filament_change_count(const MultiNozzleUtils::LayeredNozzleGroupResult &extruder_nozzle_info) + { + std::pair ret{0,0}; + int layer_nums = extruder_nozzle_info.get_layer_filament_sequences().size(); + for (int layer_id = 0; layer_id < layer_nums; layer_id++) { + std::vector extruders = extruder_nozzle_info.get_used_extruders(layer_id); + ret.first = extruders.size() - 1; + + for (auto ext_id : extruders) { + int nozzles = extruder_nozzle_info.get_used_nozzles_in_extruder(ext_id, layer_id).size(); + ret.second += nozzles; + } + ret.second = std::max(0, ret.second - ret.first); + } + return ret; + } + + std::map> build_extruder_nozzle_list(const std::vector& nozzle_list) + { + std::map> ret; + for (auto& nozzle : nozzle_list) { + ret[nozzle.extruder_id].emplace_back(nozzle.group_id); + } + + for (auto& elem : ret) + std::sort(elem.second.begin(), elem.second.end()); + return ret; + } + + std::vector update_used_filament_values(const std::vector& old_values, const std::vector& new_values, const std::vector& used_filaments) + { + std::vector res = old_values; + for (size_t i = 0; i < used_filaments.size(); ++i) { + res[used_filaments[i]] = new_values[used_filaments[i]]; + } + return res; + } } } \ No newline at end of file diff --git a/src/libslic3r/FilamentGroupUtils.hpp b/src/libslic3r/FilamentGroupUtils.hpp index 71839c2be6..f0865a93c6 100644 --- a/src/libslic3r/FilamentGroupUtils.hpp +++ b/src/libslic3r/FilamentGroupUtils.hpp @@ -7,6 +7,7 @@ #include #include "PrintConfig.hpp" +#include "MultiNozzleUtils.hpp" namespace Slic3r { @@ -31,6 +32,10 @@ namespace Slic3r Color color; std::string type; bool is_support; + // How this filament is used across the model. Orca's shipping grouping + // algorithm does not read it yet; defaulted so a default-built FilamentInfo + // is deterministic. The nozzle-centric engine consumes it later. + FilamentUsageType usage_type = FilamentUsageType::ModelOnly; }; struct MachineFilamentInfo: public FilamentInfo { @@ -80,6 +85,20 @@ namespace Slic3r void extract_unprintable_limit_indices(const std::vector>& unprintable_elems, const std::vector& used_filaments, std::unordered_map>& unplaceable_limits); bool check_printable(const std::vector>& groups, const std::map& unprintable); + + // Nozzle-centric grouping helpers. The estimate helpers read a LayeredNozzleGroupResult's + // per-layer extruder/nozzle usage; the two builders support building the grouping context + // (extruder->nozzle inventory) and writing back a resolved map onto only the used-filament + // slots. + int get_estimate_extruder_change_count(const std::vector>& layer_filaments, const MultiNozzleUtils::LayeredNozzleGroupResult& extruder_nozzle_info); + + int get_estimate_nozzle_change_count(const std::vector>& layer_filaments, const MultiNozzleUtils::LayeredNozzleGroupResult& extruder_nozzle_info); + + std::pair get_estimate_extruder_filament_change_count(const MultiNozzleUtils::LayeredNozzleGroupResult& extruder_nozzle_info); + + std::map> build_extruder_nozzle_list(const std::vector& nozzle_list); + + std::vector update_used_filament_values(const std::vector& old_values, const std::vector& new_values, const std::vector& used_filaments); } diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index fd395135ae..e7fda3ac4a 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -347,6 +347,7 @@ static constexpr const char* OTHER_LAYERS_PRINT_SEQUENCE_NUMS_ATTR = "other_laye static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode"; static constexpr const char* FILAMENT_MAP_MODE_ATTR = "filament_map_mode"; static constexpr const char* FILAMENT_MAP_ATTR = "filament_maps"; +static constexpr const char* FILAMENT_VOL_MAP_ATTR = "filament_volume_maps"; static constexpr const char* LIMIT_FILAMENT_MAP_ATTR = "limit_filament_maps"; static constexpr const char* GCODE_FILE_ATTR = "gcode_file"; static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file"; @@ -699,6 +700,43 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) info.id = it->first; info.used_g = used_filament_g; info.used_m = used_filament_m; + + // Stamp each filament's logical-nozzle assignment onto the saved 3mf so the + // device/monitor can reconstruct it. NOTE: this block runs for the whole fleet, not just + // multi-nozzle prints: reorder_extruders_for_minimum_flush_volume runs unconditionally and + // set_nozzle_group_result stores a (non-null) 1-nozzle result even for a single-extruder print, + // so result->nozzle_group_result is non-null here for X1/P1/A1/H2S too. Saved-3mf byte-identity + // vs the older filament_maps path therefore holds by VALUE-COINCIDENCE, not by skipping: for a + // standard 0.4/0.2/0.6/0.8 nozzle the stamped group_id/nozzle_diameter/volume_type render the same + // bytes as the filament_maps-derived fallback below (empirically confirmed on an X1C 0.4 saved 3mf: + // slice_info.config emits group_id="0" nozzle_diameter="0.40" volume_type="Standard" and + // == the else-path). + // The one divergence is a non-standard nozzle (e.g. 0.3/0.5): format_diameter_to_str snaps the + // stamped diameter to the nearest of {0.2,0.4,0.6,0.8} (0.5 -> "0.4"), whereas the older path wrote + // the raw config value — a metadata-only carry. No g-code effect; the raw nozzle_diameters plate + // metadata is unchanged. + if (result && result->nozzle_group_result) { + auto nozzles_for_filament = result->nozzle_group_result->get_nozzles_for_filament(it->first); + if (!nozzles_for_filament.empty()) { + info.group_id.reserve(nozzles_for_filament.size()); + std::set diameters; + std::set volume_types; + for (const auto& nozzle : nozzles_for_filament) { + info.group_id.emplace_back(nozzle.group_id); + diameters.insert(string_to_double_decimal_point(nozzle.diameter)); + volume_types.insert(nozzle.volume_type); + } + std::sort(info.group_id.begin(), info.group_id.end()); + info.group_id.erase(std::unique(info.group_id.begin(), info.group_id.end()), info.group_id.end()); + if (!diameters.empty()) + info.nozzle_diameter = *diameters.begin(); + if (volume_types.size() > 1) + info.nozzle_volume_type = get_nozzle_volume_type_string(nvtHybrid); + else if (!volume_types.empty()) + info.nozzle_volume_type = get_nozzle_volume_type_string(*volume_types.begin()); + } + } + auto model_volume_it = ps.model_volumes_per_extruder.find(it->first); auto support_volume_it = ps.support_volumes_per_extruder.find(it->first); info.used_for_object = model_volume_it != ps.model_volumes_per_extruder.end() && model_volume_it->second > EPSILON; @@ -706,6 +744,13 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) slice_filaments_info.push_back(info); } + // Carry the layer-aware grouping result into the plate so the 3mf writer can emit the tags + // and the enable_filament_dynamic_map flag. Only a LayeredNozzleGroupResult (the slicer output) is + // stored; a device-side StaticNozzleGroupResult loaded from a 3mf is not re-serialized here. + auto layered_group_result = std::dynamic_pointer_cast(result->nozzle_group_result); + if (layered_group_result) + nozzle_group_result = *layered_group_result; + /* only for test GCodeProcessorResult::SliceWarning sw; sw.msg = BED_TEMP_TOO_HIGH_THAN_FILAMENT; @@ -1283,6 +1328,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) bool _handle_start_config_warning(const char** attributes, unsigned int num_attributes); bool _handle_end_config_warning(); + bool _handle_start_config_nozzle(const char** attributes, unsigned int num_attributes); + bool _handle_end_config_nozzle(); + //BBS: add plater config parse functions bool _handle_start_config_plater(const char** attributes, unsigned int num_attributes); bool _handle_end_config_plater(); @@ -1618,8 +1666,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) plate->is_label_object_enabled = it->second->is_label_object_enabled; plate->skipped_objects = it->second->skipped_objects; plate->slice_filaments_info = it->second->slice_filaments_info; + plate->nozzles_info = it->second->nozzles_info; plate->printer_model_id = it->second->printer_model_id; plate->nozzle_diameters = it->second->nozzle_diameters; + plate->nozzle_volume_types = it->second->nozzle_volume_types; plate->filament_maps = it->second->filament_maps; plate->filament_change_sequence = it->second->filament_change_sequence; plate->nozzle_change_sequence = it->second->nozzle_change_sequence; @@ -2289,9 +2339,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) plate_data_list[it->first-1]->is_support_used = it->second->is_support_used; plate_data_list[it->first-1]->is_label_object_enabled = it->second->is_label_object_enabled; plate_data_list[it->first-1]->slice_filaments_info = it->second->slice_filaments_info; + plate_data_list[it->first-1]->nozzles_info = it->second->nozzles_info; plate_data_list[it->first-1]->skipped_objects = it->second->skipped_objects; plate_data_list[it->first-1]->printer_model_id = it->second->printer_model_id; plate_data_list[it->first-1]->nozzle_diameters = it->second->nozzle_diameters; + plate_data_list[it->first-1]->nozzle_volume_types = it->second->nozzle_volume_types; plate_data_list[it->first-1]->filament_maps = it->second->filament_maps; plate_data_list[it->first-1]->filament_change_sequence = it->second->filament_change_sequence; plate_data_list[it->first-1]->nozzle_change_sequence = it->second->nozzle_change_sequence; @@ -3469,6 +3521,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) res = _handle_start_config_filament(attributes, num_attributes); else if (::strcmp(SLICE_WARNING_TAG, name) == 0) res = _handle_start_config_warning(attributes, num_attributes); + else if (::strcmp(NOZZLE_TAG, name) == 0) + res = _handle_start_config_nozzle(attributes, num_attributes); else if (::strcmp(ASSEMBLE_TAG, name) == 0) res = _handle_start_assemble(attributes, num_attributes); else if (::strcmp(ASSEMBLE_ITEM_TAG, name) == 0) @@ -3503,6 +3557,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) res = _handle_end_config_plater(); else if (::strcmp(FILAMENT_TAG, name) == 0) res = _handle_end_config_filament(); + else if (::strcmp(NOZZLE_TAG, name) == 0) + res = _handle_end_config_nozzle(); else if (::strcmp(INSTANCE_TAG, name) == 0) res = _handle_end_config_plater_instance(); else if (::strcmp(ASSEMBLE_TAG, name) == 0) @@ -4460,6 +4516,19 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_curr_plater->config.set_key_value("filament_map", new ConfigOptionInts(filament_map)); } } + else if (key == FILAMENT_VOL_MAP_ATTR) { + if (m_curr_plater){ + auto filament_volume_map = get_vector_from_string(value); + for (size_t idx = 0; idx < filament_volume_map.size(); ++idx) { + // Only Standard(0)/High Flow(1) are currently supported; clamp any higher + // volume-type (TPU High Flow/Hybrid) back to Standard until they are wired in. + if (filament_volume_map[idx] > 1) { + filament_volume_map[idx] = 0; + } + } + m_curr_plater->config.set_key_value("filament_volume_map", new ConfigOptionInts(filament_volume_map)); + } + } else if (key == GCODE_FILE_ATTR) { m_curr_plater->gcode_file = value; @@ -4569,6 +4638,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) if (m_curr_plater) m_curr_plater->printer_model_id = value; } + else if (key == NOZZLE_VOLUME_TYPE_ATTR) + { + if (m_curr_plater) + m_curr_plater->nozzle_volume_types = value; + } else if (key == NOZZLE_DIAMETERS_ATTR) { if (m_curr_plater) @@ -4622,6 +4696,41 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return true; } + bool _BBS_3MF_Importer::_handle_start_config_nozzle(const char** attributes, unsigned int num_attributes) + { + // Read the per-plate tags. Older 3mf without tags leave nozzles_info + // empty; load_nozzle_infos_with_compatibility then rebuilds the list from the per-filament + // group_id / filament_map on the device side. + if (m_curr_plater) { + // id="0" extruder_id="1" nozzle_diameter="0.4" volume_type="Standard" + std::string id = bbs_get_attribute_value_string(attributes, num_attributes, "id"); + std::string extruder_id = bbs_get_attribute_value_string(attributes, num_attributes, "extruder_id"); + std::string nozzle_diameter= bbs_get_attribute_value_string(attributes, num_attributes, "nozzle_diameter"); + std::string volume_type = bbs_get_attribute_value_string(attributes, num_attributes, "volume_type"); + + auto volume_type_str_to_enum = ConfigOptionEnum::get_enum_values(); + + MultiNozzleUtils::NozzleInfo nozzle_info; + nozzle_info.group_id = atoi(id.c_str()); + nozzle_info.extruder_id = atoi(extruder_id.c_str()) - 1; + nozzle_info.diameter = nozzle_diameter; + + if (volume_type_str_to_enum.count(volume_type)) + nozzle_info.volume_type = NozzleVolumeType(volume_type_str_to_enum.at(volume_type)); + else + nozzle_info.volume_type = NozzleVolumeType::nvtStandard; + + m_curr_plater->nozzles_info.push_back(nozzle_info); + } + return true; + } + + bool _BBS_3MF_Importer::_handle_end_config_nozzle() + { + // do nothing + return true; + } + bool _BBS_3MF_Importer::_handle_start_config_warning(const char** attributes, unsigned int num_attributes) { if (m_curr_plater) { @@ -7980,6 +8089,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << "\"/>\n"; } + ConfigOptionInts* filament_volume_maps_opt = plate_data->config.option("filament_volume_map"); + if (filament_map_mode_opt != nullptr && filament_volume_maps_opt != nullptr) { + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << FILAMENT_VOL_MAP_ATTR << "\" " << VALUE_ATTR << "=\""; + const std::vector& volume_values = filament_volume_maps_opt->values; + for (int i = 0; i < volume_values.size(); ++i) { + stream << volume_values[i]; + if (i != (volume_values.size() - 1)) + stream << " "; + } + stream << "\"/>\n"; + } + if (save_gcode) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << GCODE_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << xml_escape(plate_data->gcode_file) << "\"/>\n"; if (!plate_data->gcode_file.empty()) { @@ -8119,7 +8240,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) [](unsigned int filament_id) { return filament_id + 1; }); const std::string plate_key = "plate_" + std::to_string(idx + 1); - sequence_json[plate_key]["sequence"] = filament_sequence; + // Dynamic-map plates write the sequence under "filament_sequence"; every other plate (the + // whole shipping fleet + H2C static mode) keeps the "sequence" key, so the saved 3mf is + // byte-identical to the older format. The reader accepts both. + const bool enable_dynamic_map = plate_data->nozzle_group_result && plate_data->nozzle_group_result->is_support_dynamic_nozzle_map(); + const std::string seq_key = enable_dynamic_map ? "filament_sequence" : "sequence"; + sequence_json[plate_key][seq_key] = filament_sequence; sequence_json[plate_key]["nozzle_sequence"] = plate_data->nozzle_change_sequence; sequence_json[plate_key]["optimal_assignment"] = plate_data->optimal_assignment; } @@ -8214,7 +8340,15 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SUPPORT_USED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_support_used << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << LABEL_OBJECT_ENABLED_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->is_label_object_enabled << "\"/>\n"; - stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ENABLE_FILAMENT_DYNAMIC_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << false << "\"/>\n"; + // Report the plate's dynamic-map state from the grouping result. The result is present + // for the whole fleet (a static single-nozzle result too), so this if-branch is normally + // taken; is_support_dynamic_nozzle_map() is false for any non-dynamic (static / + // single-extruder) result ⇒ byte-identical to the previously hard-coded value. The else + // is a defensive fallback for a missing result. + if (plate_data && plate_data->nozzle_group_result) + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ENABLE_FILAMENT_DYNAMIC_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << plate_data->nozzle_group_result->is_support_dynamic_nozzle_map() << "\"/>\n"; + else + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ENABLE_FILAMENT_DYNAMIC_MAP_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << false << "\"/>\n"; { bool has_filament_switcher = config.has("has_filament_switcher") ? config.opt_bool("has_filament_switcher") : false; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << HAS_FILAMENT_SWITCHER_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << has_filament_switcher << "\"/>\n"; @@ -8349,12 +8483,27 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << SLICE_WARNING_TAG << " msg=\"" << it->msg << "\" level=\"" << std::to_string(it->level) << "\" error_code =\"" << it->error_code << "\" />\n"; } - for (int nozzle_group_id : used_nozzle_groups) { - stream << " <" << NOZZLE_TAG << " " - << "id=\"" << nozzle_group_id << "\" " - << "extruder_id=\"" << nozzle_group_id + 1 << "\" " - << "nozzle_diameter=\"" << get_nozzle_diameter_str(nozzle_group_id) << "\" " - << "volume_type=\"" << get_nozzle_volume_type(nozzle_group_id) << "\"/>\n"; + // Emit the tags from the grouping result when present. The result is present for + // the whole fleet (see the value-coincidence note in parse_filament_info), so this if-branch + // is normally taken; for single-nozzle-per-extruder prints get_used_nozzles_in_extruder() + // yields one nozzle per used extruder whose serialize() output is byte-identical to the + // filament_maps-derived else-path below for a standard nozzle diameter (a non-standard + // diameter snaps via format_diameter_to_str — the metadata-only carry). Only genuinely + // multi-nozzle prints emit per-nozzle tags the extruder map cannot express. The else + // is a defensive fallback for a missing result. + if (plate_data->nozzle_group_result) { + auto used_nozzle_list = plate_data->nozzle_group_result->get_used_nozzles_in_extruder(); + for (auto& used_nozzle : used_nozzle_list) { + stream << " <" << NOZZLE_TAG << " " << used_nozzle.serialize() << "/>\n"; + } + } else { + for (int nozzle_group_id : used_nozzle_groups) { + stream << " <" << NOZZLE_TAG << " " + << "id=\"" << nozzle_group_id << "\" " + << "extruder_id=\"" << nozzle_group_id + 1 << "\" " + << "nozzle_diameter=\"" << get_nozzle_diameter_str(nozzle_group_id) << "\" " + << "volume_type=\"" << get_nozzle_volume_type(nozzle_group_id) << "\"/>\n"; + } } if (!plate_data->layer_filaments.empty()) { diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index c16c423f66..9c697a14fc 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -73,6 +73,7 @@ struct PlateData std::map> obj_inst_map; std::string printer_model_id; std::string nozzle_diameters; + std::string nozzle_volume_types; std::string gcode_file; std::string gcode_file_md5; std::string thumbnail_file; @@ -102,6 +103,13 @@ struct PlateData std::vector nozzle_change_sequence; std::vector optimal_assignment; + // Multi-nozzle grouping surface. nozzles_info accumulates the tags read from a + // gcode.3mf; nozzle_group_result is the slicer's per-filament→nozzle assignment carried into the + // saved 3mf metadata (write) and reconstructed on load. Both are empty/nullopt for single-nozzle + // prints, so the saved-3mf output for single-nozzle printers is byte-identical. + std::vector nozzles_info; + std::optional nozzle_group_result; + // Hexadecimal number, // the 0th digit corresponds to extruder 1 // the 1th digit corresponds to extruder 2 diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0b62fd0d6f..8ad1126096 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -99,11 +99,131 @@ static bool is_bambu_x2d_printer(const FullPrintConfig &config) return config.printer_model.value == "Bambu Lab X2D"; } +// Multi-nozzle printer predicate: an extruder carries a nozzle cluster (extruder_max_nozzle_count +// entry > 1). Today only H2C profiles trip it, so every existing single- and dual-extruder printer +// is excluded and keeps its historic placeholder values. +static bool is_multi_nozzle_printer(const FullPrintConfig &config) +{ + return std::any_of(config.extruder_max_nozzle_count.values.begin(), + config.extruder_max_nozzle_count.values.end(), + [](int v) { return v > 1; }); +} + static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config, int hotend_id) { return is_bambu_x2d_printer(config) ? -1 : hotend_id; } +// current_hotend / next_hotend value. For multi-nozzle printers a dynamic nozzle map yields the real +// nozzle id, a static map yields -1: +// - multi-nozzle (H2C): dynamic nozzle map -> real nozzle id; static -> -1. +// The dynamic branch is dormant today: the selector create() overload that sets the flag has no +// callers yet (deferred with the nozzle-assignment pipeline), so H2C currently resolves to -1. +// - X2D: keeps its historic -1 (single-nozzle -> falls through to the fallback helper). +// - every other (existing single-nozzle) printer: keeps its historic extruder-id value, so +// existing g-code stays byte-identical. +// group_result may be null on slicing paths that don't populate it -> the dynamic branch is simply +// skipped, so we never dereference null. +static int hotend_id_for_gcode_placeholder(const FullPrintConfig &config, + const std::shared_ptr &group_result, + int filament_id, + int extruder_id, + int layer_id = -1) +{ + if (is_multi_nozzle_printer(config)) { + if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0) + return group_result->get_nozzle_id(filament_id, layer_id); + return -1; + } + return hotend_id_for_gcode_placeholder(config, extruder_id); +} + +// Logical nozzle id for the *_nozzle_id placeholders. Null-safe: falls back to the +// extruder id (single-nozzle equivalent) so existing printers are unaffected and we never crash. +static int nozzle_id_for_gcode_placeholder(const std::shared_ptr &group_result, + int filament_id, int extruder_id, int layer_id = -1) +{ + if (group_result && filament_id >= 0) + return group_result->get_nozzle_id(filament_id, layer_id); + return extruder_id; +} + +// Init variants: the start-gcode init sites (first_non_support_hotend / initial_no_support_hotend / +// current_hotend / initial_nozzle_id / filament_start current_nozzle_id) use get_first_nozzle_for_filament +// (the nozzle a filament FIRST uses) rather than the layer-based get_nozzle_id. Same hotend-value semantics +// as hotend_id_for_gcode_placeholder above (multi-nozzle static -> -1; dynamic branch dormant; +// existing printers -> extruder id; X2D -> -1); they differ from the layer-based helper only on the dormant +// dynamic path for a filament first used after layer 0. +static int first_hotend_id_for_gcode_placeholder(const FullPrintConfig &config, + const std::shared_ptr &group_result, + int filament_id, + int extruder_id) +{ + if (is_multi_nozzle_printer(config)) { + if (group_result && group_result->is_support_dynamic_nozzle_map() && filament_id >= 0) { + auto nozzle = group_result->get_first_nozzle_for_filament(filament_id); + if (nozzle) + return nozzle->group_id; + } + return -1; + } + return hotend_id_for_gcode_placeholder(config, extruder_id); +} + +static int first_nozzle_id_for_gcode_placeholder(const std::shared_ptr &group_result, + int filament_id, int extruder_id) +{ + if (group_result && filament_id >= 0) { + auto nozzle = group_result->get_first_nozzle_for_filament(filament_id); + if (nozzle) + return nozzle->group_id; + } + return extruder_id; +} + +// Nozzle diameters indexed by logical nozzle id, for the nozzle_diameter_at_nozzle_id[] +// placeholder. Empty when there is no group result. +static std::vector get_nozzle_diameters_by_nozzle_id(const MultiNozzleUtils::NozzleGroupResultBase *group_result) +{ + std::vector diameters; + if (!group_result) + return diameters; + for (int id = 0;; ++id) { + auto nozzle = group_result->get_nozzle_from_id(id); + if (!nozzle) + break; + diameters.push_back(std::stod(nozzle->diameter)); + } + return diameters; +} + +// Nozzle volume-type strings indexed by logical nozzle id, for the nozzle_volume_types[] +// placeholder. Empty when there is no group result. +static std::vector get_nozzle_volume_types_by_nozzle_id(const MultiNozzleUtils::NozzleGroupResultBase *group_result) +{ + std::vector volume_types; + if (!group_result) + return volume_types; + + int max_nozzle_id = -1; + for (unsigned int filament_id : group_result->get_used_filaments()) { + for (const auto &nozzle : group_result->get_nozzles_for_filament(filament_id)) { + if (nozzle.group_id > max_nozzle_id) + max_nozzle_id = nozzle.group_id; + } + } + if (max_nozzle_id < 0) + max_nozzle_id = 0; + + volume_types.resize(max_nozzle_id + 1, get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard)); + for (int id = 0; id <= max_nozzle_id; ++id) { + auto nozzle = group_result->get_nozzle_from_id(id); + if (nozzle) + volume_types[id] = get_nozzle_volume_type_string(nozzle->volume_type); + } + return volume_types; +} + Vec2d travel_point_1; Vec2d travel_point_2; Vec2d travel_point_3; @@ -716,6 +836,9 @@ static std::vector get_path_of_change_filament(const Print& print) int new_extruder_id = get_extruder_index(*m_print_config, new_filament_id); + // Logical nozzle grouping for this print (null on paths that don't populate it). + auto group_result = gcodegen.m_print->get_layered_nozzle_group_result(); + bool is_nozzle_change = !tcr.nozzle_change_result.gcode.empty() && (gcodegen.config().nozzle_diameter.size() > 1); std::string gcode; @@ -780,6 +903,10 @@ static std::vector get_path_of_change_filament(const Print& print) const std::string& filament_end_gcode = gcodegen.config().filament_end_gcode.get_at(old_filament_id); if (gcodegen.writer().filament() != nullptr && !filament_end_gcode.empty()) { DynamicConfig config; + config.set_key_value("current_filament_id", new ConfigOptionInt((int) old_filament_id)); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(nozzle_id_for_gcode_placeholder(group_result, (int) old_filament_id, (int) gcodegen.writer().filament()->extruder_id(), m_layer_idx))); + config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z)); if (!gcodegen.m_filament_instances_code.empty()) { @@ -843,13 +970,24 @@ static std::vector get_path_of_change_filament(const Print& print) DynamicConfig config; int old_filament_id = gcodegen.writer().filament() ? (int)gcodegen.writer().filament()->id() : -1; int old_extruder_id = gcodegen.writer().filament() ? (int)gcodegen.writer().filament()->extruder_id() : -1; + // Logical nozzle ids for old/new filament (null-safe -> extruder id). + int old_nozzle_id = nozzle_id_for_gcode_placeholder(group_result, old_filament_id, old_extruder_id, m_layer_idx); + int next_nozzle_id = nozzle_id_for_gcode_placeholder(group_result, new_filament_id, new_extruder_id, m_layer_idx); config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id)); config.set_key_value("next_extruder", new ConfigOptionInt(new_filament_id)); - config.set_key_value("current_hotend", new ConfigOptionInt(old_extruder_id >= 0 ? - hotend_id_for_gcode_placeholder(gcodegen.m_config, old_extruder_id) : -1)); - config.set_key_value("next_hotend", - new ConfigOptionInt(hotend_id_for_gcode_placeholder(gcodegen.m_config, (int) gcodegen.get_extruder_id(new_filament_id)))); + // current_hotend/next_hotend (see hotend_id_for_gcode_placeholder): multi-nozzle H2C -> -1 + // (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id. + config.set_key_value("current_hotend", new ConfigOptionInt( + hotend_id_for_gcode_placeholder(gcodegen.m_config, group_result, old_filament_id, old_extruder_id, m_layer_idx))); + config.set_key_value("next_hotend", new ConfigOptionInt( + hotend_id_for_gcode_placeholder(gcodegen.m_config, group_result, new_filament_id, (int) gcodegen.get_extruder_id(new_filament_id), m_layer_idx))); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(old_nozzle_id)); + config.set_key_value("next_nozzle_id", new ConfigOptionInt(next_nozzle_id)); + config.set_key_value("current_filament_id", new ConfigOptionInt(old_filament_id)); + config.set_key_value("next_filament_id", new ConfigOptionInt(new_filament_id)); + config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); config.set_key_value("layer_num", new ConfigOptionInt(gcodegen.m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(tcr.print_z)); config.set_key_value("toolchange_z", new ConfigOptionFloat(z)); @@ -887,6 +1025,22 @@ static std::vector get_path_of_change_filament(const Print& print) wipe_avoid_pos_x = get_wipe_avoid_pos_x(box_min, box_max, 3.f); } + // Nozzle-heating center just outside the wipe tower. Clamp X to the + // region every extruder can reach (shared printable polygon), which equals the full + // printable_area for all current single/dual printers, so existing output is unchanged. + Vec2f stop_pos = tool_change_start_pos; + { + BoundingBoxf bbx = m_wipe_tower_bbx; + bbx.translate((m_wipe_tower_pos + m_rib_offset).cast()); + stop_pos.x() += (stop_pos.x() < bbx.center().x()) ? -2.f : 2.f; + auto printer_bbx = unscaled(get_extents(gcodegen.m_print->get_extruder_shared_printable_polygon())); + if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = float(printer_bbx.min[0]); + if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = float(printer_bbx.max[0]); + } + config.set_key_value("wipe_tower_center_pos_x", new ConfigOptionFloat(stop_pos.x())); + config.set_key_value("wipe_tower_center_pos_y", new ConfigOptionFloat(stop_pos.y())); + config.set_key_value("wipe_tower_center_pos_valid", new ConfigOptionBool(true)); + config.set_key_value("max_layer_z", new ConfigOptionFloat(gcodegen.m_max_layer_z)); config.set_key_value("relative_e_axis", new ConfigOptionBool(full_config.use_relative_e_distances)); config.set_key_value("toolchange_count", new ConfigOptionInt((int) gcodegen.m_toolchange_count)); @@ -895,8 +1049,14 @@ static std::vector get_path_of_change_filament(const Print& print) config.set_key_value("fan_speed", new ConfigOptionInt((int) 0)); config.set_key_value("old_retract_length", new ConfigOptionFloat(old_retract_length)); config.set_key_value("new_retract_length", new ConfigOptionFloat(new_retract_length)); + // Expose the old filament's nozzle-change retract length (filament_retract_length_nc; nil/-1 -> 0). + config.set_key_value("filament_retract_length_nc", new ConfigOptionFloat( + (old_filament_id != -1) ? (float) full_config.filament_retract_length_nc.get_at(old_filament_id) : 0.f)); config.set_key_value("old_retract_length_toolchange", new ConfigOptionFloat(old_retract_length_toolchange)); config.set_key_value("new_retract_length_toolchange", new ConfigOptionFloat(new_retract_length_toolchange)); + // Current parked-retract length of the incoming filament's extruder. + config.set_key_value("new_extruder_retracted_length", + new ConfigOptionFloat(gcode_writer.get_extruder_retracted_length((int) new_filament_id))); config.set_key_value("old_filament_temp", new ConfigOptionInt(old_filament_temp)); int interface_temp = full_config.filament_tower_interface_print_temp.get_at(new_filament_id); if (interface_temp == -1) @@ -930,7 +1090,8 @@ static std::vector get_path_of_change_filament(const Print& print) config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y()))); auto flush_v_speed = m_print_config->filament_flush_volumetric_speed.values; - auto flush_temps = m_print_config->filament_flush_temp.values; + // Fast purge mode uses filament_flush_temp_fast; Default is inert. + auto flush_temps = (m_print_config->prime_volume_mode == PrimeVolumeMode::pvmFast ? m_print_config->filament_flush_temp_fast : m_print_config->filament_flush_temp).values; auto filament_cooling_before_tower = m_print_config->filament_cooling_before_tower.values; for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) { if (flush_v_speed[idx] == 0) @@ -1015,10 +1176,20 @@ static std::vector get_path_of_change_filament(const Print& print) BoundingBox avoid_bbx, printer_bbx; { // set printer_bbx - Pointfs bed_pointsf = gcodegen.m_config.printable_area.values; - Points bed_points; - for (auto p : bed_pointsf) { bed_points.push_back(wipe_tower_point_to_object_point(gcodegen, p.cast() + plate_origin_2d)); } - printer_bbx = BoundingBox(bed_points); + // Multi-nozzle: clamp the avoid-perimeter travel bounds to the region every + // extruder can reach (get_extruder_shared_printable_polygon) instead of the full + // bed. Gated on the multi-nozzle predicate so H2D and every existing single/dual + // printer keep the historic full-printable_area routing byte-identical. + if (is_multi_nozzle_printer(gcodegen.m_config)) { + printer_bbx = get_extents(gcodegen.m_print->get_extruder_shared_printable_polygon()); + printer_bbx.min = wipe_tower_point_to_object_point(gcodegen, unscaled(printer_bbx.min) + plate_origin_2d); + printer_bbx.max = wipe_tower_point_to_object_point(gcodegen, unscaled(printer_bbx.max) + plate_origin_2d); + } else { + Pointfs bed_pointsf = gcodegen.m_config.printable_area.values; + Points bed_points; + for (auto p : bed_pointsf) { bed_points.push_back(wipe_tower_point_to_object_point(gcodegen, p.cast() + plate_origin_2d)); } + printer_bbx = BoundingBox(bed_points); + } } { // set avoid_bbx @@ -1049,7 +1220,21 @@ static std::vector get_path_of_change_filament(const Print& print) } // do unretract after setting current extruder_id - std::string toolchange_unretract_str = gcodegen.unretract(); + // PETG filaments on a device with a filament switcher get a small (2 mm) pre-extrusion + // before the tool change. has_filament_switcher is a develop-only key read defensively from the + // full config (Orca does not carry it as a static PrintConfig member — same convention as + // enable_filament_dynamic_map); no shipping profile sets it (grep resources/profiles = 0), so + // is_petg_pre_extrusion is always false -> extra_unretract stays 0 -> byte-identical to the plain + // unretract() fleet-wide. The tower-interface contact pre-extrusion length (the + // is_contact_pre_extrusion branch) is NOT applied here; it is only computed as the guard used to + // give the contact path priority over PETG. + const ConfigOptionBool* has_filament_switcher_opt = gcodegen.m_print->full_print_config().option("has_filament_switcher"); + bool is_contact_pre_extrusion = tcr.is_contact && gcodegen.m_config.enable_tower_interface_features; + bool is_petg_pre_extrusion = !is_contact_pre_extrusion + && gcodegen.config().filament_type.get_at(tcr.new_tool) == "PETG" + && has_filament_switcher_opt && has_filament_switcher_opt->value; + float extra_unretract = is_petg_pre_extrusion ? 2.f : 0.f; + std::string toolchange_unretract_str = (extra_unretract > 0.f) ? gcodegen.unretract(extra_unretract) : gcodegen.unretract(); check_add_eol(toolchange_unretract_str); gcodegen.placeholder_parser().set("current_extruder", new_filament_id); @@ -1065,6 +1250,10 @@ static std::vector get_path_of_change_filament(const Print& print) // Process the filament_start_gcode for the active filament only. DynamicConfig config; config.set_key_value("filament_extruder_id", new ConfigOptionInt(new_filament_id)); + config.set_key_value("current_filament_id", new ConfigOptionInt(new_filament_id)); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(nozzle_id_for_gcode_placeholder(group_result, new_filament_id, new_extruder_id, m_layer_idx))); + config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); start_filament_gcode_str = gcodegen.placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config); if (add_change_filament_624) { start_filament_gcode_str += "M625\n"; @@ -2172,9 +2361,31 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu extruder_unprintable_polys, m_print->get_extruder_printable_height(), m_print->get_filament_maps(), m_print->get_physical_unprintable_filaments(m_print->get_slice_used_filaments(false))); + // Hand the per-filament nozzle grouping to the processor BEFORE finalize, so the + // pre-heat injector's second pass can resolve filament->nozzle->extruder (get_nozzle_from_id / + // is_support_dynamic_nozzle_map). Print::_do_export re-assigns it onto the extracted result afterwards + // (Print.cpp) for the device GUI, but that is too late for the in-finalize injector. Null for + // single-nozzle prints, where the injector is gated off anyway (enable_pre_heating false). + m_processor.result().nozzle_group_result = m_print->get_layered_nozzle_group_result(); + m_processor.finalize(true); // DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics); DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics, print->config()); + // Printed-mass safety check. Flushed filament leaves the bed, so subtract it + // from the total to get the mass actually resting on the plate. Gated on machine_max_printed_mass + // (>0 only for A2L machines), so no existing printer's gcode_check_result changes. + if (m_print->config().machine_max_printed_mass.value > EPSILON) { + double mass_on_bed_total = print->m_print_statistics.total_weight; + for (auto volume : m_processor.get_result().print_statistics.flush_per_filament) { + size_t extruder_id = volume.first; + auto extruder = std::find_if(m_writer.extruders().begin(), m_writer.extruders().end(), [extruder_id](const Extruder &extr) { return extr.id() == extruder_id; }); + if (extruder == m_writer.extruders().end()) continue; + mass_on_bed_total -= (volume.second * extruder->filament_density() * 0.001); + } // flushed weight will not be keeped on the hot bed, exclude it + if (mass_on_bed_total > m_print->config().machine_max_printed_mass.value) { + m_processor.result().gcode_check_result.error_code |= (1 << 11); // printed weight over limit + } + } if (result != nullptr) { *result = std::move(m_processor.extract_result()); // set the filename to the correct value @@ -2476,6 +2687,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_last_layer_z = 0.f; m_max_layer_z = 0.f; m_last_width = 0.f; + m_last_layer_accumulated_mass = 0.0; m_is_role_based_fan_on.fill(false); m_role_based_fan_marker_layer.fill(-1); @@ -2848,14 +3060,32 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS match_physical_extruder_for_each_filament(first_non_support_filaments, m_config); + // Logical nozzle grouping for this print (null on paths that don't populate it). + auto group_result = m_print->get_layered_nozzle_group_result(); + std::vector first_non_support_hotends; + first_non_support_hotends.reserve(first_non_support_filaments.size()); + for (int filament_id : first_non_support_filaments) + first_non_support_hotends.push_back(filament_id < 0 ? -1 : + first_hotend_id_for_gcode_placeholder(m_config, group_result, filament_id, (int) get_extruder_id(filament_id))); + this->placeholder_parser().set("first_non_support_tools", new ConfigOptionInts(first_non_support_filaments)); this->placeholder_parser().set("first_non_support_filaments", new ConfigOptionInts(first_non_support_filaments)); + this->placeholder_parser().set("first_non_support_hotend", new ConfigOptionInts(first_non_support_hotends)); this->placeholder_parser().set("initial_no_support_tool", initial_non_support_extruder_id); this->placeholder_parser().set("initial_no_support_extruder", initial_non_support_extruder_id); + // initial_no_support_hotend/current_hotend (see first_hotend_id_for_gcode_placeholder): multi-nozzle + // H2C -> -1 (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id. this->placeholder_parser().set("initial_no_support_hotend", - hotend_id_for_gcode_placeholder(m_config, (int) get_extruder_id(initial_non_support_extruder_id))); + first_hotend_id_for_gcode_placeholder(m_config, group_result, (int) initial_non_support_extruder_id, (int) get_extruder_id(initial_non_support_extruder_id))); this->placeholder_parser().set("current_extruder", initial_extruder_id); - this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, extruder_id)); + this->placeholder_parser().set("current_hotend", + first_hotend_id_for_gcode_placeholder(m_config, group_result, (int) initial_extruder_id, extruder_id)); + // Initial filament/nozzle vocabulary + this->placeholder_parser().set("initial_filament_id", (int) initial_extruder_id); + this->placeholder_parser().set("initial_no_support_filament_id", (int) initial_non_support_extruder_id); + this->placeholder_parser().set("initial_nozzle_id", first_nozzle_id_for_gcode_placeholder(group_result, (int) initial_extruder_id, extruder_id)); + this->placeholder_parser().set("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + this->placeholder_parser().set("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); //Orca: set the key for compatibilty this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(initial_extruder_id)); this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(initial_extruder_id)); @@ -2875,7 +3105,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("additional_fan_full_speed_layer", new ConfigOptionInts(m_config.additional_fan_full_speed_layer)); auto flush_v_speed = m_config.filament_flush_volumetric_speed.values; - auto flush_temps = m_config.filament_flush_temp.values; + // Fast purge mode uses filament_flush_temp_fast; Default is inert. + auto flush_temps = (m_config.prime_volume_mode == PrimeVolumeMode::pvmFast ? m_config.filament_flush_temp_fast : m_config.filament_flush_temp).values; for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) { if (flush_v_speed[idx] == 0) flush_v_speed[idx] = m_config.filament_max_volumetric_speed.get_at(idx); @@ -2893,6 +3124,28 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato this->placeholder_parser().set("current_object_idx", 0); // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. this->placeholder_parser().set("has_wipe_tower", has_wipe_tower); + + // Nozzle-heating center just outside the wipe tower. The tower side is chosen + // from the full-bed midpoint, then X is clamped to the region every extruder can reach (shared printable + // polygon) = the full printable_area for all current single/dual printers, so existing output is unchanged. + Vec2f wipe_tower_center = Vec2f::Zero(); + bool wipe_tower_center_valid = false; + if (has_wipe_tower) { + BoundingBoxf bbx = print.wipe_tower_data().bbx; + bbx.translate(print.get_fake_wipe_tower().pos.cast()); + BoundingBoxf printer_bed_bbx(m_config.printable_area.values); + if (bbx.center().x() < printer_bed_bbx.center().x()) + wipe_tower_center = Vec2f(float(bbx.max.x() + 2.f), float(bbx.center().y())); + else + wipe_tower_center = Vec2f(float(bbx.min.x() - 2.f), float(bbx.center().y())); + auto printer_bbx = unscaled(get_extents(print.get_extruder_shared_printable_polygon())); + if (wipe_tower_center.x() < printer_bbx.min[0]) wipe_tower_center.x() = float(printer_bbx.min[0]); + if (wipe_tower_center.x() > printer_bbx.max[0]) wipe_tower_center.x() = float(printer_bbx.max[0]); + wipe_tower_center_valid = true; + } + this->placeholder_parser().set("wipe_tower_center_pos_x", new ConfigOptionFloat(wipe_tower_center.x())); + this->placeholder_parser().set("wipe_tower_center_pos_y", new ConfigOptionFloat(wipe_tower_center.y())); + this->placeholder_parser().set("wipe_tower_center_pos_valid", new ConfigOptionBool(wipe_tower_center_valid)); this->placeholder_parser().set("has_single_extruder_multi_material_priming", wipe_tower_type == WipeTowerType::Type2 && has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("total_toolchanges", DoExport::resolve_total_toolchanges(print.wipe_tower_data(), print.tool_ordering())); this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size())); @@ -3136,6 +3389,13 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Write the custom start G-code file.writeln(machine_start_gcode); + // Mark the end of the machine start g-code so the GCodeProcessor usage-block builder knows where user + // g-code ends and can start attributing filament/extruder usage. Gated on enable_pre_heating: only the + // injector fleet (H2D/X2D/H2D-Pro/H2C) emits it; the byte-frozen fleet (X1/P1/A1/H2S, flag false) never + // does, so their g-code is byte-identical. Without this marker handle_filament_change early-returns and + // no blocks are built, so this line is what actually activates the pre-heat injector. + if (m_config.enable_pre_heating.value) + file.write_format(";%s\n", GCodeProcessor::Machine_Start_GCode_End_Tag.c_str()); //BBS: gcode writer doesn't know where the real position of extruder is after inserting custom gcode m_writer.set_current_position_clear(false); @@ -3147,11 +3407,27 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato { DynamicConfig config; config.set_key_value("filament_extruder_id", new ConfigOptionInt((int)(initial_non_support_extruder_id))); + config.set_key_value("current_filament_id", new ConfigOptionInt((int)(initial_non_support_extruder_id))); + config.set_key_value("current_extruder_id", new ConfigOptionInt((int) get_extruder_id(initial_non_support_extruder_id))); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(first_nozzle_id_for_gcode_placeholder(group_result, (int) initial_non_support_extruder_id, (int) get_extruder_id(initial_non_support_extruder_id)))); + config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); std::string filament_start_gcode = this->placeholder_parser_process("filament_start_gcode", print.config().filament_start_gcode.values.at(initial_non_support_extruder_id), initial_non_support_extruder_id,&config); file.writeln(filament_start_gcode); - // mark the first filament used in print - file.write_format(";VT%d\n", initial_extruder_id); + // Mark the first filament used in print. Multi-nozzle printers (H2C) get ";VT%d H%d" where + // H = dynamic ? nozzle_id : -1; existing single-nozzle printers keep the bare ";VT%d" so their + // g-code stays byte-identical. (The dynamic branch is dormant, so H2C currently emits H-1.) + if (is_multi_nozzle_printer(m_config)) { + int initial_nozzle_id = -1; + if (group_result && group_result->is_support_dynamic_nozzle_map()) { + auto initial_nozzle = group_result->get_first_nozzle_for_filament(initial_extruder_id); + initial_nozzle_id = initial_nozzle ? initial_nozzle->group_id : -1; + } + file.write_format(";VT%d H%d\n", initial_extruder_id, initial_nozzle_id); + } else { + file.write_format(";VT%d\n", initial_extruder_id); + } } // Orca: add missing PA settings for initial filament if (m_config.enable_pressure_advance.get_at(initial_non_support_extruder_id)) { @@ -3471,6 +3747,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // adds tag for processor file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); + // Mark the start of the machine end g-code so the usage-block builder closes its open blocks here and + // ignores filament changes inside the end g-code. Same enable_pre_heating gate as the start marker → + // byte-frozen fleet unaffected. + if (m_config.enable_pre_heating.value) + file.write_format(";%s\n", GCodeProcessor::Machine_End_GCode_Start_Tag.c_str()); + // Process filament-specific gcode in extruder order. { DynamicConfig config; @@ -3478,16 +3760,24 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //BBS config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value)); config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); if (print.config().single_extruder_multi_material) { // Process the filament_end_gcode for the active filament only. int extruder_id = m_writer.filament()->id(); config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); + config.set_key_value("current_filament_id", new ConfigOptionInt(extruder_id)); + config.set_key_value("current_extruder_id", new ConfigOptionInt((int) get_extruder_id(extruder_id))); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(nozzle_id_for_gcode_placeholder(group_result, extruder_id, (int) get_extruder_id(extruder_id), m_layer_index))); file.writeln(this->placeholder_parser_process("filament_end_gcode", print.config().filament_end_gcode.get_at(extruder_id), extruder_id, &config)); } else { for (const std::string &end_gcode : print.config().filament_end_gcode.values) { int extruder_id = (unsigned int)(&end_gcode - &print.config().filament_end_gcode.values.front()); config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id)); + config.set_key_value("current_filament_id", new ConfigOptionInt(extruder_id)); + config.set_key_value("current_extruder_id", new ConfigOptionInt((int) get_extruder_id(extruder_id))); + config.set_key_value("current_nozzle_id", new ConfigOptionInt(nozzle_id_for_gcode_placeholder(group_result, extruder_id, (int) get_extruder_id(extruder_id), m_layer_index))); file.writeln(this->placeholder_parser_process("filament_end_gcode", end_gcode, extruder_id, &config)); } } @@ -3581,7 +3871,18 @@ void GCode::export_layer_filaments(GCodeProcessorResult* result) std::vectorprev_filament(m_config.nozzle_diameter.size(), -1); for (size_t idx = 0; idx < m_sorted_layer_filaments.size(); ++idx) { for (auto f : m_sorted_layer_filaments[idx]) { + // Mirror the guard in the sibling sequence loop below (the `filament_id < filament_map.size() && + // filament_map[filament_id] > 0` check): the H2C dynamic engine can yield a + // per-layer filament set whose ids fall outside filament_map, or a filament_map value beyond the + // physical-extruder count (prev_filament is sized nozzle_diameter.size()). Either an unguarded read + // (filament_map[f], prev_filament[extruder_idx]) or the write below would be out of bounds and + // corrupt the heap. Skipping such filaments keeps every access in range; on any valid slice the + // guard never fires, so the shipping/static path is byte-identical. + if (f >= filament_map.size() || filament_map[f] <= 0) + continue; int extruder_idx = filament_map[f] - 1; + if (extruder_idx >= (int) prev_filament.size()) + continue; if (prev_filament[extruder_idx] != -1 && f != prev_filament[extruder_idx]) { std::pair from_to_pair = { prev_filament[extruder_idx],f }; auto iter = result->filament_change_count_map.find(from_to_pair); @@ -4564,6 +4865,289 @@ std::string GCode::generate_object_brim(const Print &print, const PrintObject &o return emit_brim(brim_it->second, { object.id() }); } +// Bedslinger model. The heavier the bed load, the lower the achievable Y acceleration for a given +// drive force (a = F / (bed_mass + printed_mass)). Reads machine_max_force_Y / machine_bed_mass_Y (both +// default 0, i.e. absent on every existing printer), in which case it just returns the min configured Y +// acceleration. +void GCode::mass_load_limited_machine_acceleration( + const PrintStatistics &curr_print_statistics, + const Print &print, // input + double &y_acceleration_limit_res, // output + double &accumulated_mass_res) +{ + double curr_acceleration_y_config = 1e10; + auto &machine_max_acceleration_y = print.config().machine_max_acceleration_y.values; + for (auto &temp : machine_max_acceleration_y) + if (curr_acceleration_y_config > temp) curr_acceleration_y_config = temp; + accumulated_mass_res = curr_print_statistics.total_weight; + // mass in g, acceleration in mm/s2 + double machine_max_force_Y = print.config().machine_max_force_Y.getFloat(), + machine_bed_mass_Y = print.config().machine_bed_mass_Y.getFloat(); + if (machine_max_force_Y > EPSILON && machine_bed_mass_Y > EPSILON) { + // This item is not applicable to this printer FIXME-other printers need acceleration limit? + double virtual_force_g_mms2 = machine_max_force_Y * 1e6, // x N =x * 1e6 g*mm/s2 + curr_acceleration_temp = curr_acceleration_y_config; // temps + if (accumulated_mass_res > EPSILON) { + curr_acceleration_temp = virtual_force_g_mms2 / (machine_bed_mass_Y + accumulated_mass_res); + y_acceleration_limit_res = std::min(curr_acceleration_temp, curr_acceleration_y_config); + } else { + y_acceleration_limit_res = curr_acceleration_y_config; + BOOST_LOG_TRIVIAL(info) << "mass_load_limited_machine_acceleration: Printed mass not detected"; + } + } else { + y_acceleration_limit_res = curr_acceleration_y_config; + } +} + +// Farthest-point timelapse. Scan every extrusion path on this layer and record the point +// farthest from the camera (bed origin 0,0), plus which extruder prints it and whether that extruder is +// the photo head (most_used_extruder). Called only when the subsystem is enabled, so it is a no-op for +// every printer that does not set farthest_point_timelapse. +// Orca: the PrintRegionConfig filament keys are named outer_wall_filament_id / sparse_infill_filament_id / +// internal_solid_filament_id (handle_legacy renames), so the region reads use those names. +void GCode::compute_farthest_point(const std::vector &layers, int most_used_extruder, + const std::map, unsigned int> &support_filaments) +{ + m_farthest_point_timelapse.farthest_point = Point(0, 0); + m_farthest_point_timelapse.farthest_gcode_pos = Vec2d(0, 0); + m_farthest_point_timelapse.farthest_extruder_id = 0; + m_farthest_point_timelapse.farthest_is_photo_head = false; + + // Track farthest point for external perimeters and fallback (infill/support) separately + int64_t max_dist_sq_ext = -1; + Point farthest_point_ext; + int farthest_extruder_ext = 0; + + int64_t max_dist_sq_fallback = -1; + Point farthest_point_fallback; + int farthest_extruder_fallback = 0; + + // Recursive visitor: call fn(const ExtrusionPath&) for every leaf path + auto for_each_path = [](const ExtrusionEntity *entity, const auto &fn, const auto &self) -> void { + if (entity->is_collection()) { + for (const auto *child : static_cast(entity)->entities) + self(child, fn, self); + } else if (entity->is_loop()) { + for (const ExtrusionPath &p : static_cast(entity)->paths) + fn(p); + } else if (const auto *mp = dynamic_cast(entity)) { + for (const ExtrusionPath &p : mp->paths) + fn(p); + } else { + fn(static_cast(*entity)); + } + }; + + auto is_ext_perimeter_role = [](ExtrusionRole role) -> bool { + return role == erExternalPerimeter; + }; + auto is_fallback_role = [](ExtrusionRole role) -> bool { + return role == erInternalInfill || role == erSolidInfill || role == erTopSolidInfill; + }; + auto is_candidate_support_role = [](ExtrusionRole role) -> bool { + return role == erSupportMaterial || role == erSupportMaterialInterface || role == erSupportTransition; + }; + + // Update a (max_dist_sq, point, extruder_id) triple + auto update_max = [](int64_t &max_dsq, Point &out_point, int &out_ext, + const Point &p, const Point &shift, int extruder_id) { + Point global = p + shift; + int64_t dsq = (int64_t)global.x() * global.x() + (int64_t)global.y() * global.y(); + if (dsq > max_dsq) { + max_dsq = dsq; + out_point = global; + out_ext = extruder_id; + } + }; + + // Collect candidate endpoints from one ExtrusionPath, handling arc fitting. + // Orca: ExtrusionPath::polyline is a Polyline3 (Point3 points) rather than a 2D Polyline, so each + // stored point is projected to 2D via to_point() before the distance test (Z is irrelevant here). + auto collect_from_path = [&update_max](int64_t &max_dsq, Point &out_point, int &out_ext, + const ExtrusionPath &path, const Point &shift, int extruder_id) { + const Polyline3 &poly = path.polyline; + if (poly.points.empty()) return; + + if (!poly.fitting_result.empty()) { + if (poly.fitting_result.front().start_point_index < poly.points.size()) + update_max(max_dsq, out_point, out_ext, + poly.points[poly.fitting_result.front().start_point_index].to_point(), shift, extruder_id); + + for (const PathFittingData &seg : poly.fitting_result) { + if (seg.path_type == EMovePathType::Linear_move) { + for (size_t i = seg.start_point_index; i <= seg.end_point_index && i < poly.points.size(); ++i) + update_max(max_dsq, out_point, out_ext, poly.points[i].to_point(), shift, extruder_id); + } else if (seg.path_type == EMovePathType::Arc_move_cw || seg.path_type == EMovePathType::Arc_move_ccw) { + update_max(max_dsq, out_point, out_ext, seg.arc_data.end_point, shift, extruder_id); + } + } + } else { + for (const Point3 &pt : poly.points) + update_max(max_dsq, out_point, out_ext, pt.to_point(), shift, extruder_id); + } + }; + + // Single pass: scan all paths, collecting ext-perimeter and fallback candidates. + // Use original_object (not ltp.object()) to get instance shifts, because + // ltp.object() may return a shared/merged PrintObject whose instances() only + // reflects one copy's shift. original_object preserves the per-ModelObject + // PrintObject with correct instance positions. + for (const LayerToPrint <p : layers) { + const PrintObject *print_obj = ltp.original_object; + if (!print_obj) continue; + + for (const PrintInstance &inst : print_obj->instances()) { + const Point &shift = inst.shift; + + if (ltp.object_layer) { + for (const LayerRegion *region : ltp.object_layer->regions()) { + const PrintRegionConfig &rcfg = region->region().config(); + + for (const ExtrusionEntity *entity : region->perimeters.entities) { + for_each_path(entity, [&](const ExtrusionPath &path) { + if (is_ext_perimeter_role(path.role())) + collect_from_path(max_dist_sq_ext, farthest_point_ext, farthest_extruder_ext, + path, shift, (int)get_extruder_id(rcfg.outer_wall_filament_id.value - 1)); + }, for_each_path); + } + + for (const ExtrusionEntity *entity : region->fills.entities) { + for_each_path(entity, [&](const ExtrusionPath &path) { + if (!is_fallback_role(path.role())) return; + int eid = (path.role() == erInternalInfill) + ? (int)get_extruder_id(rcfg.sparse_infill_filament_id.value - 1) + : (int)get_extruder_id(rcfg.internal_solid_filament_id.value - 1); + collect_from_path(max_dist_sq_fallback, farthest_point_fallback, farthest_extruder_fallback, + path, shift, eid); + }, for_each_path); + } + } + } + + if (ltp.support_layer) { + for (const ExtrusionEntity *entity : ltp.support_layer->support_fills.entities) { + for_each_path(entity, [&](const ExtrusionPath &path) { + if (!is_candidate_support_role(path.role())) return; + auto support_filament = support_filaments.find({ ltp.support_layer, path.role() }); + if (support_filament == support_filaments.end()) return; + int eid = (int)get_extruder_id(support_filament->second); + collect_from_path(max_dist_sq_fallback, farthest_point_fallback, farthest_extruder_fallback, + path, shift, eid); + }, for_each_path); + } + } + } + } + + // Prefer external perimeter result; fall back to infill/support + int64_t max_dist_sq; + if (max_dist_sq_ext > 0) { + max_dist_sq = max_dist_sq_ext; + m_farthest_point_timelapse.farthest_point = farthest_point_ext; + m_farthest_point_timelapse.farthest_extruder_id = farthest_extruder_ext; + } else { + max_dist_sq = max_dist_sq_fallback; + m_farthest_point_timelapse.farthest_point = farthest_point_fallback; + m_farthest_point_timelapse.farthest_extruder_id = farthest_extruder_fallback; + } + + if (max_dist_sq > 0) { + m_farthest_point_timelapse.farthest_gcode_pos = unscale(m_farthest_point_timelapse.farthest_point); + // Single nozzle with AMS: all virtual extruders share one physical nozzle, + // so the nozzle is always the photo head regardless of which filament is used. + bool single_nozzle = (m_config.nozzle_diameter.size() <= 1); + m_farthest_point_timelapse.farthest_is_photo_head = single_nozzle || (m_farthest_point_timelapse.farthest_extruder_id == most_used_extruder); + } +} + +// Build the per-layer timelapse snapshot g-code. Extracted from the former process_layer +// `insert_timelapse_gcode` lambda so the per-extrusion inline hook in _extrude() can call it too. +// Byte-identical to the old lambda whenever the farthest-point subsystem is off (skip_pos_pick=false + +// m_farthest_point_timelapse.enabled=false → farthest_point unset in the picker ctx and +// farthest_point_timelapse_enabled=false in the template). +// Orca: returns the g-code string directly (Orca's timelapse path never tracked a final_pos travel +// optimization). +std::string GCode::generate_timelapse_gcode(const Print &print, coordf_t print_z, int most_used_extruder, + const std::set *layer_object_label_ids, + const std::vector *printed_objects, + bool skip_pos_pick) +{ + if (!m_writer.filament()) + return {}; + + PosPickCtx ctx; + ctx.curr_pos = { (coord_t)(scale_(m_writer.get_position().x())),(coord_t)(scale_(m_writer.get_position().y())) }; + ctx.curr_layer = this->layer(); + ctx.curr_extruder_id = m_writer.filament()->extruder_id(); + ctx.picture_extruder_id = most_used_extruder; + if (m_farthest_point_timelapse.enabled) { + // farthest_point is stored in the global print frame (includes plate origin); the picker works in + // the plate-relative frame, so subtract the plate origin here. + Vec3d po = print.get_plate_origin(); + ctx.farthest_point = m_farthest_point_timelapse.farthest_point - Point(scale_(po.x()), scale_(po.y())); + } + if (m_config.print_sequence == PrintSequence::ByObject && printed_objects) + ctx.printed_objects = *printed_objects; + + auto timelapse_pos = skip_pos_pick ? DefaultTimelapsePos : m_timelapse_pos_picker.pick_pos(ctx); + + std::string timelapse_gcode; + if (!print.config().time_lapse_gcode.value.empty()) { + DynamicConfig config; + config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); + config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); + config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); + config.set_key_value("most_used_physical_extruder_id", new ConfigOptionInt(m_config.physical_extruder_map.get_at(most_used_extruder))); + config.set_key_value("curr_physical_extruder_id", new ConfigOptionInt(m_config.physical_extruder_map.get_at(ctx.curr_extruder_id))); + config.set_key_value("timelapse_pos_x", new ConfigOptionInt((int)timelapse_pos.x())); + config.set_key_value("timelapse_pos_y", new ConfigOptionInt((int)timelapse_pos.y())); + config.set_key_value("has_timelapse_safe_pos", new ConfigOptionBool(timelapse_pos != DefaultTimelapsePos)); + // Timelapse-context vars. + config.set_key_value("timelapse_inline_photo", new ConfigOptionBool(skip_pos_pick)); + // Drive the template ternary Z{layer_z + (farthest_point_timelapse_enabled ? 0.0 : 0.4)} from the + // effective (per-layer, config+traditional+non-i3-folded) enabled state. False for every printer + // that leaves the toggle off, so their template evaluates to the pre-existing +0.4 lift byte-for-byte. + config.set_key_value("farthest_point_timelapse_enabled", new ConfigOptionBool(m_farthest_point_timelapse.enabled)); + config.set_key_value("clear_to_x0", new ConfigOptionBool(m_timelapse_pos_picker.get_is_clear_to_x0(ctx))); + timelapse_gcode = this->placeholder_parser_process("timelapse_gcode", print.config().time_lapse_gcode.value, m_writer.filament()->id(), &config) + "\n"; + } + + if (!timelapse_gcode.empty()) { + m_writer.set_current_position_clear(false); + + double temp_z_after_tool_change; + if (GCodeProcessor::get_last_z_from_gcode(timelapse_gcode, temp_z_after_tool_change)) { + Vec3d pos = m_writer.get_position(); + pos(2) = temp_z_after_tool_change; + m_writer.set_position(pos); + } + } + + // (layer_object_label_ids->size() < 64) this restriction comes from _encode_label_ids_to_base64() + if (layer_object_label_ids && + is_BBL_Printer() && + (print.num_object_instances() <= g_max_label_object) && // Don't support too many objects on one plate + (print.num_object_instances() > 1) && // Don't support skipping single object + (!layer_object_label_ids->empty()) && + (print.calib_params().mode == CalibMode::Calib_None)) { + std::ostringstream oss; + for (auto it = layer_object_label_ids->begin(); it != layer_object_label_ids->end(); ++it) { + if (it != layer_object_label_ids->begin()) oss << ","; + oss << *it; + } + + std::string start_str = std::string("; object ids of layer ") + std::to_string(m_layer_index + 1) + (" start: ") + oss.str() + "\n"; + start_str += "M624 " + _encode_label_ids_to_base64(std::vector(layer_object_label_ids->begin(), layer_object_label_ids->end())) + "\n"; + + std::string end_str = std::string("; object ids of this layer") + std::to_string(m_layer_index + 1) + (" end: ") + oss.str() + "\n"; + end_str += "M625\n"; + + timelapse_gcode = start_str + timelapse_gcode + end_str; + } + + return timelapse_gcode; +} + // In sequential mode, process_layer is called once per each object and its copy, // therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object. // In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated. @@ -4678,6 +5262,16 @@ LayerResult GCode::process_layer( bool is_i3_printer = printer_structure == PrinterStructure::psI3; bool is_multi_extruder = m_config.nozzle_diameter.size() > 1; + // Farthest-point timelapse enable-fold. Corexy-only: gated OFF for i3 (psI3 → A1/A2L), for + // smooth timelapse, and whenever the toggle is unset. When false every downstream hook (compute, + // _extrude inline photo, process_layer case gates, template ternary) is inert, so the whole shipping + // fleet that does not set farthest_point_timelapse is byte-identical to the pre-existing behavior. + m_farthest_point_timelapse.enabled = m_config.farthest_point_timelapse.value + && m_config.timelapse_type.value == TimelapseType::tlTraditional + && printer_structure != PrinterStructure::psI3; + m_farthest_point_timelapse.most_used_extruder = most_used_extruder; + m_farthest_point_timelapse.inserted_this_layer = false; + bool need_insert_timelapse_gcode_for_traditional = false; if ((!m_wipe_tower || !m_wipe_tower->enable_timelapse_print()) && (is_BBL_Printer() || !m_config.time_lapse_gcode.value.empty())) { need_insert_timelapse_gcode_for_traditional = ((is_i3_printer && !m_spiral_vase) || is_multi_extruder); @@ -4712,6 +5306,28 @@ LayerResult GCode::process_layer( config.set_key_value("most_used_physical_extruder_id", new ConfigOptionInt(m_config.physical_extruder_map.get_at(most_used_extruder))); config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); + + // Bedslinger mass model. Compute the running printed mass at this layer (same weight calc as + // DoExport::update_print_stats_and_format_filament_stats) and the Y acceleration limit it implies. + // These are new placeholder vars no existing template reads, and mass_load_limited_machine_acceleration + // returns the plain min Y accel unless the A2L force/bed-mass keys are set, so this is inert for every + // existing printer. + PrintStatistics curr_print_statistics; + for (const Extruder &extruder : m_writer.extruders()) { + double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter + double filament_weight = extruded_volume * extruder.filament_density() * 0.001; + if (filament_weight > 0.) + curr_print_statistics.total_weight += filament_weight; + } + double curr_y_acceleration_limit = -1, curr_accumulated_mass = -1; + mass_load_limited_machine_acceleration(curr_print_statistics, print, curr_y_acceleration_limit, curr_accumulated_mass); + double curr_layer_mass = curr_print_statistics.total_weight - m_last_layer_accumulated_mass; + if (curr_layer_mass <= EPSILON) curr_layer_mass = 0.0; + m_last_layer_accumulated_mass = curr_print_statistics.total_weight; + config.set_key_value("curr_y_acceleration_limit", new ConfigOptionFloat(curr_y_acceleration_limit)); + config.set_key_value("curr_accumulated_mass", new ConfigOptionFloat(curr_accumulated_mass)); + config.set_key_value("curr_layer_mass", new ConfigOptionFloat(curr_layer_mass)); + gcode += this->placeholder_parser_process("layer_change_gcode", print.config().layer_change_gcode.value, m_writer.filament()->id(), &config) + "\n"; @@ -4896,6 +5512,10 @@ LayerResult GCode::process_layer( // Group extrusions by an extruder, then by an object, an island and a region. std::map> by_extruder; + // Farthest-point timelapse: per-support-layer/role → extruder map, consumed only by + // compute_farthest_point (below, gated on m_farthest_point_timelapse.enabled). Populated alongside the + // existing support-extruder assignment; unused (and thus output-neutral) when the subsystem is off. + std::map, unsigned int> support_filaments; std::vector> split_perimeter_storage; bool is_anything_overridden = const_cast(layer_tools).wiping_extrusions().is_anything_overridden(); for (const LayerToPrint &layer_to_print : layers) { @@ -4989,6 +5609,16 @@ LayerResult GCode::process_layer( // Both the support and the support interface are printed with the same extruder, therefore // the interface may be interleaved with the support base. bool single_extruder = ! has_support || support_extruder == interface_extruder; + // Farthest-point timelapse: record the extruder for each support role so + // compute_farthest_point can attribute farthest support points correctly. + if (has_support) { + support_filaments[{ &support_layer, erSupportMaterial }] = support_extruder; + support_filaments[{ &support_layer, erSupportTransition }] = support_extruder; + } + if (has_interface) { + support_filaments[{ &support_layer, erSupportMaterialInterface }] = + single_extruder ? (has_support ? support_extruder : interface_extruder) : interface_extruder; + } // Assign an extruder to the base. ObjectByExtruder &obj = object_by_extruder(by_extruder, has_support ? support_extruder : interface_extruder, &layer_to_print - layers.data(), layers.size()); obj.support = &support_layer.support_fills; @@ -5136,6 +5766,11 @@ LayerResult GCode::process_layer( } } // for objects + // Farthest-point timelapse: once all this layer's extrusions are grouped, find the point + // farthest from the camera. No-op when the subsystem is disabled. + if (m_farthest_point_timelapse.enabled) + compute_farthest_point(layers, most_used_extruder, support_filaments); + std::map> filament_to_print_instances; { for (unsigned int filament_id : layer_tools.extruders) { @@ -5175,67 +5810,20 @@ LayerResult GCode::process_layer( } } - auto insert_timelapse_gcode = [this, print_z, &print, &most_used_extruder, &layer_object_label_ids,&printed_objects = std::as_const(m_printed_objects)]() -> std::string { - PosPickCtx ctx; - ctx.curr_pos = { (coord_t)(scale_(m_writer.get_position().x())),(coord_t)(scale_(m_writer.get_position().y())) }; - ctx.curr_layer = this->layer(); - ctx.curr_extruder_id = m_writer.filament()->extruder_id(); - ctx.picture_extruder_id = most_used_extruder; - if (m_config.print_sequence == PrintSequence::ByObject) - ctx.printed_objects = printed_objects; + m_farthest_point_timelapse.layer_object_label_ids = layer_object_label_ids; - auto timelapse_pos=m_timelapse_pos_picker.pick_pos(ctx); - - std::string timelapse_gcode; - if (!print.config().time_lapse_gcode.value.empty()) { - DynamicConfig config; - config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); - config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); - config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); - config.set_key_value("most_used_physical_extruder_id", new ConfigOptionInt(m_config.physical_extruder_map.get_at(most_used_extruder))); - config.set_key_value("curr_physical_extruder_id", new ConfigOptionInt(m_config.physical_extruder_map.get_at(ctx.curr_extruder_id))); - config.set_key_value("timelapse_pos_x", new ConfigOptionInt((int)timelapse_pos.x())); - config.set_key_value("timelapse_pos_y", new ConfigOptionInt((int)timelapse_pos.y())); - config.set_key_value("has_timelapse_safe_pos", new ConfigOptionBool(timelapse_pos != DefaultTimelapsePos)); - timelapse_gcode = this->placeholder_parser_process("timelapse_gcode", print.config().time_lapse_gcode.value, m_writer.filament()->id(), &config) + "\n"; - } - - if (!timelapse_gcode.empty()) { - m_writer.set_current_position_clear(false); - - double temp_z_after_tool_change; - if (GCodeProcessor::get_last_z_from_gcode(timelapse_gcode, temp_z_after_tool_change)) { - Vec3d pos = m_writer.get_position(); - pos(2) = temp_z_after_tool_change; - m_writer.set_position(pos); - } - } - - // (layer_object_label_ids.size() < 64) this restriction comes from _encode_label_ids_to_base64() - if (is_BBL_Printer() && - (print.num_object_instances() <= g_max_label_object) && // Don't support too many objects on one plate - (print.num_object_instances() > 1) && // Don't support skipping single object - (layer_object_label_ids.size() > 0) && - (print.calib_params().mode == CalibMode::Calib_None)) { - std::ostringstream oss; - for (auto it = layer_object_label_ids.begin(); it != layer_object_label_ids.end(); ++it) { - if (it != layer_object_label_ids.begin()) oss << ","; - oss << *it; - } - - std::string start_str = std::string("; object ids of layer ") + std::to_string(m_layer_index + 1) + (" start: ") + oss.str() + "\n"; - start_str += "M624 " + _encode_label_ids_to_base64(std::vector(layer_object_label_ids.begin(), layer_object_label_ids.end())) + "\n"; - - std::string end_str = std::string("; object ids of this layer") + std::to_string(m_layer_index + 1) + (" end: ") + oss.str() + "\n"; - end_str += "M625\n"; - - timelapse_gcode = start_str + timelapse_gcode + end_str; - } - - return timelapse_gcode; + // skip_pos_pick: when true the head takes an inline photo at its current spot instead of moving to a + // picked safe position. Delegates to the extracted member so the per-extrusion farthest-point hook in + // _extrude() shares the exact same generation path. Every existing call site uses the default (false). + auto insert_timelapse_gcode = [this, print_z, &print, &most_used_extruder, &layer_object_label_ids,&printed_objects = std::as_const(m_printed_objects)](bool skip_pos_pick = false) -> std::string { + return generate_timelapse_gcode(print, print_z, most_used_extruder, &layer_object_label_ids, &printed_objects, skip_pos_pick); }; - if (!need_insert_timelapse_gcode_for_traditional && is_BBL_Printer()) { // Equivalent to the timelapse gcode placed in layer_change_gcode + // With farthest-point-is-photo-head active, the snapshot is deferred to the inline _extrude + // hook / layer-end fallback, so skip the layer-start placement here. The extra clause is inert (true) + // whenever the subsystem is off → pre-existing behavior byte-for-byte. + if (!need_insert_timelapse_gcode_for_traditional && is_BBL_Printer() + && !(m_farthest_point_timelapse.enabled && m_farthest_point_timelapse.farthest_is_photo_head)) { // Equivalent to the timelapse gcode placed in layer_change_gcode if (FILAMENT_CONFIG(retract_when_changing_layer)) { gcode += this->retract(false, false, auto_lift_type, true); } @@ -5291,15 +5879,24 @@ LayerResult GCode::process_layer( m_filament_instances_code = _encode_label_ids_to_base64(filament_instances_id); } + // The inline _extrude hook may already have taken the snapshot mid-extrusion on a + // previous extruder; sync so we don't insert it a second time. + has_insert_timelapse_gcode |= m_farthest_point_timelapse.inserted_this_layer; + std::string gcode_toolchange; if (has_wipe_tower) { if (!m_wipe_tower->is_empty_wipe_tower_gcode(*this, extruder_id, extruder_id == layer_tools.extruders.back())) { - if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) { + if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode + && !(m_farthest_point_timelapse.enabled && m_farthest_point_timelapse.farthest_is_photo_head)) { bool should_insert = true; if (m_config.nozzle_diameter.values.size() == 2){ - if (!writer().filament() || get_extruder_id(writer().filament()->id()) != most_used_extruder) { - should_insert = false; - } + bool curr_is_photo_head = writer().filament() && + get_extruder_id(writer().filament()->id()) == most_used_extruder; + // Case B (farthest point printed by a non-photo head): the firmware + // snapshots at the picked safe pos, so insert when leaving the photo head instead. + // is_case_b is false whenever the subsystem is off → should_insert == pre-existing value. + bool is_case_b = m_farthest_point_timelapse.enabled && !m_farthest_point_timelapse.farthest_is_photo_head; + should_insert = is_case_b ? !curr_is_photo_head : curr_is_photo_head; } if (should_insert) { @@ -5319,17 +5916,24 @@ LayerResult GCode::process_layer( gcode_toolchange = m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()); } } else { + // Same case-A/case-B split for the non-wipe-tower path. With the subsystem off, + // is_case_b is false and should_insert == (curr == most_used) = pre-existing behavior. if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && + !(m_farthest_point_timelapse.enabled && m_farthest_point_timelapse.farthest_is_photo_head) && m_writer.need_toolchange(extruder_id) && m_config.nozzle_diameter.values.size() == 2 && - writer().filament() && - (get_extruder_id(writer().filament()->id()) == most_used_extruder)) { - gcode += this->retract(false, false, auto_lift_type, true); - m_writer.add_object_change_labels(gcode); + writer().filament()) { + bool curr_is_photo_head = get_extruder_id(writer().filament()->id()) == most_used_extruder; + bool is_case_b = m_farthest_point_timelapse.enabled && !m_farthest_point_timelapse.farthest_is_photo_head; + bool should_insert = is_case_b ? !curr_is_photo_head : curr_is_photo_head; + if (should_insert) { + gcode += this->retract(false, false, auto_lift_type, true); + m_writer.add_object_change_labels(gcode); - gcode += insert_timelapse_gcode(); - has_insert_timelapse_gcode = true; + gcode += insert_timelapse_gcode(); + has_insert_timelapse_gcode = true; + } } if (print.config().enable_wrapping_detection && !has_insert_wrapping_detection_gcode) { @@ -5557,6 +6161,22 @@ LayerResult GCode::process_layer( BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << log_memory_info(); + // The inline _extrude hook may have taken the snapshot; sync. + has_insert_timelapse_gcode |= m_farthest_point_timelapse.inserted_this_layer; + + // Farthest-point-is-photo-head layer-end fallback. If the head never passed within tolerance of + // the farthest point during extrusion (so the inline hook never fired) insert the snapshot here — + // single-extruder prints have no traditional multi-extruder fallback below. Guarded on enabled, so this + // block never runs for a printer with the subsystem off. + if (m_farthest_point_timelapse.enabled && m_farthest_point_timelapse.farthest_is_photo_head && !has_insert_timelapse_gcode) { + if (FILAMENT_CONFIG(retract_when_changing_layer)) { + gcode += this->retract(false, false, auto_lift_type, true); + } + m_writer.add_object_change_labels(gcode); + gcode += insert_timelapse_gcode(); + has_insert_timelapse_gcode = true; + } + if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) { // The traditional model of thin-walled object will have flaws for I3 if (m_support_traditional_timelapse @@ -5625,7 +6245,10 @@ void GCode::append_full_config(const Print &print, std::string &str) { DynamicPrintConfig cfg = print.full_print_config(); { // correct the flush_volumes_matrix with flush_multiplier values - std::vector temp_cfg_flush_multiplier = cfg.option("flush_multiplier")->values; + // Fast purge mode uses flush_multiplier_fast; Default is inert. + std::vector temp_cfg_flush_multiplier = (print.config().prime_volume_mode == PrimeVolumeMode::pvmFast) + ? cfg.option("flush_multiplier_fast")->values + : cfg.option("flush_multiplier")->values; std::vector temp_flush_volumes_matrix = cfg.option("flush_volumes_matrix")->values; auto temp_filament_color = cfg.option("filament_colour")->values; size_t heads_count_tmp = temp_cfg_flush_multiplier.size(), @@ -5648,6 +6271,29 @@ void GCode::append_full_config(const Print &print, std::string &str) } // Sorted list of config keys, which shall not be stored into the G-code. Initializer list. static const std::set banned_keys( { + // filament_extruder_compatibility is a device-side (blacklist) compatibility hint read from the + // loaded presets, never consumed by slicing or firmware. Keep it out of the G-code config block so + // the config key stays inert to g-code (byte-identical output). + "filament_extruder_compatibility"sv, + // The fast-purge / prime-volume-mode keys are new static-member registrations. Excluding them from + // the config block keeps registration byte-identical for the shipping fleet (default + // prime_volume_mode==Default leaves the slicing body unchanged; only the config-dump would otherwise + // gain lines). They only affect output on the pvmFast / pvmSaving branch. + "prime_volume_mode"sv, + "flush_multiplier_fast"sv, + "filament_flush_temp_fast"sv, + "support_fast_purge_mode"sv, + // deretract_speed_extruder_change is a device/firmware-facing machine-profile key with no slicer + // consumer. Banning it from the g-code config dump keeps the H2D/A2L/X2D/P2S leaves that carry it + // byte-identical, while still registering it as a known, validated config key. + "deretract_speed_extruder_change"sv, + // farthest_point_timelapse is a newly-registered printer key (corexy-only timelapse refinement). + // Excluding it from the config block keeps the config-dump byte-identical for the whole shipping + // fleet — otherwise every printer's dump would gain a `= 0` line vs the previous baseline, and + // H2C/H2D would gain a non-timelapse `= 1` line. The key is read at slice time from m_config, so + // banning it from the dump has no effect on the feature; the only H2C/H2D delta is the M9711/M971 + // snapshot reposition. + "farthest_point_timelapse"sv, "compatible_printers"sv, "compatible_prints"sv, "print_host"sv, @@ -6969,6 +7615,34 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, ironing_fan_speed >= 0 && path.role() == erIroning); }; + // Farthest-point timelapse inline hook. When the photo head reaches (within 0.5 mm of) the + // farthest-from-camera point while extruding, take the snapshot in place (skip_pos_pick → M971 inline + // photo, no travel). Early-returns unless the subsystem is enabled AND the farthest point is on the + // photo head, so it is a no-op for every printer that leaves the toggle off. + auto check_and_insert_timelapse = [this, &gcode](const Point &endpoint_scaled) { + if (!m_farthest_point_timelapse.enabled || !m_farthest_point_timelapse.farthest_is_photo_head || m_farthest_point_timelapse.inserted_this_layer) + return; + // Inline M971 only when current extruder is the photo head; other nozzles may pass through nearby + // coordinates but their physical position differs. + if (!m_writer.filament() || get_extruder_id(m_writer.filament()->id()) != m_farthest_point_timelapse.most_used_extruder) + return; + // Compare in the global print frame to match farthest_gcode_pos, which is unscale(farthest_point) + // without the per-extruder nozzle offset. Using point_to_gcode() here would subtract extruder_offset + // on this side only, leaving a constant mismatch that could prevent the inline photo from ever + // triggering on machines with a non-zero photo-head extruder_offset. + Vec2d endpoint_mm = unscale(endpoint_scaled) + m_origin; + if ((endpoint_mm - m_farthest_point_timelapse.farthest_gcode_pos).norm() >= 0.5) + return; + if (!m_print || !m_layer) + return; + std::string timelapse_gcode = generate_timelapse_gcode(*m_print, m_layer->print_z, m_farthest_point_timelapse.most_used_extruder, + &m_farthest_point_timelapse.layer_object_label_ids, &m_printed_objects, true); + if (!timelapse_gcode.empty()) { + gcode += timelapse_gcode; + m_farthest_point_timelapse.inserted_this_layer = true; + } + }; + if (!variable_speed) { // F is mm per minute. if( (std::abs(writer().get_current_speed() - F) > EPSILON) || (std::abs(_mm3_per_mm - m_last_mm3_mm) > EPSILON) ){ @@ -7092,6 +7766,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, dE * e_ratio, GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion()); } + check_and_insert_timelapse(line.b.to_point()); // Inline farthest-point snapshot } } else { // BBS: start to generate gcode from arc fitting data which includes line and arc @@ -7121,6 +7796,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, this->point_to_gcode(line.b), dE, GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion()); + check_and_insert_timelapse(line.b); // Inline farthest-point snapshot } break; } @@ -7146,6 +7822,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, dE, arc.direction == ArcDirection::Arc_Dir_CCW, GCodeWriter::full_gcode_comment ? tempDescription : "", path.is_force_no_extrusion()); + check_and_insert_timelapse(arc.end_point); // Inline farthest-point snapshot break; } default: @@ -7292,6 +7969,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += m_writer.extrude_to_xyz(dest3d, dE * e_ratio, GCodeWriter::full_gcode_comment ? tempDescription : ""); } + // Inline farthest-point snapshot on the variable-speed emission path. Inert unless the + // farthest-point subsystem is on, matching the other paths. + check_and_insert_timelapse(processed_point.p.to_point()); + prev = p; } @@ -7905,13 +8586,32 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo // set volumetric speed of outer wall ,ignore per obejct,just use default setting float outer_wall_volumetric_speed = get_outer_wall_volumetric_speed(m_config, *m_print, new_filament_id, get_extruder_id(new_filament_id)); float wipe_avoid_pos_x = 110.f; + // Logical nozzle grouping (null on paths that don't populate it) + null-safe nozzle ids. + auto group_result = m_print->get_layered_nozzle_group_result(); + int old_nozzle_id = nozzle_id_for_gcode_placeholder(group_result, old_filament_id, old_extruder_id, m_layer_index); + int next_nozzle_id = nozzle_id_for_gcode_placeholder(group_result, (int) new_filament_id, new_extruder_id, m_layer_index); DynamicConfig dyn_config; dyn_config.set_key_value("outer_wall_volumetric_speed", new ConfigOptionFloat(outer_wall_volumetric_speed)); dyn_config.set_key_value("previous_extruder", new ConfigOptionInt(old_filament_id)); dyn_config.set_key_value("next_extruder", new ConfigOptionInt((int)new_filament_id)); - dyn_config.set_key_value("current_hotend", - new ConfigOptionInt(old_filament_id >= 0 ? hotend_id_for_gcode_placeholder(m_config, old_extruder_id) : -1)); - dyn_config.set_key_value("next_hotend", new ConfigOptionInt(hotend_id_for_gcode_placeholder(m_config, new_extruder_id))); + // current_hotend/next_hotend (see hotend_id_for_gcode_placeholder): multi-nozzle H2C -> -1 + // (static; dynamic branch dormant), X2D -> -1, existing printers -> extruder id. + dyn_config.set_key_value("current_hotend", new ConfigOptionInt( + hotend_id_for_gcode_placeholder(m_config, group_result, old_filament_id, old_extruder_id, m_layer_index))); + dyn_config.set_key_value("next_hotend", new ConfigOptionInt( + hotend_id_for_gcode_placeholder(m_config, group_result, (int) new_filament_id, new_extruder_id, m_layer_index))); + dyn_config.set_key_value("current_nozzle_id", new ConfigOptionInt(old_nozzle_id)); + dyn_config.set_key_value("next_nozzle_id", new ConfigOptionInt(next_nozzle_id)); + dyn_config.set_key_value("current_filament_id", new ConfigOptionInt(old_filament_id)); + dyn_config.set_key_value("next_filament_id", new ConfigOptionInt((int)new_filament_id)); + dyn_config.set_key_value("nozzle_diameter_at_nozzle_id", new ConfigOptionFloats(get_nozzle_diameters_by_nozzle_id(group_result.get()))); + dyn_config.set_key_value("nozzle_volume_types", new ConfigOptionStrings(get_nozzle_volume_types_by_nozzle_id(group_result.get()))); + // Old filament's nozzle-change retract length (filament_retract_length_nc; nil/-1 -> 0). + dyn_config.set_key_value("filament_retract_length_nc", new ConfigOptionFloat( + (old_filament_id != -1) ? (float) m_config.filament_retract_length_nc.get_at(old_filament_id) : 0.f)); + // Current parked-retract length of the incoming filament's extruder. + dyn_config.set_key_value("new_extruder_retracted_length", + new ConfigOptionFloat(m_writer.get_extruder_retracted_length((int) new_filament_id))); dyn_config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); dyn_config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); dyn_config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z)); @@ -7964,7 +8664,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo } auto flush_v_speed = m_print->config().filament_flush_volumetric_speed.values; - auto flush_temps = m_print->config().filament_flush_temp.values; + // Fast purge mode uses filament_flush_temp_fast; Default is inert. + auto flush_temps = (m_print->config().prime_volume_mode == PrimeVolumeMode::pvmFast ? m_print->config().filament_flush_temp_fast : m_print->config().filament_flush_temp).values; auto filament_cooling_before_tower = m_print->config().filament_cooling_before_tower.values; for (size_t idx = 0; idx < flush_v_speed.size(); ++idx) { if (flush_v_speed[idx] == 0) @@ -8052,7 +8753,8 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo } this->placeholder_parser().set("current_extruder", new_filament_id); - this->placeholder_parser().set("current_hotend", hotend_id_for_gcode_placeholder(m_config, new_extruder_id)); + this->placeholder_parser().set("current_hotend", + hotend_id_for_gcode_placeholder(m_config, group_result, (int) new_filament_id, new_extruder_id, m_layer_index)); this->placeholder_parser().set("retraction_distance_when_cut", m_config.retraction_distances_when_cut.get_at(new_filament_id)); this->placeholder_parser().set("long_retraction_when_cut", m_config.long_retractions_when_cut.get_at(new_filament_id)); this->placeholder_parser().set("retraction_distance_when_ec", m_config.retraction_distances_when_ec.get_at(new_filament_id)); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 01c253a4fc..9acff7c82c 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -252,7 +252,8 @@ public: std::string travel_to(const Point& point, ExtrusionRole role, std::string comment, double z = DBL_MAX); bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type); std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::NormalLift, bool apply_instantly = false, ExtrusionRole role = erNone); - std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } + // extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract. + std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); } std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1); bool is_BBL_Printer(); WipeTowerType wipe_tower_type(); @@ -402,6 +403,11 @@ private: std::string preamble(); // BBS std::string change_layer(coordf_t print_z); + // Bedslinger model: derive the Y-axis acceleration limit from the machine force/bed-mass config + // and the mass already printed. Yields the min machine Y acceleration when the A2L config keys are + // unset (i.e. every existing printer), so it is inert for them. + void mass_load_limited_machine_acceleration(const PrintStatistics &curr_print_statistics, const Print &print, + double &y_acceleration_limit_res, double &accumulated_mass_res); // Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop // should be executed std::string extrude_entity(const ExtrusionEntity& entity, @@ -500,6 +506,18 @@ private: std::string extrude_infill(const Print& print, const std::vector& by_region, bool ironing); std::string extrude_support(const ExtrusionEntityCollection& support_fills, const ExtrusionRole support_extrusion_role); + // Farthest-point timelapse: find the extrusion point farthest from camera (0,0) + void compute_farthest_point(const std::vector &layers, int most_used_extruder, + const std::map, unsigned int> &support_filaments); + // Build the per-layer timelapse snapshot g-code (safe-position or, when skip_pos_pick, + // an inline photo at the current head position). Extracted from the former process_layer lambda so the + // per-extrusion farthest-point hook (_extrude) can call it too. Identical to the old lambda when the + // farthest-point subsystem is disabled (skip_pos_pick=false, m_farthest_point_timelapse.enabled=false). + std::string generate_timelapse_gcode(const Print &print, coordf_t print_z, int most_used_extruder, + const std::set *layer_object_label_ids, + const std::vector *printed_objects, + bool skip_pos_pick = false); + // BBS LiftType to_lift_type(ZHopType z_hop_types); @@ -556,6 +574,32 @@ private: AvoidCrossingPerimeters m_avoid_crossing_perimeters; RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters; TimelapsePosPicker m_timelapse_pos_picker; + + // Farthest-point timelapse context. Corexy-only refinement layered on top of the existing + // timelapse_type. All fields default to the inert state; `enabled` is (re)computed each layer in + // process_layer and is false whenever the farthest_point_timelapse config toggle is off, the printer + // is i3 (psI3), or timelapse_type is not traditional — so every shipping printer that does not set the + // toggle is identical to the previous path. + struct FarthestPointTimelapseContext { + // Whether farthest-point timelapse is active for this layer + bool enabled{false}; + // The farthest extrusion point from camera (0,0) in global scaled coordinates (includes plate origin + inst.shift) + Point farthest_point; + // farthest_point converted to mm (gcode coordinate space, includes plate origin) + Vec2d farthest_gcode_pos{0, 0}; + // Extruder index (0-based) that prints the farthest point + int farthest_extruder_id{0}; + // Whether the farthest point is printed by the photo head (most_used_extruder) + bool farthest_is_photo_head{false}; + // Whether inline timelapse gcode has already been inserted on this layer + bool inserted_this_layer{false}; + // The extruder used most on this layer, chosen as the photo head + int most_used_extruder{0}; + // Object labels for the current layer, used when inline timelapse is inserted from extrusion code. + std::set layer_object_label_ids; + }; + FarthestPointTimelapseContext m_farthest_point_timelapse; + bool m_enable_loop_clipping; //resonance avoidance bool m_resonance_avoidance; @@ -595,6 +639,9 @@ private: float m_last_layer_z{ 0.0f }; float m_max_layer_z{ 0.0f }; float m_last_width{ 0.0f }; + // Bedslinger mass model: cumulative printed mass at the previous layer, used to derive + // the current layer mass for the per-layer Y acceleration limit (curr_y_acceleration_limit). + double m_last_layer_accumulated_mass{ 0.0 }; // Always check gcode placeholders when building in debug mode. #if !defined(NDEBUG) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index c0a92780c4..22ed145ca5 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,21 @@ const std::string GCodeProcessor::VFlush_End_Tag = " VFLUSH_END"; //Orca: External device purge tag const std::string GCodeProcessor::External_Purge_Tag = " EXTERNAL_PURGE"; +// SKIPPABLE region tags. SKIPTYPE carries a trailing "" payload so it is matched with +// starts_with; START/END are whole-line tags. +const std::string GCodeProcessor::Skippable_Start_Tag = " SKIPPABLE_START"; +const std::string GCodeProcessor::Skippable_End_Tag = " SKIPPABLE_END"; +const std::string GCodeProcessor::Skippable_Type_Tag = " SKIPTYPE: "; + +// Usage-block builder markers. START/END machine-gcode markers are whole-line tags; the +// NOZZLE_CHANGE_* and CP_TOOLCHANGE_WIPE tags carry an OF/NF/ON/NN or CT/FL payload and are +// matched with starts_with. +const std::string GCodeProcessor::Machine_Start_GCode_End_Tag = " MACHINE_START_GCODE_END"; +const std::string GCodeProcessor::Machine_End_GCode_Start_Tag = " MACHINE_END_GCODE_START"; +const std::string GCodeProcessor::Nozzle_Change_Start_Tag = " NOZZLE_CHANGE_START"; +const std::string GCodeProcessor::Nozzle_Change_End_Tag = " NOZZLE_CHANGE_END"; +const std::string GCodeProcessor::Toolchange_Wipe_Tag = " CP_TOOLCHANGE_WIPE"; + const float GCodeProcessor::Wipe_Width = 0.05f; const float GCodeProcessor::Wipe_Height = 0.05f; @@ -469,6 +485,12 @@ void GCodeProcessor::TimeMachine::calculate_time(GCodeProcessorResult& result, P } time += double(block_time); + // Orca: accumulate per-SkipType time spent inside SKIPPABLE regions, folded into this single + // calculate_time write site. Fires fleet-wide (the shipping time_lapse_gcode template stamps + // blocks stTimelapse), but writes only skippable_part_time, which has no g-code-emitting + // reader until the pre-heat injector consumes it, so output is byte-identical. + if (block.skippable_type != SkipType::stNone) + result.skippable_part_time[block.skippable_type] += block.time(); result.moves[block.move_id].time[static_cast(mode)] = block_time; gcode_time.cache += block_time; //BBS @@ -960,6 +982,22 @@ public: } } + // Map a single first-pass (input) line id to its final output line id, using the same + // original->final table synchronize_moves() applies to the moves. The pre-heat injector's + // usage/skippable blocks are keyed on the pre-M73 input line id; this rebases them into the + // output-line-id space the moves and the second pass both use. Sentinel (unsigned)-1 and any + // id with no exact table entry are returned unchanged, matching synchronize_moves' exact-match rule. + unsigned int remap_gcode_id(unsigned int gcode_id) const + { + if (gcode_id == static_cast(-1)) + return gcode_id; + auto it = std::lower_bound(m_gcode_lines_map.begin(), m_gcode_lines_map.end(), static_cast(gcode_id), + [](const std::pair& e, size_t v) { return e.first < v; }); + if (it != m_gcode_lines_map.end() && it->first == static_cast(gcode_id)) + return static_cast(it->second); + return gcode_id; + } + size_t get_size() const { return m_size; } private: @@ -1392,6 +1430,11 @@ void GCodeProcessor::run_post_process() m_result.lines_ends.clear(); // m_result.lines_ends.emplace_back(std::vector()); + // Orca: freshly collect SKIPPABLE ranges each post-process pass. The ranges are stored on the + // member (rather than a local) so the injection pass can consume them, hence the clear here to + // avoid stale ranges on re-invocation. + m_skippable_blocks.clear(); + unsigned int line_id = 0; // Backtrace data for Tx gcode lines const ExportLines::Backtrace backtrace_T = { m_preheat_time, m_preheat_steps }; @@ -1399,6 +1442,161 @@ void GCodeProcessor::run_post_process() // to flush the backtrace cache accordingly float max_backtrace_time = 120.0f; + // First-pass usage-block builder. Reconstructs, from the emitted g-code, which filament/extruder + // is active over each output-line span so the pre-heat injector can locate idle-hotend windows. + // Gated behind m_enable_pre_heating: the byte-frozen fleet (X1/P1/A1/H2S, which never set the + // flag) runs none of this. It is pure data construction — it only fills m_filament_blocks / + // m_extruder_blocks / m_machine_*_gcode_*_line_id and never touches the exported g-code, so even + // the enable_pre_heating fleet stays byte-identical (nothing reads the blocks until the injection + // pass). In practice it also stays empty/degenerate today because no template/code yet emits the + // MACHINE_*_GCODE_* / NOZZLE_CHANGE_* / CP_TOOLCHANGE_WIPE markers it keys off. + m_filament_blocks.clear(); + m_extruder_blocks.clear(); + m_machine_start_gcode_end_line_id = (unsigned int) (-1); + m_machine_end_gcode_start_line_id = (unsigned int) (-1); + // the first use of an extruder emits no nozzle-change tag, so seed a dummy leading block + if (m_enable_pre_heating) + m_extruder_blocks.push_back(ExtruderPreHeating::ExtruderUsageBlcok()); + // Resolve the concrete layer-aware grouping: get_nozzle_id/get_extruder_id are not on the base + // interface. May be null on slicing paths that never populated it, in which case the builder + // degrades to empty blocks (every dereference below is nil-guarded). + auto layered_ngr = std::dynamic_pointer_cast(m_result.nozzle_group_result); + ExtruderPreHeating::ExtruderUsageBlcok temp_construct_block; // constructed, then pushed after init + + // Append a per-filament usage block at a filament change. + auto handle_filament_change = [&](int filament_id, int cur_line_id, int nozzle_id) { + // skip filament changes emitted inside the machine start / end gcode + if (m_machine_start_gcode_end_line_id == (unsigned int) (-1) && (unsigned int) (cur_line_id) < m_machine_start_gcode_end_line_id || + m_machine_end_gcode_start_line_id != (unsigned int) (-1) && (unsigned int) (cur_line_id) > m_machine_end_gcode_start_line_id) + return; + if (!m_filament_blocks.empty()) + m_filament_blocks.back().upper_gcode_id = cur_line_id; + if (nozzle_id == -1 && layered_ngr) + nozzle_id = layered_ngr->get_nozzle_id(filament_id, current_layer_id); + int extruder_id = 0; + if (layered_ngr) { + // Orca: nil-guard the optional nozzle lookup. + if (auto nozzle_info = layered_ngr->get_nozzle_from_id(nozzle_id)) + extruder_id = nozzle_info->extruder_id; + } + m_filament_blocks.emplace_back(filament_id, extruder_id, nozzle_id, cur_line_id, (unsigned int) (-1)); + }; + + // Parse a "; NOZZLE_CHANGE_* OF NF ON NN" line. The get_nozzle_from_id optional + // is nil-guarded here. + auto handle_nozzle_change_line = [&](const std::string& line, int& old_filament, int& next_filament, int& extruder_id, int gcode_id, int& old_nozzle_id, int& new_nozzle_id) -> bool { + std::regex re(R"(OF(\d+)\s+NF(\d+)\s+ON(\d+)\s+NN(\d+))"); + std::smatch match; + if (!std::regex_search(line, match, re)) + return false; + old_filament = std::stoi(match[1]); + next_filament = std::stoi(match[2]); + old_nozzle_id = std::stoi(match[3]); + new_nozzle_id = std::stoi(match[4]); + std::optional nozzle_info; + if (layered_ngr) + nozzle_info = layered_ngr->get_nozzle_from_id(new_nozzle_id); + extruder_id = nozzle_info ? nozzle_info->extruder_id : -1; + return true; + }; + + // Parse a "; CP_TOOLCHANGE_WIPE CT [FL]" line. + auto handle_toolchange_wipe_line = [](const std::string& line, bool& is_contact, bool& is_first_layer) -> bool { + std::regex re(R"(CT(\d)(?:\s+FL(\d))?)"); + std::smatch match; + if (!std::regex_search(line, match, re)) + return false; + is_contact = std::stoi(match[1]) != 0; + is_first_layer = match[2].matched ? std::stoi(match[2]) != 0 : false; + return true; + }; + + // Inspect one output line and update the usage-block state. Called only when m_enable_pre_heating; + // never modifies gcode_line. + auto build_usage_blocks = [&](const std::string& gcode_line, int line_id) { + using GLine = GCodeReader::GCodeLine; + // leading-whitespace count (GCodeReader::skip_whitespaces is private; is_whitespace == space|tab) + size_t skips = 0; + while (skips < gcode_line.size() && (gcode_line[skips] == ' ' || gcode_line[skips] == '\t')) + ++skips; + + // whole-line machine start / end gcode markers + if (gcode_line.size() > 1 && gcode_line.front() == ';') { + std::string_view tag(gcode_line); + while (!tag.empty() && (tag.back() == '\n' || tag.back() == '\r')) + tag.remove_suffix(1); + tag.remove_prefix(1); // strip leading ';' + if (tag == Machine_Start_GCode_End_Tag) { m_machine_start_gcode_end_line_id = line_id; return; } + if (tag == Machine_End_GCode_Start_Tag) { m_machine_end_gcode_start_line_id = line_id; return; } + } + + // filament-change commands: T, ;VT, M1020 S, each optionally " H" + if (GLine::cmd_starts_with(gcode_line, "T")) { + std::istringstream str(gcode_line.substr(skips + 1)); // skip whitespace and 'T' + int fid; + str >> fid; + if (!str.fail() && 0 <= fid && fid < 255) { + int nozzle_id = -1; char param; + while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in T command: " << gcode_line; break; } } + handle_filament_change(fid, line_id, nozzle_id); + } + return; + } + if (GLine::cmd_starts_with(gcode_line, ";VT")) { + std::istringstream str(gcode_line.substr(skips + 3)); // skip whitespace and ";VT" + int fid; + str >> fid; + if (!str.fail() && 0 <= fid && fid < 255) { + int nozzle_id = -1; char param; + while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in VT command: " << gcode_line; break; } } + handle_filament_change(fid, line_id, nozzle_id); + } + return; + } + if (GLine::cmd_starts_with(gcode_line, "M1020")) { + size_t s_pos = gcode_line.find('S'); + if (s_pos != std::string::npos) { + std::istringstream str(gcode_line.substr(s_pos + 1)); + int fid; + str >> fid; + if (!str.fail() && 0 <= fid && fid < 255) { + int nozzle_id = -1; char param; + while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in M1020 command: " << gcode_line; break; } } + handle_filament_change(fid, line_id, nozzle_id); + } + } + return; + } + + // extruder usage blocks are delimited by the NOZZLE_CHANGE_START/END markers + if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Nozzle_Change_Start_Tag).c_str())) { + int prev_filament{-1}, next_filament{-1}, extruder_id{-1}, prev_nozzle_id{-1}, next_nozzle_id{-1}; + handle_nozzle_change_line(gcode_line, prev_filament, next_filament, extruder_id, line_id, prev_nozzle_id, next_nozzle_id); + if (!m_extruder_blocks.empty()) + m_extruder_blocks.back().initialize_step_2(line_id); + return; + } + if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Nozzle_Change_End_Tag).c_str())) { + int prev_filament{-1}, next_filament{-1}, extruder_id{-1}, prev_nozzle_id{-1}, next_nozzle_id{-1}; + handle_nozzle_change_line(gcode_line, prev_filament, next_filament, extruder_id, line_id, prev_nozzle_id, next_nozzle_id); + if (!m_extruder_blocks.empty()) + m_extruder_blocks.back().initialize_step_3(line_id, prev_filament, line_id, prev_nozzle_id); + temp_construct_block.initialize_step_1(extruder_id, line_id, next_filament, next_nozzle_id); + m_extruder_blocks.emplace_back(temp_construct_block); + temp_construct_block.reset(); + return; + } + // CP_TOOLCHANGE_WIPE records whether the upcoming tower wipe contacts the model / is on the + // first layer, which later suppresses pre-cooling before the tower. + if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Toolchange_Wipe_Tag).c_str())) { + bool is_contact = false, is_first_layer = false; + handle_toolchange_wipe_line(gcode_line, is_contact, is_first_layer); + if (!m_extruder_blocks.empty()) + m_extruder_blocks.back().ignore_cooling_before_tower = is_contact || is_first_layer; + return; + } + }; + { // Read the input stream 64kB at a time, extract lines and process them. std::vector buffer(65536 * 10, 0); @@ -1444,7 +1642,22 @@ void GCodeProcessor::run_post_process() tag_line.remove_prefix(1); if (tag_line == reserved_tag(ETags::Layer_Change)) ++current_layer_id; + // Collect [start,end] output-line-id ranges of each SKIPPABLE region for the + // pre-heat injector. The `!empty()` guard on END avoids dereferencing .back() + // on an empty vector. The shipping time_lapse_gcode template emits SKIPPABLE_* + // fleet-wide, so this records ~100 ranges per timelapse-on slice; output stays + // byte-identical because it only records line-ids (comment lines pass through + // unmodified) and nothing reads the ranges until the injection pass. + else if (tag_line == Skippable_Start_Tag) + m_skippable_blocks.emplace_back(line_id, 0); + else if (tag_line == Skippable_End_Tag && !m_skippable_blocks.empty()) + m_skippable_blocks.back().second = line_id; } + // Build the first-pass usage blocks off the raw line (before any placeholder + // replacement/clear below). Gated on m_enable_pre_heating so the byte-frozen fleet + // executes nothing; pure data construction, so the output is untouched regardless. + if (m_enable_pre_heating) + build_usage_blocks(gcode_line, line_id); // replace placeholder lines bool processed = process_placeholders(gcode_line); if (processed) @@ -1488,6 +1701,39 @@ void GCodeProcessor::run_post_process() } } + // Close out the usage blocks after the stream. The trailing filament block runs to the end-gcode + // start; the seeded first extruder block gets its start filled from the first filament, and the + // open last extruder block is completed with the trailing filament/nozzle. Gated + pure data — + // no effect on the exported g-code. + if (m_enable_pre_heating) { + if (!m_filament_blocks.empty()) + m_filament_blocks.back().upper_gcode_id = m_machine_end_gcode_start_line_id; + + if (!m_extruder_blocks.empty()) { + int first_filament = 0; + int last_filament = 0; + if (!m_filament_blocks.empty()) { + first_filament = m_filament_blocks.front().filament_id; + last_filament = m_filament_blocks.back().filament_id; + } + { + int extruder_id = -1; + std::optional nozzle_info; + if (layered_ngr) + nozzle_info = layered_ngr->get_first_nozzle_for_filament(first_filament); + if (nozzle_info) + extruder_id = nozzle_info->extruder_id; + int start_nozzle_id = nozzle_info ? nozzle_info->group_id : -1; + m_extruder_blocks.front().initialize_step_1(extruder_id, m_machine_start_gcode_end_line_id, first_filament, start_nozzle_id); + } + m_extruder_blocks.back().initialize_step_2(m_machine_end_gcode_start_line_id); + int last_nozzle_id = -1; + if (!m_filament_blocks.empty()) + last_nozzle_id = m_filament_blocks.back().nozzle_id; + m_extruder_blocks.back().initialize_step_3(m_machine_end_gcode_start_line_id, last_filament, m_machine_end_gcode_start_line_id, last_nozzle_id); + } + } + export_line.flush(out, m_result, out_path); out.close(); @@ -1496,11 +1742,628 @@ void GCodeProcessor::run_post_process() const std::string result_filename = m_result.filename; export_line.synchronize_moves(m_result); + // Rebase the first-pass usage/skippable blocks + the machine start/end gcode line ids from the + // pre-M73 input-line-id space into the final output-line-id space, so they share one coordinate + // system with the moves (whose gcode_ids synchronize_moves() just rebased) and with the + // second-pass line_id. This is the block-side counterpart to synchronize_moves, which does the + // same rebasing for the moves. Gated on m_enable_pre_heating so the byte-frozen fleet skips it + // entirely; on the flag-true fleet it writes only the (inert) block members, so the emitted + // g-code is unaffected either way. + if (m_enable_pre_heating) { + auto remap = [&export_line](unsigned int& id) { id = export_line.remap_gcode_id(id); }; + for (auto& b : m_filament_blocks) { + remap(b.lower_gcode_id); + remap(b.upper_gcode_id); + } + for (auto& b : m_extruder_blocks) { + remap(b.start_id); + remap(b.end_id); + remap(b.post_extrusion_start_id); + remap(b.post_extrusion_end_id); + } + for (auto& b : m_skippable_blocks) { + remap(b.first); + remap(b.second); + } + remap(m_machine_start_gcode_end_line_id); + remap(m_machine_end_gcode_start_line_id); + } + if (rename_file(out_path, result_filename)) throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + result_filename + '\n' + "Is " + out_path + " locked?" + '\n'); } +// Additive second file-rewrite pass for the pre-heat/pre-cool injector. The single-pass +// run_post_process (M73 / filament stats / ActualSpeedMove / Backtrace / machine_tool_change_time / +// is_final EOF hardening) is left untouched; this pass runs AFTER it, reads the finished g-code back, +// and splices the injector's InsertedLinesMap (keyed on the final output line id) after the matching +// lines, then re-shifts every move's gcode_id by the inserted-line count before it (see +// handle_offsets_of_second_process). It runs only when m_enable_pre_heating — the byte-frozen fleet +// (X1/P1/A1/H2S) never sets the flag, so it never enters this pass. The PreCoolingInjector (below) +// fills the map; when the injector produces no lines (no idle windows / no usage blocks) the map is +// empty and the pass is a byte-for-byte identity rewrite of the finished file. +void GCodeProcessor::run_second_pass_injection() +{ + // The ordered map of M632/M400/M104/M633 lines to splice into the finished g-code, keyed on the + // final output line id. Populated by the PreCoolingInjector below. If the injector produces + // nothing (no idle windows / no usage blocks), the map stays empty and the rewrite below is a + // byte-for-byte identity pass. + TimeProcessor::InsertedLinesMap inserted_operation_lines; + + // The enable_pre_heating orchestration block. Build the injector from the reconciled first-pass + // usage/skippable blocks (now in the final output-line-id space, sharing one coordinate with the + // moves' synchronized gcode_ids) and the per-move time substrate, then have it populate + // inserted_operation_lines. Runs under the same m_enable_pre_heating gate finalize() already + // applied, so the byte-frozen fleet (X1/P1/A1/H2S) never reaches here. + { + // Pick the active time mode (Normal/Stealth) whose move.time[] the injector reads. + int valid_machine_id = 0; + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + if (m_time_processor.machines[i].enabled) { + valid_machine_id = (int) i; + break; + } + } + // Reach the concrete layer-aware grouping (get_nozzle_from_id / is_support_dynamic_nozzle_map + // are not on the base interface). Orca: nil-guard it — on a slicing path that never populated + // the grouping, skip injection → empty map → identity rewrite. The shared_ptr local keeps the + // object alive for the injector's const ref. + auto layered_ngr = std::dynamic_pointer_cast(m_result.nozzle_group_result); + if (layered_ngr) { + constexpr float inject_time_threshold = 0.f; // threshold hardcoded to 0 + // Orca: nozzle temps are stored as float (ExtruderTemps) but the injector signature takes + // std::vector, so convert to int locals that outlive the injector (they are + // int-valued floats — see apply_config). + std::vector filament_nozzle_temps(m_filament_nozzle_temp.begin(), m_filament_nozzle_temp.end()); + std::vector filament_nozzle_temps_initial(m_filament_nozzle_temp_first_layer.begin(), m_filament_nozzle_temp_first_layer.end()); + // filament_max_temperature_drop_when_ec is inert (default {0}, never read by the injector); + // pass the same inert default (the config is registered but unwired). + const std::vector filament_max_temperature_drop_when_ec{ 0.f }; + + // Orca: MoveVertex.time[mode] stores the per-move DURATION (calculate_time: `= block_time`), + // but the injector's algorithm reads move.time[] as CUMULATIVE print time (idle-window gap = + // upper.time - prev(lower).time; heating_start back-solve = upper.time - delta/rate). Build a + // cumulative view of the active mode IN PLACE (prefix-sum in gcode-id/move order — moves are + // sorted by gcode_id), run the injector, then RESTORE the per-move durations so every + // downstream consumer (and the byte output) is unperturbed. Only the single active-mode + // column is touched. + std::vector saved_time; + saved_time.reserve(m_result.moves.size()); + { + float acc = 0.f; + for (auto& mv : m_result.moves) { + saved_time.push_back(mv.time[valid_machine_id]); + acc += mv.time[valid_machine_id]; + mv.time[valid_machine_id] = acc; + } + } + + PreCoolingInjector injector( + m_result.moves, + m_filament_types, + *layered_ngr, + filament_nozzle_temps, + filament_nozzle_temps_initial, + m_physical_extruder_map, + valid_machine_id, + inject_time_threshold, + m_handle_hotend_as_extruder, + m_has_filament_switcher, + m_filament_pre_cooling_temp, + m_hotend_cooling_rate, + m_hotend_heating_rate, + m_skippable_blocks, + m_extruder_max_nozzle_count, + m_filament_preheat_temperature_delta, + filament_max_temperature_drop_when_ec, + m_machine_start_gcode_end_line_id, + m_machine_end_gcode_start_line_id, + m_result.extruder_types, + m_nozzle_diameter); + injector.build_extruder_free_blocks(m_filament_blocks, m_extruder_blocks); + injector.process_pre_cooling_and_heating(inserted_operation_lines); + + // Restore the per-move durations (leave the moves exactly as run_post_process produced them). + for (size_t i = 0; i < m_result.moves.size(); ++i) + m_result.moves[i].time[valid_machine_id] = saved_time[i]; + } + } + + FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") }; + if (in.f == nullptr) + throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nCannot open file for reading.\n")); + + const std::string out_path = m_result.filename + ".preheat"; + FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") }; + if (out.f == nullptr) + throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nCannot open file for writing.\n")); + + // The rewrite may shift byte positions (once the injector inserts lines), so rebuild lines_ends from scratch. + // With an empty map the scanned '\n' offsets reproduce the current lines_ends exactly. + m_result.lines_ends.clear(); + size_t out_file_pos = 0; + + auto write_out = [&out, &out_path, this, &out_file_pos](std::string& str) { + if (str.empty()) + return; + fwrite((const void*) str.c_str(), 1, str.length(), out.f); + if (ferror(out.f)) { + out.close(); + boost::nowide::remove(out_path.c_str()); + throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nIs the disk full?\n")); + } + for (size_t i = 0; i < str.size(); ++i) { + if (str[i] == '\n') + m_result.lines_ends.emplace_back(out_file_pos + i + 1); + } + out_file_pos += str.size(); + str.clear(); + }; + + // Orca: read/split lines with EOL-preserving semantics (keep the original \r and \n bytes, and + // synthesize no trailing newline). This is required for the empty-map identity: normalizing every + // line ending to "\n" would not be byte-identical if the finished file used \r\n or lacked a + // final newline. + std::string gcode_line; + std::string export_buffer; + unsigned int line_id = 0; + auto op_it = inserted_operation_lines.begin(); + std::vector buffer(65536 * 10, 0); + for (;;) { + size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f); + if (::ferror(in.f)) + throw Slic3r::RuntimeError(std::string("GCode processor pre-heat injection pass failed.\nError while reading from file.\n")); + bool eof = cnt_read == 0; + auto it = buffer.begin(); + auto it_bufend = buffer.begin() + cnt_read; + while (it != it_bufend || (eof && !gcode_line.empty())) { + bool eol = false; + auto it_end = it; + for (; it_end != it_bufend && !(eol = *it_end == '\r' || *it_end == '\n'); ++it_end); + eol |= eof && it_end == it_bufend; + gcode_line.insert(gcode_line.end(), it, it_end); + it = it_end; + if (it != it_bufend && *it == '\r') + gcode_line += *it++; + if (it != it_bufend && *it == '\n') + gcode_line += *it++; + if (eol) { + ++line_id; + // Splice any injector lines registered at this output line id. They are appended to the + // end of the current line's text (which already carries its EOL), so they land AFTER + // this line. PlaceholderReplace / TimePredict / ExtruderChangePredict are handled in the + // first pass and skipped here. + if (op_it != inserted_operation_lines.end() && line_id == op_it->first) { + for (const auto& elem : op_it->second) { + switch (elem.second) { + case TimeProcessor::InsertLineType::PreCooling: + case TimeProcessor::InsertLineType::PreHeating: + case TimeProcessor::InsertLineType::FilamentChangePredict: + gcode_line += elem.first; + break; + default: + break; + } + } + ++op_it; + } + export_buffer += gcode_line; + gcode_line.clear(); + if (export_buffer.length() >= 65536) + write_out(export_buffer); + } + } + if (eof) + break; + } + write_out(export_buffer); + + out.close(); + in.close(); + + // Re-shift the moves by the inserted-line counts (no-op with an empty map). + handle_offsets_of_second_process(inserted_operation_lines); + + if (rename_file(out_path, m_result.filename)) + throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' + + "Is " + out_path + " locked?" + '\n'); +} + +// Every move whose gcode_id sits at or after an inserted line is pushed down by the running count of +// injector lines inserted before it. +void GCodeProcessor::handle_offsets_of_second_process(const TimeProcessor::InsertedLinesMap& inserted_operation_lines) +{ + int total_offset = 0; + auto iter = inserted_operation_lines.begin(); + for (GCodeProcessorResult::MoveVertex& move : m_result.moves) { + while (iter != inserted_operation_lines.end() && iter->first < move.gcode_id) { + total_offset += static_cast(iter->second.size()); + ++iter; + } + move.gcode_id += total_offset; + } +} + +// The pre-cool / pre-heat injection engine. See the class comment in the header. The methods populate +// a TimeProcessor::InsertedLinesMap (keyed on the final output line id) that run_second_pass_injection +// splices into the finished g-code. + +// Group the free-blocks per extruder; for each, always pre-cool, and pre-heat all-but-the-last; derive +// curr/target temps from the filament nozzle temps +/- filament_preheat_temperature_delta; apply the +// X2D mixed-extruder-type workaround. +void GCodeProcessor::PreCoolingInjector::process_pre_cooling_and_heating(TimeProcessor::InsertedLinesMap& inserted_operation_lines) +{ + bool is_multiple_nozzle = std::any_of(extruder_max_nozzle_count.begin(), extruder_max_nozzle_count.end(), [](auto& elem) { return elem > 1; }); + (void) is_multiple_nozzle; // computed but currently unused here + auto get_nozzle_temp = [this](int filament_id, bool is_first_layer, bool from_or_to, bool consider_preheat_temperature_delta) { + if (filament_id == -1) + return from_or_to ? 140 : 0; // default temp + double temp = (is_first_layer ? filament_nozzle_temps_initial_layer[filament_id] : filament_nozzle_temps[filament_id]); + if (consider_preheat_temperature_delta) + return (int) (temp - filament_preheat_temperature_delta[filament_id]); + else + return (int) (temp); + }; + + // Temporary workaround for X2D: when extruder types are mixed (e.g. DirectDrive + Bowden), + // limit pre-heating target to avoid overshooting on the slower-responding extruder. + bool has_mixed_extruder_types = extruder_types.size() > 1 && + std::adjacent_find(extruder_types.begin(), extruder_types.end(), std::not_equal_to<>()) != extruder_types.end(); + // Temporary workaround for X2D: Use the first nozzle diameter to determine the temp offset: 40 for large nozzles (0.6/0.8), 20 for others + float first_nozzle_dia = nozzle_diameter.empty() ? 0.4 : nozzle_diameter.front(); + float switcher_temp_offset = (first_nozzle_dia >= 0.6 - EPSILON) ? 40.f : 20.f; + + std::map> per_extruder_free_blocks; + + for (auto& block : m_extruder_free_blocks) + per_extruder_free_blocks[block.extruder_id].emplace_back(block); + + for (auto& elem : per_extruder_free_blocks) { + auto& extruder_free_blcoks = elem.second; + for (auto iter = extruder_free_blcoks.begin(); iter != extruder_free_blcoks.end(); ++iter) { + bool is_end = std::next(iter) == extruder_free_blcoks.end(); + bool apply_pre_cooling = true; + bool apply_pre_heating = is_end ? false : true; + float curr_temp = get_nozzle_temp(iter->last_filament_id, false, true, false); + float target_temp = get_nozzle_temp(iter->next_filament_id, false, false, !iter->ignore_cooling_before_tower); + // X2D temporary workaround: only apply temp offset when extruder types are mixed + if (has_filament_switcher && has_mixed_extruder_types && apply_pre_heating) { + float print_temp = get_nozzle_temp(iter->next_filament_id, false, false, false); + target_temp = std::min(target_temp, print_temp - switcher_temp_offset); + } + inject_cooling_heating_command(inserted_operation_lines, *iter, curr_temp, target_temp, apply_pre_cooling, apply_pre_heating); + } + } +} + +// A single extruder-usage block (or none) means the print stays on one extruder, so the idle windows +// are between per-filament usages; otherwise the print switches extruders and the idle windows are +// between per-extruder usages. +void GCodeProcessor::PreCoolingInjector::build_extruder_free_blocks(const std::vector& filament_usage_blocks, const std::vector& extruder_usage_blocks) +{ + if (extruder_usage_blocks.size() <= 1) + build_by_filament_blocks(filament_usage_blocks); + else + build_by_extruder_blocks(extruder_usage_blocks); +} + +// The core injector. Measures the idle-window duration from move.time[valid_machine_id], bails if it is +// below the threshold, and emits pre-cool M104 at the window start and pre-heat M104 (relocated out of +// SKIPPABLE blocks) at the back-solved heating-start move. +void GCodeProcessor::PreCoolingInjector::inject_cooling_heating_command(TimeProcessor::InsertedLinesMap& inserted_operation_lines, const ExtruderFreeBlock& block, float curr_temp, float target_temp, bool pre_cooling, bool pre_heating) +{ + auto get_valid_extruder_id = [&](int last_nozzle_id) { + auto nozzle_opt = nozzle_group_result.get_nozzle_from_id(last_nozzle_id); + return nozzle_opt ? nozzle_opt->extruder_id : 0; + }; + + auto is_pre_cooling_valid = [&nozzle_temps = this->filament_nozzle_temps, &pre_cooling_temps = this->filament_pre_cooling_temps](int idx) -> bool { + if (idx < 0) + return false; + return pre_cooling_temps[idx] > 0 && pre_cooling_temps[idx] < nozzle_temps[idx]; + }; + + auto get_partial_free_cooling_thres = [&](int idx) -> float { + if (idx < 0) + return 30.f; + float temp_in_tower = filament_nozzle_temps[idx]; + return temp_in_tower - (float) (filament_pre_cooling_temps[idx]); + }; + + auto gcode_move_comp = [](const GCodeProcessorResult::MoveVertex& a, unsigned int gcode_id) { + return a.gcode_id < gcode_id; + }; + + auto find_skip_block_end = [&skippable_blocks = this->skippable_blocks](unsigned int gcode_id) -> unsigned int { + auto it = std::upper_bound( + skippable_blocks.begin(), skippable_blocks.end(), gcode_id, + [](unsigned int id, const std::pair& block) { return id < block.first; }); + if (it != skippable_blocks.begin()) { + auto candidate = std::prev(it); + if (gcode_id >= candidate->first && gcode_id <= candidate->second) + return candidate->second; + } + return 0; + }; + + auto find_skip_block_start = [&skippable_blocks = this->skippable_blocks](unsigned int gcode_id) -> unsigned int { + auto it = std::upper_bound( + skippable_blocks.begin(), skippable_blocks.end(), gcode_id, + [](unsigned int id, const std::pair& block) { return id < block.first; }); + if (it != skippable_blocks.begin()) { + auto candidate = std::prev(it); + if (gcode_id >= candidate->first && gcode_id <= candidate->second) + return candidate->first; + } + return 0; + }; + + auto adjust_iter = [&](std::vector::const_iterator iter, + const std::vector::const_iterator& begin, + const std::vector::const_iterator& end, + bool forward) -> std::vector::const_iterator { + if (forward) { + while (iter != end) { + unsigned current_id = iter->gcode_id; + unsigned skip_block_end = find_skip_block_end(current_id); + if (skip_block_end == 0) + break; + iter = std::lower_bound(iter, end, skip_block_end + 1, gcode_move_comp); + } + } else { + while (iter != begin) { + unsigned current_id = iter->gcode_id; + unsigned skip_block_start = find_skip_block_start(current_id); + if (skip_block_start == 0) + break; + auto new_iter = std::lower_bound(begin, iter, skip_block_start, gcode_move_comp); + if (new_iter == begin) + break; + iter = std::prev(new_iter); + } + } + return iter; + }; + + if (!pre_cooling && !pre_heating && block.free_upper_gcode_id <= block.free_lower_gcode_id) + return; + + auto move_iter_lower = std::lower_bound(moves.begin(), moves.end(), block.free_lower_gcode_id, gcode_move_comp); + auto move_iter_upper = std::lower_bound(moves.begin(), moves.end(), block.free_upper_gcode_id, gcode_move_comp); // closed iter + + if (move_iter_lower == moves.end() || move_iter_upper == moves.begin()) + return; + --move_iter_upper; + float complete_free_time_gap = 0; // time of complete free + if (move_iter_lower == moves.begin()) + complete_free_time_gap = move_iter_upper->time[valid_machine_id]; + else + complete_free_time_gap = move_iter_upper->time[valid_machine_id] - std::prev(move_iter_lower)->time[valid_machine_id]; + + auto partial_free_move_lower = std::lower_bound(moves.begin(), moves.end(), block.partial_free_lower_id, gcode_move_comp); + auto partial_free_move_upper = std::lower_bound(moves.begin(), moves.end(), block.partial_free_upper_id, gcode_move_comp); // closed iter + if (partial_free_move_lower == moves.end() || partial_free_move_upper == moves.begin()) + return; + --partial_free_move_upper; + float partial_free_time_gap = 0; // time of partial free + if (partial_free_move_lower == moves.begin()) + partial_free_time_gap = partial_free_move_upper->time[valid_machine_id]; + else + partial_free_time_gap = partial_free_move_upper->time[valid_machine_id] - std::prev(partial_free_move_lower)->time[valid_machine_id]; + + if (move_iter_lower >= move_iter_upper) + return; + + bool apply_cooling_when_partial_free = is_pre_cooling_valid(block.last_filament_id) && pre_cooling; + + if (apply_cooling_when_partial_free && partial_free_time_gap + complete_free_time_gap < inject_time_threshold) + return; + + if (!apply_cooling_when_partial_free && complete_free_time_gap < inject_time_threshold) + return; + + int extruder_id = get_valid_extruder_id(block.last_nozzle_id); + float ext_heating_rate = heating_rate[extruder_id]; + float ext_cooling_rate = cooling_rate[extruder_id]; + + auto add_M104_lines = [&](int gcode_id, int target_extruder, int target_temp, int target_filament, bool skippable, int next_filament_idx, int next_nozzle_id, TimeProcessor::InsertLineType type, const std::string& comment = std::string()) { + auto format_line_M104 = [&](int target_extruder, int target_temp, int target_filament, bool skippable, int next_filament_idx, int next_nozzle_id, const std::string& comment = std::string()) -> std::vector { + std::vector buffer; + if (skippable) { + const bool support_dynamic_nozzle_map = this->nozzle_group_result.is_support_dynamic_nozzle_map(); + std::string m632_line = "M632 S" + std::to_string(next_filament_idx); + if (support_dynamic_nozzle_map) + m632_line += " H" + std::to_string(next_nozzle_id); + if (extruder_max_nozzle_count[target_extruder] > 1) + m632_line += " N R"; + m632_line += " W\n"; + buffer.emplace_back(std::move(m632_line)); + } + buffer.emplace_back("M400\n"); + std::string M104_line = "M104"; + if (handle_hotend_as_extruder) { + M104_line += (" I" + std::to_string(target_filament == -1 ? next_filament_idx : target_filament)); + } else if (target_extruder != -1) { + M104_line += (" T" + std::to_string(physical_extruder_map[target_extruder])); + } + + M104_line += " S" + std::to_string(target_temp); + M104_line += " N0"; // N0 means the gcode is generated by slicer + + if (!comment.empty()) + M104_line += " ;" + comment; + M104_line += '\n'; + + buffer.emplace_back(M104_line); + + if (skippable) + buffer.emplace_back("M633\n"); + + return buffer; + }; + + std::vector line_buf = format_line_M104(target_extruder, target_temp, target_filament, skippable, next_filament_idx, next_nozzle_id, comment); + for (auto& line : line_buf) + inserted_operation_lines[gcode_id].emplace_back(line, type); + }; + + constexpr float room_temperature = 25.f; + + if (apply_cooling_when_partial_free) { + float max_cooling_temp = std::min(curr_temp, std::min(get_partial_free_cooling_thres(block.last_filament_id), partial_free_time_gap * ext_cooling_rate)); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": partial cooling for %1% %2%") % max_cooling_temp % curr_temp; + curr_temp = std::max(room_temperature, curr_temp - max_cooling_temp); // set the temperature after doing cooling when post-extruding + add_M104_lines(block.partial_free_lower_id, extruder_id, curr_temp, block.last_filament_id, false, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreCooling, "Multi extruder pre cooling in post extrusion"); + } + + if (pre_cooling && !pre_heating) { + // only perform cooling + if (target_temp >= curr_temp) + return; + int clamped_target = std::max((int) room_temperature, (int) target_temp); + add_M104_lines(block.free_lower_gcode_id, extruder_id, clamped_target, block.last_filament_id, false, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreCooling, "Multi extruder pre cooling"); + return; + } + if (!pre_cooling && pre_heating) { + // only perform heating + if (target_temp <= curr_temp) + return; + float heating_start_time = move_iter_upper->time[valid_machine_id] - (target_temp - curr_temp) / ext_heating_rate; + auto heating_move_iter = std::upper_bound(move_iter_lower, move_iter_upper + 1, heating_start_time, [valid_machine_id = this->valid_machine_id](float time, const GCodeProcessorResult::MoveVertex& a) { return time < a.time[valid_machine_id]; }); + if (heating_move_iter == move_iter_lower) { + add_M104_lines(block.free_lower_gcode_id, extruder_id, target_temp, block.next_filament_id, true, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreHeating, "Multi extruder pre heating"); + } else { + --heating_move_iter; + heating_move_iter = adjust_iter(heating_move_iter, move_iter_lower, move_iter_upper, false); + add_M104_lines(heating_move_iter->gcode_id, extruder_id, target_temp, block.next_filament_id, true, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreHeating, "Multi extruder pre heating"); + } + return; + } + // perform cooling first and then perform heating + float mid_temp = std::max(room_temperature, (curr_temp * ext_heating_rate + target_temp * ext_cooling_rate - complete_free_time_gap * ext_cooling_rate * ext_heating_rate) / (ext_cooling_rate + ext_heating_rate)); + float heating_temp = target_temp - mid_temp; + float heating_start_time = move_iter_upper->time[valid_machine_id] - heating_temp / ext_heating_rate; + auto heating_move_iter = std::upper_bound(move_iter_lower, move_iter_upper + 1, heating_start_time, [valid_machine_id = this->valid_machine_id](float time, const GCodeProcessorResult::MoveVertex& a) { return time < a.time[valid_machine_id]; }); + if (heating_move_iter == move_iter_lower) + return; + --heating_move_iter; + heating_move_iter = adjust_iter(heating_move_iter, move_iter_lower, move_iter_upper, false); + + // get the insert pos of heat cmd and recalculate time gap and delta temp + float real_cooling_time = heating_move_iter->time[valid_machine_id] - move_iter_lower->time[valid_machine_id]; + int real_delta_temp = std::min((int) (real_cooling_time * ext_cooling_rate), (int) curr_temp); + if (real_delta_temp == 0) + return; + int cooling_temp = std::max((int) room_temperature, (int) curr_temp - real_delta_temp); + add_M104_lines(block.free_lower_gcode_id, extruder_id, cooling_temp, block.last_filament_id, false, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreCooling, "Multi extruder pre cooling"); + add_M104_lines(heating_move_iter->gcode_id, extruder_id, target_temp, block.next_filament_id, true, block.next_filament_id, block.next_nozzle_id, TimeProcessor::InsertLineType::PreHeating, "Multi extruder pre heating"); +} + +// Single-extruder / A2L path. Idle windows are the gaps between consecutive per-filament usages on the +// same extruder; ignore_cooling_before_tower is forced true (pre-cooling before the tower is handled by +// the wipe-tower template, not the injector). +void GCodeProcessor::PreCoolingInjector::build_by_filament_blocks(const std::vector& filament_usage_blocks_) +{ + m_extruder_free_blocks.clear(); + + std::map> per_extruder_usage_blocks; + for (auto& block : filament_usage_blocks_) { + per_extruder_usage_blocks[block.extruder_id].emplace_back(block); + } + ExtruderPreHeating::FilamentUsageBlock start_filament_block(-1, -1, -1, 0, machine_start_gcode_end_id); + ExtruderPreHeating::FilamentUsageBlock end_filament_block(-1, -1, -1, machine_end_gcode_start_id, std::numeric_limits::max()); + + for (auto& elem : per_extruder_usage_blocks) { + auto& blocks = elem.second; + blocks.insert(blocks.begin(), start_filament_block); + blocks.emplace_back(end_filament_block); + } + + for (auto& elem : per_extruder_usage_blocks) { + size_t extruder_id = elem.first; + const auto& filament_blocks = elem.second; + + for (auto iter = filament_blocks.begin(); iter < filament_blocks.end(); ++iter) { + auto niter = std::next(iter); + if (niter == filament_blocks.end()) + break; + ExtruderFreeBlock block; + block.free_lower_gcode_id = iter->upper_gcode_id; + block.last_filament_id = iter->filament_id; + block.last_nozzle_id = iter->nozzle_id; + block.free_upper_gcode_id = niter->lower_gcode_id; + block.next_filament_id = niter->filament_id; + block.next_nozzle_id = niter->nozzle_id; + if (block.last_nozzle_id == -1) + block.last_nozzle_id = block.next_nozzle_id; + block.extruder_id = extruder_id; + block.partial_free_lower_id = block.free_lower_gcode_id; + block.partial_free_upper_id = block.free_lower_gcode_id; + m_extruder_free_blocks.emplace_back(block); + } + } + std::for_each(m_extruder_free_blocks.begin(), m_extruder_free_blocks.end(), [](ExtruderFreeBlock& block) { block.ignore_cooling_before_tower = true; }); + sort(m_extruder_free_blocks.begin(), m_extruder_free_blocks.end(), [](const auto& a, const auto& b) { + return a.free_lower_gcode_id < b.free_lower_gcode_id || (a.free_lower_gcode_id == b.free_lower_gcode_id && a.free_upper_gcode_id < b.free_upper_gcode_id); + }); +} + +// Multi-extruder path. Idle windows are the gaps between consecutive per-extruder usages, with +// post-extrusion partial-free sub-ranges (the tower ramming region). +void GCodeProcessor::PreCoolingInjector::build_by_extruder_blocks(const std::vector& extruder_usage_blocks_) +{ + m_extruder_free_blocks.clear(); + std::map> per_extruder_usage_blocks; + for (auto& block : extruder_usage_blocks_) + per_extruder_usage_blocks[block.extruder_id].emplace_back(block); + + for (auto& elem : per_extruder_usage_blocks) { + size_t extruder_id = elem.first; + auto& blocks = elem.second; + ExtruderPreHeating::ExtruderUsageBlcok start_filament_block; + start_filament_block.initialize_step_1(extruder_id, 0, -1, -1); + start_filament_block.initialize_step_2(machine_start_gcode_end_id); + start_filament_block.initialize_step_3(machine_start_gcode_end_id, -1, machine_start_gcode_end_id, -1); + + ExtruderPreHeating::ExtruderUsageBlcok end_filament_block; + end_filament_block.initialize_step_1(extruder_id, machine_end_gcode_start_id, -1, -1); + end_filament_block.initialize_step_2(std::numeric_limits::max()); + end_filament_block.initialize_step_3(std::numeric_limits::max(), -1, std::numeric_limits::max(), -1); + + blocks.insert(blocks.begin(), start_filament_block); + blocks.emplace_back(end_filament_block); + } + + for (auto& elem : per_extruder_usage_blocks) { + size_t extruder_id = elem.first; + const auto& extruder_usage_blocks = elem.second; + for (auto iter = extruder_usage_blocks.begin(); iter != extruder_usage_blocks.end(); ++iter) { + auto niter = std::next(iter); + if (niter == extruder_usage_blocks.end()) + break; + ExtruderFreeBlock block; + block.free_lower_gcode_id = iter->end_id; + block.last_filament_id = iter->end_filament; + block.last_nozzle_id = iter->end_nozzle_id; + block.free_upper_gcode_id = niter->start_id; + block.next_filament_id = niter->start_filament; + block.next_nozzle_id = niter->start_nozzle_id; + if (block.last_nozzle_id == -1) + block.last_nozzle_id = block.next_nozzle_id; + block.extruder_id = extruder_id; + block.partial_free_lower_id = iter->post_extrusion_start_id; + block.partial_free_upper_id = iter->post_extrusion_end_id; + block.ignore_cooling_before_tower = niter->ignore_cooling_before_tower; + m_extruder_free_blocks.emplace_back(block); + } + } + + sort(m_extruder_free_blocks.begin(), m_extruder_free_blocks.end(), [](const auto& a, const auto& b) { + return a.free_lower_gcode_id < b.free_lower_gcode_id || (a.free_lower_gcode_id == b.free_lower_gcode_id && a.free_upper_gcode_id < b.free_upper_gcode_id); + }); +} + void GCodeProcessor::UsedFilaments::reset() { color_change_cache = 0.0f; @@ -1681,6 +2544,12 @@ void GCodeProcessorResult::reset() { optimal_assignment.clear(); filament_change_count_map.clear(); warnings.clear(); + // keep the grouping-result field default-empty across resets. + nozzle_group_result.reset(); + // per-extruder hotend types (pre-heat injector input); repopulated by apply_config. + extruder_types.clear(); + // SKIPPABLE per-type accumulated time. + skippable_part_time.clear(); //BBS: add mutex for protection of gcode result unlock(); @@ -2056,6 +2925,26 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_nozzle_volume[idx] = config.nozzle_volume.values[idx]; m_physical_extruder_map = config.physical_extruder_map.values; + // Multi-nozzle context state, consumed by the multi-nozzle time model and pre-heat injector. + m_extruder_max_nozzle_count = config.extruder_max_nozzle_count.values; + + // Pre-heat / pre-cool injector estimator inputs. Gated on enable_pre_heating; the injector + // side-pass that consumes them runs later in run_second_pass_injection. has_filament_switcher is + // read defensively because it is registered as a ConfigDef only, not a static PrintConfig member. + m_filament_types.resize(filament_count); + for (size_t idx = 0; idx < filament_count; ++idx) + m_filament_types[idx] = config.filament_type.get_at(idx); + m_nozzle_diameter = config.nozzle_diameter.values; + m_hotend_cooling_rate = config.hotend_cooling_rate.values; + m_hotend_heating_rate = config.hotend_heating_rate.values; + m_filament_pre_cooling_temp = config.filament_pre_cooling_temperature.values; + m_filament_preheat_temperature_delta = config.filament_preheat_temperature_delta.values; + m_enable_pre_heating = config.enable_pre_heating.value; + if (const ConfigOptionBool* has_switcher = config.option("has_filament_switcher")) + m_has_filament_switcher = has_switcher->value; + m_result.extruder_types.resize(config.extruder_type.values.size()); + for (size_t idx = 0; idx < config.extruder_type.values.size(); ++idx) + m_result.extruder_types[idx] = static_cast(config.extruder_type.values[idx]); m_extruder_offsets.resize(filament_count); m_extruder_colors.resize(filament_count); @@ -2184,6 +3073,61 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_physical_extruder_map = physical_extruder_map->values; } + // Multi-nozzle context state, consumed by the multi-nozzle time model and pre-heat injector. + const ConfigOptionIntsNullable* extruder_max_nozzle_count = config.option("extruder_max_nozzle_count"); + if (extruder_max_nozzle_count != nullptr) { + m_extruder_max_nozzle_count = extruder_max_nozzle_count->values; + } + + // Pre-heat / pre-cool injector estimator inputs. Gated on enable_pre_heating; consumed later by the + // injector side-pass. handle_hotend_as_extruder is read only in this overload; nozzle_diameter uses + // the non-nullable ConfigOptionFloats type. + const ConfigOptionFloatsNullable* hotend_cooling_rate = config.option("hotend_cooling_rate"); + if (hotend_cooling_rate != nullptr) + m_hotend_cooling_rate = hotend_cooling_rate->values; + + const ConfigOptionFloatsNullable* hotend_heating_rate = config.option("hotend_heating_rate"); + if (hotend_heating_rate != nullptr) + m_hotend_heating_rate = hotend_heating_rate->values; + + const ConfigOptionIntsNullable* filament_pre_cooling_temperature = config.option("filament_pre_cooling_temperature"); + if (filament_pre_cooling_temperature != nullptr) + m_filament_pre_cooling_temp = filament_pre_cooling_temperature->values; + + const ConfigOptionFloatsNullable* filament_preheat_temperature_delta = config.option("filament_preheat_temperature_delta"); + if (filament_preheat_temperature_delta != nullptr) + m_filament_preheat_temperature_delta = filament_preheat_temperature_delta->values; + + const ConfigOptionBool* enable_pre_heating = config.option("enable_pre_heating"); + if (enable_pre_heating != nullptr) + m_enable_pre_heating = enable_pre_heating->value; + + const ConfigOptionBool* handle_hotend_as_extruder = config.option("handle_hotend_as_extruder"); + if (handle_hotend_as_extruder != nullptr) + m_handle_hotend_as_extruder = handle_hotend_as_extruder->value; + + const ConfigOptionBool* has_filament_switcher = config.option("has_filament_switcher"); + if (has_filament_switcher != nullptr) + m_has_filament_switcher = has_filament_switcher->value; + + const ConfigOptionFloats* nozzle_diameter = config.option("nozzle_diameter"); + if (nozzle_diameter != nullptr) + m_nozzle_diameter = nozzle_diameter->values; + + const ConfigOptionStrings* filament_type = config.option("filament_type"); + if (filament_type != nullptr) { + m_filament_types.resize(filament_type->size()); + for (size_t idx = 0; idx < filament_type->size(); ++idx) + m_filament_types[idx] = filament_type->get_at(idx); + } + + const ConfigOptionEnumsGeneric* extruder_type = config.option("extruder_type"); + if (extruder_type != nullptr) { + m_result.extruder_types.resize(extruder_type->values.size()); + for (size_t idx = 0; idx < extruder_type->values.size(); ++idx) + m_result.extruder_types[idx] = static_cast(extruder_type->values[idx]); + } + const ConfigOptionEnumsGenericNullable* nozzle_type = config.option("nozzle_type"); if (nozzle_type != nullptr) { m_result.nozzle_type.resize(nozzle_type->size()); @@ -2520,6 +3464,15 @@ void GCodeProcessor::reset() m_flushing = false; m_virtual_flushing = false; m_wipe_tower = false; + // reset SKIPPABLE tracking + the collected ranges (stored on the member; see run_post_process). + m_skippable = false; + m_skippable_type = SkipType::stNone; + m_skippable_blocks.clear(); + // reset the first-pass usage-block state (rebuilt each run_post_process). + m_filament_blocks.clear(); + m_extruder_blocks.clear(); + m_machine_start_gcode_end_line_id = (unsigned int) (-1); + m_machine_end_gcode_start_line_id = (unsigned int) (-1); m_remaining_volume = std::vector(MAXIMUM_EXTRUDER_NUMBER, 0.f); m_line_id = 0; @@ -2539,6 +3492,9 @@ void GCodeProcessor::reset() m_filament_id = std::vector(MAXIMUM_EXTRUDER_NUMBER, static_cast(-1)); m_last_filament_id = std::vector(MAXIMUM_EXTRUDER_NUMBER, static_cast(-1)); m_extruder_id = static_cast(-1); + // clear the multi-nozzle occupancy tracker between slices (the richer hotend-change model's only + // mutable state). Inert for the single-nozzle fleet (never populated). + m_nozzle_status_recorder = MultiNozzleUtils::NozzleStatusRecorder{}; m_extruder_colors.resize(MIN_EXTRUDERS_COUNT); for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) { m_extruder_colors[i] = static_cast(i); @@ -2549,6 +3505,18 @@ void GCodeProcessor::reset() } m_physical_extruder_map.clear(); + m_extruder_max_nozzle_count = { 1 }; + + // reset pre-heat / pre-cool injector estimator inputs to defaults. Repopulated by apply_config + // each slice. + m_filament_types.clear(); + m_nozzle_diameter.clear(); + m_hotend_cooling_rate = m_hotend_heating_rate = { 2.f }; + m_filament_pre_cooling_temp = { 0 }; + m_filament_preheat_temperature_delta.clear(); + m_enable_pre_heating = false; + m_handle_hotend_as_extruder = false; + m_has_filament_switcher = false; m_highest_bed_temp = 0; @@ -2726,6 +3694,12 @@ void GCodeProcessor::finalize(bool post_process) if (post_process){ run_post_process(); + // Additive pre-heat/pre-cool injection second pass. Gated on m_enable_pre_heating so the + // byte-frozen fleet (X1/P1/A1/H2S) never enters it. When the injector produces no lines the + // InsertedLinesMap is empty, so this is a byte-for-byte identity rewrite; it exercises the + // merge/offset machinery on the multi-nozzle fleet (H2D/X2D/H2D-Pro/H2C). + if (m_enable_pre_heating) + run_second_pass_injection(); } //BBS: update slice warning update_slice_warnings(); @@ -3178,6 +4152,29 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers return; } + // SKIPPABLE region tags. Mark the current section so its time blocks are stamped with the skip + // type. The shipping time_lapse_gcode template emits these tags fleet-wide, so this parse fires on + // essentially every slice (m_skippable → true, m_skippable_type → stTimelapse); it only sets + // internal state and early-returns, so the output is byte-identical until the injector reads the + // stamps. + if (boost::starts_with(comment, GCodeProcessor::Skippable_Start_Tag)) { + m_skippable = true; + return; + } + + if (boost::starts_with(comment, GCodeProcessor::Skippable_End_Tag)) { + m_skippable = false; + m_skippable_type = SkipType::stNone; + return; + } + + // skippable type + if (boost::starts_with(comment, GCodeProcessor::Skippable_Type_Tag)) { + std::string_view type = comment.substr(GCodeProcessor::Skippable_Type_Tag.length()); + set_skippable_type(type); + return; + } + //BBS: flush start tag if (boost::starts_with(comment, GCodeProcessor::Flush_Start_Tag)) { m_flushing = true; @@ -4009,6 +5006,10 @@ void GCodeProcessor::process_G1(const std::array, 4>& axes TimeBlock block; block.move_type = type; + // stamp the current SKIPPABLE type onto the block. Stamped stTimelapse inside the fleet-wide + // time_lapse_gcode regions; byte-inert because nothing reads the stamp until the injector + // consumes it. + block.skippable_type = m_skippable_type; //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode. block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.distance = distance; @@ -4369,6 +5370,10 @@ void GCodeProcessor::process_VG1(const GCodeReader::GCodeLine& line) TimeBlock block; block.move_type = type; + // stamp the current SKIPPABLE type onto the block. Stamped stTimelapse inside the fleet-wide + // time_lapse_gcode regions; byte-inert because nothing reads the stamp until the injector + // consumes it. + block.skippable_type = m_skippable_type; //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode. block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone; block.distance = distance; @@ -5450,7 +6455,14 @@ void GCodeProcessor::process_SYNC(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_T(const GCodeReader::GCodeLine& line) { - process_T(line.cmd()); + // parse the H logical-nozzle id off the T line. H2C's change_filament template emits + // `T H`; the single-nozzle fleet emits a bare `T` (H absent → -1 → byte-inert + // via the self-gate). + int nozzle_id = -1; + float nozzle_val = 0.f; + if (line.has_value('H', nozzle_val)) + nozzle_id = static_cast(nozzle_val); + process_T(line.cmd(), nozzle_id); } void GCodeProcessor::process_M1020(const GCodeReader::GCodeLine &line) @@ -5474,12 +6486,25 @@ void GCodeProcessor::process_M1020(const GCodeReader::GCodeLine &line) BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; return; } - process_filament_change(eid); + // carry the H logical-nozzle id. process_filament_change(int,int) self-gates back + // to the single-arg model for the single-nozzle fleet, so this is byte-inert for them. + int nozzle_id = -1; + float nozzle_val = 0.f; + if (line.has_value('H', nozzle_val)) + nozzle_id = static_cast(nozzle_val); + process_filament_change(eid, nozzle_id); } } } void GCodeProcessor::process_T(const std::string_view command) +{ + // the no-nozzle-context callers (custom-gcode tool-change strings, color-print T parsing) route + // through the H-less variant; -1 keeps the richer model on its filament-first nozzle fallback. + process_T(command, -1); +} + +void GCodeProcessor::process_T(const std::string_view command, int nozzle_id) { unsigned int eid = 0; auto ret = std::from_chars(command.data() + 1, command.data()+command.size(), eid); @@ -5505,7 +6530,9 @@ void GCodeProcessor::process_T(const std::string_view command) BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; return; } - process_filament_change(eid); + // process_filament_change(int,int) self-gates back to the single-arg model for the + // single-nozzle fleet, so this call is byte-inert for X1/P1/A1/H2S/A2L. + process_filament_change(eid, nozzle_id); } } } @@ -5521,6 +6548,148 @@ void GCodeProcessor::init_filament_maps_and_nozzle_type_when_import_only_gcode() } } +bool GCodeProcessor::use_multi_nozzle_change_time_model() const +{ + // Multi-nozzle context = a printer that can incur nozzle-change events the single-arg model + // cannot distinguish: either a multi-extruder machine (nozzle_diameter has >1 physical extruder, + // e.g. H2D/X2D/H2D-Pro) or an extruder that carries a nozzle cluster (extruder_max_nozzle_count>1, + // e.g. H2C's {1,6}). Every single-extruder single-nozzle printer (X1/P1/A1/H2S/A2L) fails both + // tests → false → they keep the byte-frozen single-arg time model. Both members are populated by + // apply_config (each overload) and cleared in reset(), so this is stream-time safe. + if (m_nozzle_diameter.size() > 1) + return true; + for (int count : m_extruder_max_nozzle_count) + if (count > 1) + return true; + return false; +} + +// The richer hotend-change time model. It resolves the target nozzle from the nozzle-grouping result +// (by the H id when present, else the filament's first nozzle) and splits the change into three +// independent costs — physical-extruder switch, nozzle-in-extruder change, and filament-in-nozzle +// change — so a multi-nozzle print's ETA reflects only the transitions that actually occur. +// Estimator-gated: for the single-nozzle fleet it delegates to the single-arg model, so their time +// estimate — hence exported g-code — is unchanged. +// +// Orca: +// - The nozzle-grouping result is stored on m_result. Both resolver methods are virtual on +// NozzleGroupResultBase, so no down-cast is needed. +// - The flush delay is attributed via a Tool_change move-type block with no extrusion role (mirroring +// the single-arg convention) rather than an erFlush-stamped block, to keep the delay out of the +// per-role feature-time distribution, so the multi-nozzle delta stays a pure ETA/time shift. +// - Beyond total_(flush_)filament_changes, the richer counters (total_extruder_changes / load / +// unload / tool_change time) are maintained in the matching branches so the multi-nozzle +// GCodeViewer stats do not regress to zero. These are UI-only (not written to g-code). +void GCodeProcessor::process_filament_change(int id, int nozzle_id) +{ + // Gate: outside the multi-nozzle context, or when the nozzle-grouping result is not available + // (e.g. re-importing a bare g-code file), run the existing single-arg model byte-for-byte. + if (!use_multi_nozzle_change_time_model() || !m_result.nozzle_group_result) { + process_filament_change(id); + return; + } + + assert(id < m_result.filaments_count); + const int prev_extruder_id = get_extruder_id(false); + const int prev_filament_id = get_filament_id(false); + float extra_time = 0.0f; + + // A same-filament re-select with no explicit nozzle target costs nothing. + if (prev_filament_id == id && nozzle_id == -1) + return; + + if (prev_extruder_id != -1) + m_last_filament_id[prev_extruder_id] = static_cast(prev_filament_id); + + // Resolve the destination nozzle: by explicit H id first, else the filament's first nozzle. + std::optional target_nozzle_info; + if (nozzle_id != -1) + target_nozzle_info = m_result.nozzle_group_result->get_nozzle_from_id(nozzle_id); + if (!target_nozzle_info) { + auto used_nozzles = m_result.nozzle_group_result->get_nozzles_for_filament(id); + if (used_nozzles.empty()) + return; + target_nozzle_info = used_nozzles.front(); + } + if (!target_nozzle_info) + return; + + const int new_extruder_id = target_nozzle_info->extruder_id; + const int old_extruder_id = prev_extruder_id; + const int new_nozzle_id_in_extruder = target_nozzle_info->group_id; + const int old_nozzle_id_in_extruder = m_nozzle_status_recorder.get_nozzle_in_extruder(new_extruder_id); + const int new_filament_id = id; + const int old_filament_in_nozzle = m_nozzle_status_recorder.get_filament_in_nozzle(new_nozzle_id_in_extruder); + const int old_filament_in_extruder = m_nozzle_status_recorder.get_filament_in_nozzle(old_nozzle_id_in_extruder); + + const bool extruder_change = new_extruder_id != old_extruder_id; + const bool nozzle_in_extruder_change = new_nozzle_id_in_extruder != old_nozzle_id_in_extruder; + const bool filament_in_nozzle_change = new_filament_id != old_filament_in_nozzle; + + // Orca: attribute the accumulated volume usage to the OLD extruder before switching state. Unlike + // an unconditional call, the single-arg model (and every other Orca estimator path) skips this on + // the very first tool-select (prev_extruder_id == -1) where there is no prior filament segment to + // close out. Matching that keeps H2C's initial `T H` byte-identical to its single-arg + // baseline; every subsequent change closes out identically. + if (prev_extruder_id != -1) + process_filaments(CustomGCode::ToolChange); + + m_result.lock(); + if (extruder_change && old_extruder_id != -1) { + const float t = get_extruder_change_time(new_extruder_id); + extra_time += t; + m_result.print_statistics.total_tool_change_time += t; // Orca-only stat + m_result.print_statistics.total_extruder_changes += 1; // Orca-only stat + } + if (nozzle_in_extruder_change || filament_in_nozzle_change) { + if (old_filament_in_extruder >= 0) { + const float t = get_filament_unload_time(static_cast(old_filament_in_extruder)); + extra_time += t; + m_result.print_statistics.total_filament_unload_time += t; // Orca-only stat + } + m_time_processor.extruder_unloaded = false; + const float t = get_filament_load_time(static_cast(new_filament_id)); + extra_time += t; + m_result.print_statistics.total_filament_load_time += t; // Orca-only stat + if (filament_in_nozzle_change && old_filament_in_nozzle != -1) + m_result.print_statistics.total_flush_filament_changes += 1; + } + if (prev_filament_id != -1) + m_result.print_statistics.total_filament_changes += 1; + m_result.unlock(); + + if (new_extruder_id != -1) + m_filament_id[new_extruder_id] = static_cast(new_filament_id); + m_extruder_id = static_cast(new_extruder_id); + + // Record the resulting nozzle/extruder occupancy so the next change can classify itself. + m_nozzle_status_recorder.set_nozzle_status(new_nozzle_id_in_extruder, new_filament_id, new_extruder_id); + + m_cp_color.current = m_extruder_colors[new_filament_id]; + + // Same tool-change move + zero-distance time block plumbing as the single-arg model, so the flush + // delay lands on a Tool_change block (kept out of the per-role feature-time distribution). + store_move_vertex(EMoveType::Tool_change); + + for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { + TimeMachine& machine = m_time_processor.machines[i]; + if (!machine.enabled) + continue; + TimeBlock block; + block.move_id = static_cast(m_result.moves.size()) - 1; + block.move_type = EMoveType::Tool_change; + block.skippable_type = m_skippable_type; + block.layer_id = std::max(1, m_layer_id); + block.g1_line_id = m_g1_line_id; + block.flags.prepare_stage = m_processing_start_custom_gcode; + block.distance = 0.0f; + block.calculate_trapezoid(); + machine.blocks.push_back(block); + } + + simulate_st_synchronize(extra_time, EMoveType::Tool_change); +} + void GCodeProcessor::process_filament_change(int id) { assert(id < m_result.filaments_count); @@ -5628,6 +6797,10 @@ void GCodeProcessor::process_filament_change(int id) TimeBlock block; block.move_id = static_cast(m_result.moves.size()) - 1; block.move_type = EMoveType::Tool_change; + // stamp the current SKIPPABLE type onto the tool-change block (the fleet-wide time_lapse_gcode + // regions stamp stTimelapse); byte-inert because nothing reads the stamp until the injector + // consumes it. + block.skippable_type = m_skippable_type; block.layer_id = std::max(1, m_layer_id); block.g1_line_id = m_g1_line_id; block.flags.prepare_stage = m_processing_start_custom_gcode; @@ -5735,6 +6908,21 @@ void GCodeProcessor::set_extrusion_role(ExtrusionRole role) m_extrusion_role = role; } +// Resolve a SKIPPABLE_TYPE payload to a SkipType. Only meaningful inside a SKIPPABLE region. +void GCodeProcessor::set_skippable_type(const std::string_view type) +{ + if (!m_skippable) { + m_skippable_type = SkipType::stNone; + return; + } + auto iter = skip_type_map.find(type); + if (iter != skip_type_map.end()) { + m_skippable_type = iter->second; + } else { + m_skippable_type = SkipType::stOther; + } +} + float GCodeProcessor::minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const { if (m_time_processor.machine_limits.machine_min_extruding_rate.empty()) diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index fcefd1a9a7..633695b03e 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -6,6 +6,7 @@ #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/PrintConfig.hpp" #include "libslic3r/CustomGCode.hpp" +#include "libslic3r/MultiNozzleUtils.hpp" #include #include @@ -43,6 +44,23 @@ class Print; Count }; + // Classifies why a wipe-tower / change_filament / time-lapse region is safe to relocate a + // pre-heat M104 into, for the pre-heat/pre-cool injector. The shipping time_lapse_gcode + // template (timelapse-on by default) emits SKIPPABLE_* on essentially every slice, so the + // "timelapse" payload -> stTimelapse classification is exercised widely. + enum SkipType + { + stTimelapse, + stHeadWrapDetect, + stOther, + stNone + }; + + const std::unordered_map skip_type_map{ + {"timelapse", SkipType::stTimelapse}, + {"head_wrap_detect", SkipType::stHeadWrapDetect} + }; + struct PrintEstimatedStatistics { enum class ETimeMode : unsigned char @@ -77,6 +95,10 @@ class Print; std::array(ETimeMode::Count)> modes; unsigned int total_filament_changes; + // Number of filament changes that actually re-flush a nozzle (a filament-in-nozzle change + // onto a non-empty nozzle), tracked only by the richer multi-nozzle hotend-change time model. + // Stays 0 for single-nozzle printers (X1/P1/A1/H2S/A2L), which never enter the two-arg model. + unsigned int total_flush_filament_changes; unsigned int total_extruder_changes; float total_filament_load_time; float total_filament_unload_time; @@ -101,6 +123,7 @@ class Print; flush_per_filament.clear(); used_filaments_per_role.clear(); total_filament_changes = 0; + total_flush_filament_changes = 0; total_extruder_changes = 0; total_filament_load_time = 0.0f; total_filament_unload_time = 0.0f; @@ -166,6 +189,14 @@ class Print; ConflictResultOpt conflict_result; GCodeCheckResult gcode_check_result; FilamentPrintableResult filament_printable_reuslt; + // The per-filament -> logical-nozzle grouping the slicer computed for this + // result, surfaced onto the object the device GUI reads + // (plater->background_process().get_current_gcode_result()). Populated only from + // Print::get_layered_nozzle_group_result() (ToolOrdering's static L/R + rack subset); + // default-empty (null) and read by no g-code emitter, so it is invisible in the emitted + // g-code. Consumed by the print-dispatch nozzle mapping (DevNozzleMappingCtrl) via + // DevUtilBackend::GetNozzleGroupResult. + std::shared_ptr nozzle_group_result; float initial_layer_time; struct SettingsIds @@ -263,6 +294,10 @@ class Print; std::vector warnings; int nozzle_hrc; std::vector nozzle_type; + // Per-extruder physical hotend type. Fed to the pre-heat injector's TimeProcessContext + // (mixed-type X2D workaround). Populated in apply_config; unused until the injector side-pass + // consumes it. + std::vector extruder_types; // first key stores filaments, second keys stores the layer ranges(enclosed) that use the filaments std::unordered_map, std::vector>,FilamentSequenceHash> layer_filaments; std::vector nozzle_change_sequence; @@ -271,6 +306,11 @@ class Print; // first key stores `from` filament, second keys stores the `to` filament std::map, int > filament_change_count_map; + // Accumulated print time spent inside SKIPPABLE regions, per skip type. Populated by the time + // estimator; consumed only downstream. The shipping time_lapse_gcode template emits SKIPPABLE_* + // widely, so this is typically populated (stTimelapse) on most slices. + std::unordered_map skippable_part_time; + BedType bed_type = BedType::btCount; void reset(); @@ -304,11 +344,18 @@ class Print; gcode_check_result = other.gcode_check_result; limit_filament_maps = other.limit_filament_maps; filament_printable_reuslt = other.filament_printable_reuslt; + // Orca: copy the shared grouping result so a copied result keeps it (shared_ptr => + // memory-safe), rather than leaving a stale pointer on the target. No g-code effect either way. + nozzle_group_result = other.nozzle_group_result; + // Keep the per-extruder hotend types on a copied result (injector input). + extruder_types = other.extruder_types; layer_filaments = other.layer_filaments; filament_change_sequence = other.filament_change_sequence; nozzle_change_sequence = other.nozzle_change_sequence; optimal_assignment = other.optimal_assignment; filament_change_count_map = other.filament_change_count_map; + // Keep the SKIPPABLE per-type time on a copied result. + skippable_part_time = other.skippable_part_time; initial_layer_time = other.initial_layer_time; #if ENABLE_GCODE_VIEWER_STATISTICS time = other.time; @@ -319,6 +366,75 @@ class Print; void unlock() const { result_mutex.unlock(); } }; + // First-pass usage-block descriptors for the pre-heat/pre-cool injector. FilamentUsageBlock + // records the [lower,upper) output-line-id span a single filament occupies; ExtruderUsageBlcok + // (the "Blcok" typo is intentional) records the span an extruder is active in, with the start/end + // filament + logical-nozzle ids and the post-extrusion (pre-switch) partial-free sub-range. Built + // during run_post_process, consumed only by the injector side-pass under the enable_pre_heating gate. + namespace ExtruderPreHeating + { + struct FilamentUsageBlock + { + int filament_id; + int extruder_id; + int nozzle_id; + unsigned int lower_gcode_id; + unsigned int upper_gcode_id; // [lower_gcode_id,upper_gcode_id) uses current filament , upper gcode id will be set after finding next block + FilamentUsageBlock(int filament_id_, int extruder_id_, int nozzle_id_, unsigned int lower_gcode_id_, unsigned int upper_gcode_id_) :filament_id(filament_id_), extruder_id(extruder_id_), nozzle_id(nozzle_id_), lower_gcode_id(lower_gcode_id_), upper_gcode_id(upper_gcode_id_) {} + }; + + /** + * @brief Describle the usage of a exturder in a section + * + * The strucutre stores the start and end lines of the sections as well as + * the filament used at the beginning and end of the section. + * Post extrusion means the final extrusion before switching to the next extruder. + * + * Simplified GCode Flow: + * 1.Extruder Change Block (ext0 switch to ext1) + * 2.Extruder Usage Block (use ext1 to print) + * 3.Extruder Change Block (ext1 switch to ext0) + * 4.Extruder Usage Block (use ext0 to print) + * 5.Extruder Change Block (ext0 switch to ex1) + * ... + * + * So the construct of extruder usage block relys on two extruder change block + */ + struct ExtruderUsageBlcok + { + int extruder_id = -1; + unsigned int start_id = -1; + unsigned int end_id = -1; + int start_filament = -1; + int end_filament = -1; + int start_nozzle_id = -1; + int end_nozzle_id = -1; + unsigned int post_extrusion_start_id = -1; + unsigned int post_extrusion_end_id = -1; + bool ignore_cooling_before_tower = false; + + void initialize_step_1(int extruder_id_, int start_id_, int start_filament_, int start_nozzle_id_) { + extruder_id = extruder_id_; + start_id = start_id_; + start_filament = start_filament_; + start_nozzle_id = start_nozzle_id_; + }; + void initialize_step_2(int post_extrusion_start_id_) { + post_extrusion_start_id = post_extrusion_start_id_; + } + void initialize_step_3(int end_id_, int end_filament_, int post_extrusion_end_id_, int end_nozzle_id_) { + end_id = end_id_; + end_filament = end_filament_; + post_extrusion_end_id = post_extrusion_end_id_; + end_nozzle_id = end_nozzle_id_; + } + void reset() { + *this = ExtruderUsageBlcok(); + } + ExtruderUsageBlcok() = default; + }; + } + class CommandProcessor { public: @@ -347,6 +463,24 @@ class Print; static const std::string VFlush_Start_Tag; static const std::string VFlush_End_Tag; static const std::string External_Purge_Tag; + public: + // Orca: SKIPPABLE region tags, stored as static strings (the FLUSH idiom above) rather than + // a CustomETags/CustomTags array. Public so the emission sites (WipeTower / change_filament + // path) can reference them single-sourced. + static const std::string Skippable_Start_Tag; + static const std::string Skippable_End_Tag; + static const std::string Skippable_Type_Tag; + // Orca: usage-block builder markers (MACHINE_START_GCODE_END / MACHINE_END_GCODE_START / + // NOZZLE_CHANGE_START / NOZZLE_CHANGE_END / CP_TOOLCHANGE_WIPE), stored as static strings (the + // FLUSH/SKIPPABLE idiom above) rather than extending the Reserved_Tags arrays — these are + // multi-nozzle markers only ever emitted by BBL-printer paths. Public so the emission sites can + // reference them single-sourced. The MACHINE_*_GCODE_* emission (GCode.cpp, gated + // enable_pre_heating) activates the usage-block builder. + static const std::string Machine_Start_GCode_End_Tag; + static const std::string Machine_End_GCode_Start_Tag; + static const std::string Nozzle_Change_Start_Tag; + static const std::string Nozzle_Change_End_Tag; + static const std::string Toolchange_Wipe_Tag; public: enum class ETags : unsigned char { @@ -455,6 +589,9 @@ class Print; EMoveType move_type{ EMoveType::Noop }; ExtrusionRole role{ erNone }; + // SKIPPABLE tag classification stamped onto each time block. Feeds skippable_part_time + // and the injector's SKIPPABLE relocation. stNone unless inside a SKIPPABLE_* region. + SkipType skippable_type{ SkipType::stNone }; unsigned int move_id{ 0 }; unsigned int g1_line_id{ 0 }; unsigned int remaining_internal_g1_lines{ 0 }; @@ -624,6 +761,25 @@ class Print; struct TimeProcessor { + // Orca: the insert-line taxonomy + the ordered map of lines the pre-heat/pre-cool injector + // splices into the finished g-code, keyed by output-line id. Orca keeps its single-pass + // run_post_process (M73 / filament stats / ActualSpeedMove / Backtrace / + // machine_tool_change_time) intact and applies this map in a separate, gated ADDITIVE + // second file-rewrite pass (run_second_pass_injection); with an empty map that pass is a + // byte-for-byte identity rewrite. The map is populated by the PreCoolingInjector. + enum InsertLineType + { + PlaceholderReplace, + TimePredict, + FilamentChangePredict, + ExtruderChangePredict, + PreCooling, + PreHeating, + }; + + // first key is line id, second key is content + using InsertedLinesMap = std::map>>; + struct Planner { // Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks. @@ -651,6 +807,117 @@ class Print; void reset(); }; + + // The pre-cool / pre-heat injection engine. It consumes the already-computed per-move time + // substrate (moves[i].time[valid_machine_id] / .gcode_id) and the first-pass usage blocks to + // locate idle-hotend windows, then emits M632/M400/M104/M633 lines into a + // TimeProcessor::InsertedLinesMap that the additive second file-rewrite pass + // (run_second_pass_injection) splices into the finished g-code. It is constructed and run ONLY + // when m_enable_pre_heating — single-nozzle printers (X1/P1/A1/H2S, flag false) never reach it. + // Every input is a const reference bundled from GCodeProcessor members; the injector never + // mutates GCodeProcessor state. + class PreCoolingInjector { + public: + struct ExtruderFreeBlock { + unsigned int free_lower_gcode_id; + unsigned int free_upper_gcode_id; + unsigned int partial_free_lower_id; // range of extrusion in wipe tower; without a wipe tower + unsigned int partial_free_upper_id; // partial_free lower/upper equal free_lower_gcode_id + int last_filament_id; + int next_filament_id; + int last_nozzle_id; + int next_nozzle_id; + int extruder_id; // partition key for the pre-heat/pre-cool region (extruder or hotend), not + // necessarily a real extruder id + bool ignore_cooling_before_tower = false; + }; + + void process_pre_cooling_and_heating(TimeProcessor::InsertedLinesMap& inserted_operation_lines); + void build_extruder_free_blocks(const std::vector& filament_usage_blocks, const std::vector& extruder_usage_blocks); + + PreCoolingInjector( + const std::vector& moves_, + const std::vector& filament_types_, + const MultiNozzleUtils::LayeredNozzleGroupResult& nozzle_group_result_, + const std::vector& filament_nozzle_temps_, + const std::vector& filament_nozzle_temps_initial_layer_, + const std::vector& physical_extruder_map_, + int valid_machine_id_, + float inject_time_threshold_, + bool handle_hotend_as_extruder_, + bool has_filament_switcher_, + const std::vector& pre_cooling_temp_, + const std::vector& cooling_rate_, + const std::vector& heating_rate_, + const std::vector>& skippable_blocks_, + const std::vector& extruder_max_nozzle_count_, + const std::vector& filament_preheat_temperature_delta_, + const std::vector& filament_max_temperature_drop_when_ec_, + unsigned int machine_start_gcode_end_id_, + unsigned int machine_end_gcode_start_id_, + const std::vector& extruder_types_, + const std::vector& nozzle_diameter_ + ) : + moves(moves_), + filament_types(filament_types_), + nozzle_group_result(nozzle_group_result_), + filament_nozzle_temps(filament_nozzle_temps_), + filament_nozzle_temps_initial_layer(filament_nozzle_temps_initial_layer_), + physical_extruder_map(physical_extruder_map_), + valid_machine_id(valid_machine_id_), + inject_time_threshold(inject_time_threshold_), + handle_hotend_as_extruder(handle_hotend_as_extruder_), + has_filament_switcher(has_filament_switcher_), + filament_pre_cooling_temps(pre_cooling_temp_), + cooling_rate(cooling_rate_), + heating_rate(heating_rate_), + skippable_blocks(skippable_blocks_), + extruder_max_nozzle_count(extruder_max_nozzle_count_), + filament_preheat_temperature_delta(filament_preheat_temperature_delta_), + filament_max_temperature_drop_when_ec(filament_max_temperature_drop_when_ec_), + machine_start_gcode_end_id(machine_start_gcode_end_id_), + machine_end_gcode_start_id(machine_end_gcode_start_id_), + extruder_types(extruder_types_), + nozzle_diameter(nozzle_diameter_) + { + } + + private: + std::vector m_extruder_free_blocks; + const std::vector& moves; + const std::vector& filament_types; + const MultiNozzleUtils::LayeredNozzleGroupResult& nozzle_group_result; + const std::vector& filament_nozzle_temps; + const std::vector& filament_nozzle_temps_initial_layer; + const std::vector& physical_extruder_map; + const int valid_machine_id; + const float inject_time_threshold; + const bool handle_hotend_as_extruder; + const bool has_filament_switcher; + const std::vector& cooling_rate; + const std::vector& heating_rate; + const std::vector& filament_pre_cooling_temps; // target cooling temp during post extrusion + const std::vector>& skippable_blocks; + const std::vector& extruder_max_nozzle_count; + const std::vector& filament_preheat_temperature_delta; + const std::vector& filament_max_temperature_drop_when_ec; + const unsigned int machine_start_gcode_end_id; + const unsigned int machine_end_gcode_start_id; + const std::vector& extruder_types; + const std::vector& nozzle_diameter; + + void inject_cooling_heating_command( + TimeProcessor::InsertedLinesMap& inserted_operation_lines, + const ExtruderFreeBlock& free_block, + float curr_temp, + float target_temp, + bool pre_cooling, + bool pre_heating + ); + + void build_by_filament_blocks(const std::vector& filament_usage_blocks); + void build_by_extruder_blocks(const std::vector& extruder_usage_blocks); + }; public: class SeamsDetector { @@ -795,12 +1062,51 @@ class Print; bool m_flushing; // mark a section with real flush bool m_virtual_flushing; // mark a section with virtual flush, only for statistics bool m_wipe_tower; + // Current-section SKIPPABLE state. Set by process_tags when inside a SKIPPABLE_* region; + // stamped onto each TimeBlock. The shipping time_lapse_gcode template emits SKIPPABLE_* + // widely, so these commonly go active (true / stTimelapse) and stamp blocks on most slices. + bool m_skippable{false}; + SkipType m_skippable_type{SkipType::stNone}; int m_object_label_id{-1}; float m_print_z{0.0f}; std::vector m_remaining_volume; ExtruderTemps m_filament_nozzle_temp; ExtruderTemps m_filament_nozzle_temp_first_layer; std::vector m_physical_extruder_map; + // Multi-nozzle context state. Per-extruder max (sub-)nozzle count; >1 marks a multi-nozzle + // extruder. Input for the pre-heat/filament-change-time injection model; not yet consumed by + // Orca's time estimator, so it is inert for existing printers. + std::vector m_extruder_max_nozzle_count{1}; + // Pre-heat / pre-cool injector estimator inputs. Populated from the config in apply_config + // (both overloads) and cleared in reset(), so the PreCoolingInjector has its inputs in place. + // Consumed only by the injector two-pass side-pass, gated on m_enable_pre_heating. + std::vector m_filament_types; + std::vector m_nozzle_diameter; + std::vector m_hotend_cooling_rate{ 2.f }; + std::vector m_hotend_heating_rate{ 2.f }; + std::vector m_filament_pre_cooling_temp{ 0 }; + std::vector m_filament_preheat_temperature_delta; + bool m_enable_pre_heating{ false }; + bool m_handle_hotend_as_extruder{ false }; + bool m_has_filament_switcher{ false }; + // [start,end] output-line-id ranges of each SKIPPABLE region, collected during + // run_post_process. The injector relocates pre-heat M104s out of these ranges. The shipping + // time_lapse_gcode template emits SKIPPABLE_* widely, so on a timelapse-on slice this is + // populated with many timelapse ranges (not empty) — the consumer must expect the common + // timelapse case, not only H2C/A2L wipe-tower ranges. + std::vector> m_skippable_blocks; + // First-pass usage blocks, built in run_post_process and stored on the member so the + // injector side-pass can consume them. Filled only when m_enable_pre_heating — single-nozzle + // printers (X1/P1/A1/H2S) never build them. They depend on the MACHINE_*_GCODE_* / + // NOZZLE_CHANGE_* emission the builder keys off. + std::vector m_filament_blocks; + std::vector m_extruder_blocks; + unsigned int m_machine_start_gcode_end_line_id{ (unsigned int) (-1) }; + unsigned int m_machine_end_gcode_start_line_id{ (unsigned int) (-1) }; + // Tracks, during the stream, which filament sits in each physical nozzle and which nozzle each + // extruder currently carries. Consumed ONLY by the richer two-arg process_filament_change + // model, which single-nozzle printers (X1/P1/A1/H2S/A2L) never enter. + MultiNozzleUtils::NozzleStatusRecorder m_nozzle_status_recorder; bool m_manual_filament_change; //BBS: x, y offset for gcode generated @@ -1094,22 +1400,43 @@ class Print; // Processes T line (Select Tool) void process_T(const GCodeReader::GCodeLine& line); void process_T(const std::string_view command); + // T variant carrying the H logical-nozzle id parsed off the command line. -1 = absent. + void process_T(const std::string_view command, int nozzle_id); void process_M1020(const GCodeReader::GCodeLine &line); void process_M622(const GCodeReader::GCodeLine &line); void process_M623(const GCodeReader::GCodeLine &line); void process_filament_change(int id); + // Richer hotend-change time model distinguishing extruder-switch / nozzle-in-extruder change / + // filament-in-nozzle change. Self-gated: for single-nozzle printers it delegates to + // process_filament_change(int) so their time estimate — hence exported g-code — is unchanged. + void process_filament_change(int id, int nozzle_id); + // True only for multi-nozzle-capable printers (H2C cluster, or a dual/multi-extruder machine + // like H2D/X2D): the gate that admits the richer two-arg hotend-change time model. False for + // every single-extruder single-nozzle printer (X1/P1/A1/H2S/A2L). + bool use_multi_nozzle_change_time_model() const; // post process the file with the given filename to: // 1) add remaining time lines M73 and update moves' gcode ids accordingly // 2) update used filament data void run_post_process(); + // Additive second file-rewrite pass. Splices the pre-heat/pre-cool injector's InsertedLinesMap + // into the finished g-code and re-shifts every move's gcode_id by the number of inserted lines + // before it. Runs only when m_enable_pre_heating, AFTER run_post_process, so single-nozzle + // printers (X1/P1/A1/H2S) never enter it; with an empty map it is a byte-for-byte identity rewrite. + void run_second_pass_injection(); + // Shift each move's gcode_id by the count of injector lines inserted before it. No-op when the + // map is empty. + void handle_offsets_of_second_process(const TimeProcessor::InsertedLinesMap& inserted_operation_lines); + //BBS: different path_type is only used for arc move void store_move_vertex(EMoveType type, EMovePathType path_type = EMovePathType::Noop_move, bool internal_only = false); void set_extrusion_role(ExtrusionRole role); + // Resolve the SKIPPABLE_TYPE payload to a SkipType. + void set_skippable_type(const std::string_view type); float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const; diff --git a/src/libslic3r/GCode/TimelapsePosPicker.cpp b/src/libslic3r/GCode/TimelapsePosPicker.cpp index 0301d01122..364624a88c 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.cpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.cpp @@ -361,7 +361,8 @@ namespace Slic3r { * @param safe_areas A collection of extended polygons defining the safe areas. * @return Point The nearest point within the safe areas or the default timelapse position if no safe areas exist. */ - Point pick_pos_internal(const Point& curr_pos, const ExPolygons& safe_areas, const ExPolygons& path_collision_area, bool detect_path_collision) + Point pick_pos_internal(const Point& curr_pos, const ExPolygons& safe_areas, const ExPolygons& path_collision_area, bool detect_path_collision, + const std::optional& farthest_point = std::nullopt) { struct CandidatePoint { @@ -381,7 +382,11 @@ namespace Slic3r { std::priority_queue max_heap; const double candidate_point_segment = scale_(5), weight_of_camera=1./3.; - auto penaltyFunc = [&weight_of_camera](const Point &curr_post, const Point &CameraPos, const Point &candidatet) -> double { + auto penaltyFunc = [&weight_of_camera, &farthest_point](const Point &curr_post, const Point &CameraPos, const Point &candidatet) -> double { + if (farthest_point.has_value()) { + // Farthest-point timelapse: prefer candidate closest to the farthest point (L1 norm) + return (farthest_point.value() - candidatet).cwiseAbs().sum(); + } // move distance + Camera occlusion penalty function double ret_pen = (curr_post - candidatet).cwiseAbs().sum() - weight_of_camera * (CameraPos - candidatet).cwiseAbs().sum(); return ret_pen; @@ -523,7 +528,7 @@ namespace Slic3r { path_collision_area = union_ex(layer_slices_without_curr, rod_limit_areas); } - return pick_pos_internal(center_p, safe_area,path_collision_area, by_object); + return pick_pos_internal(center_p, safe_area,path_collision_area, by_object, ctx.farthest_point); } /** @@ -610,4 +615,50 @@ namespace Slic3r { return *m_all_layer_pos; } + // Whether the head can travel to X0 without crossing any other instance that is + // taller than the current print position. + bool TimelapsePosPicker::get_is_clear_to_x0(const PosPickCtx &ctx) + { + bool by_object = m_print_seq == PrintSequence::ByObject; + std::vector object_list = get_object_list(ctx.printed_objects); + + auto range_intersect = [](int left1, int right1, int left2, int right2) { + if (left1 <= left2 && left2 <= right1) return true; + if (left2 <= left1 && left1 <= right2) return true; + return false; + }; + + ExPolygons unclear_area; + const Layer *layer = ctx.curr_layer; + float z_target = layer->print_z; + float z_low = layer->print_z - 0.5; + float z_high = layer->print_z + 0.5; + + for (auto &obj : object_list) { + for (auto &instance : obj->instances()) { + auto instance_bbox = get_real_instance_bbox(instance); + bool is_curr_obj = ( obj == object_list.back() ) || ( !by_object ), + higher_than_curr_pos = instance_bbox.max.z() > z_target; + if (!is_curr_obj && range_intersect(instance_bbox.min.z(), instance_bbox.max.z(), z_low, z_high)) { + ExPolygon expoly; + expoly.contour = {{scale_(instance_bbox.min.x()), scale_(instance_bbox.min.y())}, + {scale_(instance_bbox.max.x()), scale_(instance_bbox.min.y())}, + {scale_(instance_bbox.max.x()), scale_(instance_bbox.max.y())}, + {scale_(instance_bbox.min.x()), scale_(instance_bbox.max.y())}}; + expoly.contour = expand_object_projection(expoly.contour, by_object, higher_than_curr_pos); + unclear_area.emplace_back(std::move(expoly)); + } + } + } + + Point curr_pos_in_plate = {ctx.curr_pos.x() - scale_(m_plate_offset.x()), ctx.curr_pos.y() - scale_(m_plate_offset.y())}; + for (const ExPolygon &expoly : unclear_area) { + BoundingBox bbox = expoly.contour.bounding_box(); + if (curr_pos_in_plate.y() < bbox.min.y() || curr_pos_in_plate.y() > bbox.max.y()) continue; + if (bbox.min.x() <= curr_pos_in_plate.x()) return false; + } + + return true; + } + } \ No newline at end of file diff --git a/src/libslic3r/GCode/TimelapsePosPicker.hpp b/src/libslic3r/GCode/TimelapsePosPicker.hpp index c4930b3022..9ed6b14fc7 100644 --- a/src/libslic3r/GCode/TimelapsePosPicker.hpp +++ b/src/libslic3r/GCode/TimelapsePosPicker.hpp @@ -22,6 +22,9 @@ namespace Slic3r { int picture_extruder_id; // the extruder id to take picture int curr_extruder_id; std::optional> printed_objects; // printed objects, only have value in by object mode + // Farthest-point timelapse: plate-relative scaled point; when set, pick_pos_internal + // biases the picked snapshot position toward this point (nullopt → legacy camera-occlusion loss). + std::optional farthest_point; }; // data are stored without plate offset @@ -32,6 +35,9 @@ namespace Slic3r { ~TimelapsePosPicker() = default; Point pick_pos(const PosPickCtx& ctx); + // Is the path to X0 clear of other (taller) instances? Drives the + // `clear_to_x0` timelapse-gcode variable (g39 clamping detection). + bool get_is_clear_to_x0(const PosPickCtx& ctx); void init(const Print* print, const Point& plate_offset); void reset(); private: diff --git a/src/libslic3r/GCode/ToolOrderUtils.cpp b/src/libslic3r/GCode/ToolOrderUtils.cpp index 5a6e9059f2..c8b8ac3fdc 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.cpp +++ b/src/libslic3r/GCode/ToolOrderUtils.cpp @@ -7,13 +7,100 @@ namespace Slic3r { +// ==================== MaxFlowWithLowerBounds ==================== + struct MaxFlowWithLowerBounds { + public: + + void add_edge(int from, int to, int capacity); + + bool bfs(); + int dfs(int u, int f); + int solve(std::vector& matching); + + public: + std::vector l_nodes; + std::vector r_nodes; + std::vector edges; + std::vector> adj; + std::vector level; + std::vector it; + + int total_nodes{ -1 }; + int source_id{ -1 }; + int sink_id{ -1 }; + }; + + void MaxFlowWithLowerBounds::add_edge(int from, int to, int capacity) + { + adj[from].emplace_back(edges.size()); + edges.emplace_back(from, to, capacity, 0); + // also add the reverse residual edge with zero capacity + adj[to].emplace_back(edges.size()); + edges.emplace_back(to, from, 0, 0); + } + + bool MaxFlowWithLowerBounds::bfs() { + level.assign(total_nodes, -1); + std::queue q; + q.push(source_id); + level[source_id] = 0; + + while (!q.empty()) { + int u = q.front(); q.pop(); + for (int eid : adj[u]) { + Edge &e = edges[eid]; + if (e.flow < e.capacity && level[e.to] == -1) { + level[e.to] = level[u] + 1; + q.push(e.to); + } + } + } + return level[sink_id] != -1; + } + + int MaxFlowWithLowerBounds::dfs(int u, int f) { + if (u == sink_id) return f; + for (int &i = it[u]; i < (int)adj[u].size(); ++i) { + int eid = adj[u][i]; + Edge &e = edges[eid]; + if (e.flow < e.capacity && level[e.to] == level[u] + 1) { + int pushed = dfs(e.to, std::min(f, e.capacity - e.flow)); + if (pushed > 0) { + e.flow += pushed; + edges[eid ^ 1].flow -= pushed; + return pushed; + } + } + } + return 0; + } + + int MaxFlowWithLowerBounds::solve(std::vector& matching) { + int flow = 0; + while (bfs()) { + it.assign(total_nodes, 0); + while (int pushed = dfs(source_id, MaxFlowGraph::INF)) + flow += pushed; + } + + int L = l_nodes.size(); + int R = r_nodes.size(); + // collect l-r matches + matching.resize(l_nodes.size(), MaxFlowGraph::INVALID_ID); + for (int u = 0; u < L; ++u) { + for (int eid : adj[u]) { + Edge &e = edges[eid]; + if (e.flow > 0 && e.to >= L && e.to < L + R) { + matching[e.from] = e.to - L; + } + } + } + return flow; + } + +// ==================== MinCostMaxFlow ==================== struct MinCostMaxFlow { public: - struct Edge { - int from, to, capacity, cost, flow; - Edge(int u, int v, int cap, int cst) : from(u), to(v), capacity(cap), cost(cst), flow(0) {} - }; - std::vector solve(); void add_edge(int from, int to, int capacity, int cost); bool spfa(int source, int sink); @@ -107,15 +194,10 @@ namespace Slic3r { if (l_nodes[idx_in_left] == -1) { return 0; - //TODO: test more here - int sum = 0; - for (int i = 0; i < matrix.size(); ++i) - sum += matrix[i][idx_in_right]; - sum /= matrix.size(); - return -sum; } - return matrix[l_nodes[idx_in_left]][r_nodes[idx_in_right]]; + float val = matrix[l_nodes[idx_in_left]][r_nodes[idx_in_right]]; + return std::min(static_cast(val), MaxFlowGraph::MCMF_MAX_EDGE_COST); } @@ -123,27 +205,40 @@ namespace Slic3r const std::unordered_map>& uv_link_limits, const std::unordered_map>& uv_unlink_limits, const std::vector& u_capacity, - const std::vector& v_capacity) + const std::vector& v_capacity, + const std::vector,int>>& v_group_capacity) { assert(u_capacity.empty() || u_capacity.size() == u_nodes.size()); assert(v_capacity.empty() || v_capacity.size() == v_nodes.size()); l_nodes = u_nodes; r_nodes = v_nodes; - total_nodes = u_nodes.size() + v_nodes.size() + 2; + total_nodes = u_nodes.size() + v_nodes.size() + v_group_capacity.size() + 2; source_id = total_nodes - 2; sink_id = total_nodes - 1; adj.resize(total_nodes); + std::vectorv_node_to(v_nodes.size(), sink_id); + for (size_t gid = 0; gid < v_group_capacity.size(); ++gid) { + for (auto vid : v_group_capacity[gid].first) + v_node_to[vid] = l_nodes.size() + r_nodes.size() + gid; + } + // add edge from source to left nodes for (int idx = 0; idx < l_nodes.size(); ++idx) { int capacity = u_capacity.empty() ? 1 : u_capacity[idx]; add_edge(source_id, idx, capacity); } - // add edge from right nodes to sink node + // add edge from right nodes to v_node_to(sink node or temp group node) for (int idx = 0; idx < r_nodes.size(); ++idx) { int capacity = v_capacity.empty() ? 1 : v_capacity[idx]; - add_edge(l_nodes.size() + idx, sink_id, capacity); + add_edge(l_nodes.size() + idx, v_node_to[idx], capacity); + } + + // add edge from temp group node to sink node + for (int idx = 0; idx < v_group_capacity.size(); ++idx) { + int capacity = v_group_capacity[idx].second; + add_edge(l_nodes.size() + r_nodes.size() + idx, sink_id, capacity); } // add edge from left nodes to right nodes @@ -269,6 +364,301 @@ namespace Slic3r return m_solver->solve(); } +// ==================== GeneralMinCostLowerBoundsSolver ==================== + GeneralMinCostLowerBoundsSolver::~GeneralMinCostLowerBoundsSolver() = default; + + GeneralMinCostLowerBoundsSolver::GeneralMinCostLowerBoundsSolver(const std::vector &matrix_, + const std::vector &u_nodes, + const std::vector &v_nodes, + const std::vector &v_nodes_group, + const std::unordered_map> &uv_link_limits, + const std::unordered_map> &uv_unlink_limits) + { + flush_matrix = matrix_; + l_nodes = u_nodes; + r_nodes = v_nodes; + r_nodes_group = v_nodes_group; + m_uv_link_limits = uv_link_limits; + m_uv_unlink_limits = uv_unlink_limits; + num_groups = *std::max_element(r_nodes_group.begin(), r_nodes_group.end()) + 1; + + m_solver_lower_bounds = std::make_unique(); + m_solver_min_cost = std::make_unique(); + } + + std::vector GeneralMinCostLowerBoundsSolver::solve() + { + // group nodes that do not need a lower-bound constraint + std::unordered_set no_lower_group; + for (int i = 0; i < r_nodes.size(); i++) { + if (r_nodes[i] >= 0) + no_lower_group.insert(r_nodes_group[i]); + } + + // 1. build the lower-bound network graph + build_feasible_graph(no_lower_group); + + // 2. compute the max flow + int need = 0; + for (int d : demand) + if (d > 0) need += d; + std::vector feasible_matching; + int pushed_flow = m_solver_lower_bounds->solve(feasible_matching); + assert(need == pushed_flow); + + // 3. convert the lower-bound max-flow network into a min-cost-max-flow network + build_graph_with_feasible_result(); + // 4. compute the min-cost max-flow + auto min_cost_matching = m_solver_min_cost->solve(); + + return min_cost_matching; + } + + void GeneralMinCostLowerBoundsSolver::build_feasible_graph(const std::unordered_set &no_lower_groups) + { + m_solver_lower_bounds->l_nodes = l_nodes; + m_solver_lower_bounds->r_nodes = r_nodes; + m_solver_lower_bounds->total_nodes = l_nodes.size() + r_nodes.size() + num_groups + 2; + + m_solver_lower_bounds->source_id = m_solver_lower_bounds->total_nodes - 2; + m_solver_lower_bounds->sink_id = m_solver_lower_bounds->total_nodes - 1; + m_solver_lower_bounds->adj.resize(m_solver_lower_bounds->total_nodes); + demand.resize(m_solver_lower_bounds->total_nodes, 0); + + const int L = m_solver_lower_bounds->l_nodes.size(); + const int R = m_solver_lower_bounds->r_nodes.size(); + + // source -> l + for (int i = 0; i < L; ++i) + m_solver_lower_bounds->add_edge(m_solver_lower_bounds->source_id, i, 1); + + // u -> v (with link/unlink limits) + for (int i = 0; i < L; ++i) { + if (auto it = m_uv_link_limits.find(i); it != m_uv_link_limits.end()) { + for (int j : it->second) + m_solver_lower_bounds->add_edge(i, L + j, 1); + continue; + } + + std::optional> unlink_limits; + if (auto it = m_uv_unlink_limits.find(i); it != m_uv_unlink_limits.end()) + unlink_limits = it->second; + + for (int j = 0; j < R; ++j) { + if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end()) + continue; + m_solver_lower_bounds->add_edge(i, L + j, 1); + } + } + + // r -> group + for (int j = 0; j < R; ++j) { + int g = r_nodes_group[j]; + m_solver_lower_bounds->add_edge(L + j, L + R + g, 1); + } + + // group -> sink (lower bound = 1) + for (int g = 0; g < num_groups; ++g) { + if (no_lower_groups.count(g)) + m_solver_lower_bounds->add_edge(L + R + g, m_solver_lower_bounds->sink_id, R); + else + add_edge_with_lower_bound(L + R + g, m_solver_lower_bounds->sink_id, 1, R, 0); + } + + max_flow_edges = m_solver_lower_bounds->edges.size(); + + // support lower bounds, add super source super sink + super_source = m_solver_lower_bounds->total_nodes++; + super_sink = m_solver_lower_bounds->total_nodes++; + + m_solver_lower_bounds->adj.resize(m_solver_lower_bounds->total_nodes); + demand.resize(m_solver_lower_bounds->total_nodes, 0); + + for (int i = 0; i < super_source; ++i) { + if (demand[i] > 0) { + m_solver_lower_bounds->add_edge(super_source, i, demand[i]); + } else if (demand[i] < 0) { + m_solver_lower_bounds->add_edge(i, super_sink, -demand[i]); + } + } + m_solver_lower_bounds->add_edge(m_solver_lower_bounds->sink_id, m_solver_lower_bounds->source_id, MaxFlowGraph::INF); + source_id = m_solver_lower_bounds->source_id; + sink_id = m_solver_lower_bounds->sink_id; + m_solver_lower_bounds->source_id = super_source; + m_solver_lower_bounds->sink_id = super_sink; + } + + void GeneralMinCostLowerBoundsSolver::build_graph_with_feasible_result() + { + for (auto&lb:lower_bound_edges){ + m_solver_lower_bounds->edges[lb.edge_id].flow += lb.lower; + m_solver_lower_bounds->edges[lb.edge_id ^ 1].flow -= lb.lower; + } + + m_solver_min_cost->l_nodes = m_solver_lower_bounds->l_nodes; + m_solver_min_cost->r_nodes = m_solver_lower_bounds->r_nodes; + + m_solver_min_cost->source_id = source_id; + m_solver_min_cost->sink_id = sink_id; + m_solver_min_cost->total_nodes = sink_id + 1; + + m_solver_min_cost->edges = m_solver_lower_bounds->edges; + m_solver_min_cost->edges.erase(m_solver_min_cost->edges.begin() + max_flow_edges, m_solver_min_cost->edges.end()); + + m_solver_min_cost->adj = m_solver_lower_bounds->adj; + m_solver_min_cost->adj.resize(m_solver_min_cost->total_nodes); + for (auto &node_edges : m_solver_min_cost->adj) { + node_edges.erase(std::remove_if(node_edges.begin(), node_edges.end(), [this](int val) {return val >= this->max_flow_edges;}), node_edges.end()); + } + + + for (auto& e : m_solver_min_cost->edges) { + int L = m_solver_min_cost->l_nodes.size(); + int R = m_solver_min_cost->r_nodes.size(); + + if (e.from < L && e.to >= L && e.to < L + R) { + int idx_in_left = e.from; + int idx_in_right = e.to - L; + int group_id = r_nodes_group[idx_in_right]; + + if (r_nodes[idx_in_right] == -1) continue; + e.cost = flush_matrix[group_id][l_nodes[idx_in_left]][r_nodes[idx_in_right]]; + } + } + } + void GeneralMinCostLowerBoundsSolver::add_edge_with_lower_bound(int from, int to, int lower, int upper, int cost) + { + int eid = m_solver_lower_bounds->edges.size(); + m_solver_lower_bounds->add_edge(from, to, upper - lower); + + lower_bound_edges.push_back({eid, lower}); + demand[from] -= lower; + demand[to] += lower; + } + +// ==================== GroupMinCostFlowSolver ==================== + GroupMinCostFlowSolver::~GroupMinCostFlowSolver() = default; + + GroupMinCostFlowSolver::GroupMinCostFlowSolver(const std::vector &matrix_, + const std::vector &u_nodes, + const std::vector &v_nodes, + const std::vector &v_nodes_group, + const std::unordered_map> &uv_link_limits, + const std::unordered_map> &uv_unlink_limits) + { + flush_matrix = matrix_; + l_nodes = u_nodes; + r_nodes = v_nodes; + r_nodes_group = v_nodes_group; + m_uv_link_limits = uv_link_limits; + m_uv_unlink_limits = uv_unlink_limits; + num_groups = *std::max_element(r_nodes_group.begin(), r_nodes_group.end()) + 1; + + m_solver = std::make_unique(); + build_graph(); + } + + int GroupMinCostFlowSolver::get_flush_cost(int l_idx, int r_idx) + { + if (r_nodes[r_idx] == -1) + return 0; + int group_id = r_nodes_group[r_idx]; + return (int)flush_matrix[group_id][l_nodes[l_idx]][r_nodes[r_idx]]; + } + + void GroupMinCostFlowSolver::build_graph() + { + const int L = (int)l_nodes.size(); + const int R = (int)r_nodes.size(); + const int G = num_groups; + + m_solver->l_nodes = l_nodes; + m_solver->r_nodes = r_nodes; + m_solver->total_nodes = L + R + G + 2; + m_solver->source_id = L + R + G; + m_solver->sink_id = L + R + G + 1; + m_solver->adj.resize(m_solver->total_nodes); + + int max_flush = 0; + for (const auto &mat : flush_matrix) + for (const auto &row : mat) + for (float v : row) + max_flush = std::max(max_flush, (int)v); + int bonus = max_flush * L + 1; + + // source -> l_i + for (int i = 0; i < L; ++i) + m_solver->add_edge(m_solver->source_id, i, 1, 0); + + // l_i -> r_j (with link/unlink limits) + for (int i = 0; i < L; ++i) { + if (auto it = m_uv_link_limits.find(i); it != m_uv_link_limits.end()) { + for (int j : it->second) + m_solver->add_edge(i, L + j, 1, get_flush_cost(i, j)); + continue; + } + + std::optional> unlink_limits; + if (auto it = m_uv_unlink_limits.find(i); it != m_uv_unlink_limits.end()) + unlink_limits = it->second; + + for (int j = 0; j < R; ++j) { + if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end()) + continue; + m_solver->add_edge(i, L + j, 1, get_flush_cost(i, j)); + } + } + + // r_j -> group_g + // Compute per-nozzle incoming edge count as capacity upper bound. + // When unlink_limits restrict multiple filaments to the same nozzle, + // capacity=1 would block valid assignments. Using the actual in-degree + // allows the necessary flow while still preserving nozzle-level balance + // (a nozzle with fewer forced filaments keeps a tighter cap). + // The first unit carries a small nozzle-bonus to encourage spreading + // filaments across distinct nozzles within the same group. + int nozzle_bonus = max_flush + 1; + std::vector r_in_degree(R, 0); + for (int i = 0; i < L; ++i) { + if (auto it = m_uv_link_limits.find(i); it != m_uv_link_limits.end()) { + for (int j : it->second) + r_in_degree[j]++; + continue; + } + std::optional> unlink_limits; + if (auto it = m_uv_unlink_limits.find(i); it != m_uv_unlink_limits.end()) + unlink_limits = it->second; + for (int j = 0; j < R; ++j) { + if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end()) + continue; + r_in_degree[j]++; + } + } + + for (int j = 0; j < R; ++j) { + int g = r_nodes_group[j]; + int cap = std::max(r_in_degree[j], 1); + // First unit gets -nozzle_bonus to prefer using distinct nozzles + m_solver->add_edge(L + j, L + R + g, 1, -nozzle_bonus); + if (cap > 1) + m_solver->add_edge(L + j, L + R + g, cap - 1, 0); + } + + // group_g -> sink (split: first unit gets -bonus, rest gets 0) + // bonus >> nozzle_bonus, so group coverage always takes priority + for (int g = 0; g < G; ++g) { + m_solver->add_edge(L + R + g, m_solver->sink_id, 1, -bonus); + if (L > 1) + m_solver->add_edge(L + R + g, m_solver->sink_id, L - 1, 0); + } + } + + std::vector GroupMinCostFlowSolver::solve() + { + return m_solver->solve(); + } + +// ==================== MinFlushFlowSolver ==================== MinFlushFlowSolver::~MinFlushFlowSolver() { } @@ -277,7 +667,8 @@ namespace Slic3r const std::unordered_map>& uv_link_limits, const std::unordered_map>& uv_unlink_limits, const std::vector& u_capacity, - const std::vector& v_capacity) + const std::vector& v_capacity, + const std::vector,int>>&v_group_capacity) { assert(u_capacity.empty() || u_capacity.size() == u_nodes.size()); assert(v_capacity.empty() || v_capacity.size() == v_nodes.size()); @@ -286,13 +677,19 @@ namespace Slic3r m_solver->l_nodes = u_nodes; m_solver->r_nodes = v_nodes; - m_solver->total_nodes = u_nodes.size() + v_nodes.size() + 2; + m_solver->total_nodes = u_nodes.size() + v_nodes.size() + v_group_capacity.size() + 2; m_solver->source_id =m_solver->total_nodes - 2; m_solver->sink_id = m_solver->total_nodes - 1; m_solver->adj.resize(m_solver->total_nodes); + std::vector v_node_to(v_nodes.size(), m_solver->sink_id); + for (size_t gid = 0; gid < v_group_capacity.size(); ++gid) { + for (auto vid : v_group_capacity[gid].first) + v_node_to[vid] = m_solver->l_nodes.size() + m_solver->r_nodes.size() + gid; + } + // add edge from source to left nodes,cost to 0 for (int i = 0; i < m_solver->l_nodes.size(); ++i) { int capacity = u_capacity.empty() ? 1 : u_capacity[i]; @@ -301,7 +698,12 @@ namespace Slic3r // add edge from right nodes to sink,cost to 0 for (int i = 0; i < m_solver->r_nodes.size(); ++i) { int capacity = v_capacity.empty() ? 1 : v_capacity[i]; - m_solver->add_edge(m_solver->l_nodes.size() + i, m_solver->sink_id, capacity, 0); + m_solver->add_edge(m_solver->l_nodes.size() + i, v_node_to[i], capacity, 0); + } + // add edge from temp group node to sink node + for(int i=0;iadd_edge(m_solver->l_nodes.size() + m_solver->r_nodes.size() + i, m_solver->sink_id, capacity, 0); } // add edge from left node to right nodes for (int i = 0; i < m_solver->l_nodes.size(); ++i) { @@ -602,12 +1004,125 @@ namespace Slic3r } + // Single-nozzle flush-minimizing reorder over one filament set / one flush matrix, with an + // optional seed filament. Extracted from the group loop so the multi-nozzle reorder can call it + // per physical nozzle. + // TODO: add custom sequence + static int reorder_filaments_for_minimum_flush_volume_base(const std::vector& filament_lists, + const std::vector>& layer_filaments, + const FlushMatrix& flush_matrix, + const std::function&)> get_custom_seq, + std::vector>* filament_sequences, + std::optional initial_filament_id = std::nullopt) + { + constexpr int max_n_with_forcast = 5; + using uint128_t = boost::multiprecision::uint128_t; + + if (filament_sequences) { + filament_sequences->clear(); + filament_sequences->reserve(layer_filaments.size()); + } + auto filament_list_to_hash_key = [](const std::vector& curr_layer_filaments, const std::vector& next_layer_filaments, + const std::optional& prev_filament, bool use_forcast) -> uint128_t { + uint128_t hash_key = 0; + // 31-0 bit define current layer extruder,63-32 bit define next layer extruder,95~64 define prev extruder + if (prev_filament) hash_key |= (uint128_t(1) << (64 + *prev_filament)); + + if (use_forcast) { + for (auto item : next_layer_filaments) { hash_key |= (uint128_t(1) << (32 + item)); } + } + + for (auto item : curr_layer_filaments) { hash_key |= (uint128_t(1) << item); } + return hash_key; + }; + + int cost = 0; + std::map> custom_layer_sequence_map; + std::unordered_map>> caches; + std::unordered_set filament_sets(filament_lists.begin(), filament_lists.end()); + std::optional curr_filament_id; + // use the provided initial filament id as the starting state when it is valid + if (initial_filament_id.has_value() && *initial_filament_id < flush_matrix.size()) { + curr_filament_id = initial_filament_id; + } + + for (size_t layer = 0; layer < layer_filaments.size(); ++layer){ + const auto& curr_lf = layer_filaments[layer]; + std::vector custom_filament_seq; + if (get_custom_seq && get_custom_seq(layer, custom_filament_seq) && !custom_filament_seq.empty()) { + std::vector unsign_custom_extruder_seq; + for (int extruder : custom_filament_seq) { + unsigned int unsign_extruder = static_cast(extruder) - 1; + auto it = std::find(layer_filaments[layer].begin(), layer_filaments[layer].end(), unsign_extruder); + if (it != layer_filaments[layer].end()) + unsign_custom_extruder_seq.emplace_back(unsign_extruder); + } + assert(layer_filaments[layer].size() == unsign_custom_extruder_seq.size()); + + custom_layer_sequence_map[layer] = unsign_custom_extruder_seq; + } + } + + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { + const auto& curr_lf = layer_filaments[layer]; + + if(auto iter = custom_layer_sequence_map.find(layer); iter != custom_layer_sequence_map.end()){ + auto sequence_in_group = collect_filaments_in_groups(std::unordered_set(filament_lists.begin(),filament_lists.end()), iter->second); + + std::optional prev = curr_filament_id; + for (auto& f: sequence_in_group){ + if(prev) + cost += flush_matrix[*prev][f]; + prev = f; + } + + if(!sequence_in_group.empty()){ + curr_filament_id = sequence_in_group.back(); + } + + if(filament_sequences) + filament_sequences->emplace_back(sequence_in_group); + + continue; + } + + std::vector filament_used = collect_filaments_in_groups(filament_sets, curr_lf); + std::vector next_lf; + if (layer + 1 < layer_filaments.size()) next_lf = layer_filaments[layer + 1]; + std::vector filament_used_next_layer = collect_filaments_in_groups(filament_sets, next_lf); + + bool use_forcast = false; + float tmp_cost = 0; + std::vector sequence; + uint128_t hash_key = filament_list_to_hash_key(filament_used, filament_used_next_layer, curr_filament_id, use_forcast); + if (auto iter = caches.find(hash_key); iter != caches.end()) { + tmp_cost = iter->second.first; + sequence = iter->second.second; + } + else { + sequence = get_extruders_order(flush_matrix, filament_used, filament_used_next_layer, curr_filament_id, use_forcast, &tmp_cost); + caches[hash_key] = { tmp_cost,sequence }; + } + + if (filament_sequences) + filament_sequences->emplace_back(sequence); + + if (!sequence.empty()) + curr_filament_id = sequence.back(); + + cost += tmp_cost; + } + + return cost; + } + int reorder_filaments_for_minimum_flush_volume(const std::vector& filament_lists, const std::vector& filament_maps, const std::vector>& layer_filaments, const std::vector& flush_matrix, std::optional&)>> get_custom_seq, - std::vector>* filament_sequences) + std::vector>* filament_sequences, + const std::unordered_map& nozzle_status) { //only when layer filament num <= 5,we do forcast constexpr int max_n_with_forcast = 5; @@ -670,6 +1185,12 @@ namespace Slic3r if (groups[idx].empty()) continue; std::optionalcurrent_extruder_id; + // seed the group (nozzle) with the filament already loaded, if nozzle_status supplies one + if (auto it = nozzle_status.find(static_cast(idx)); it != nozzle_status.end() && it->second >= 0) { + unsigned int initial_fil = static_cast(it->second); + if (initial_fil < flush_matrix[idx].size()) + current_extruder_id = initial_fil; + } std::unordered_map>> caches; @@ -775,4 +1296,174 @@ namespace Slic3r return cost; } + + int reorder_filaments_for_multi_nozzle_extruder(const std::vector& filament_lists, + const MultiNozzleUtils::LayeredNozzleGroupResult& nozzle_group_result, + const std::vector>& layer_filaments, + const std::vector& flush_matrix, + const std::function&)> get_custom_seq, + std::vector>* filament_sequences, + const MultiNozzleUtils::NozzleStatusRecorder& initial_status) + { + std::map> nozzle_filament_groups; + std::map> extruder_to_nozzle; + + for(auto filament_idx : filament_lists){ + auto nozzle_info = nozzle_group_result.get_nozzle_for_filament(filament_idx, -1); + if (!nozzle_info) + continue; + nozzle_filament_groups[nozzle_info->group_id].insert(filament_idx); + extruder_to_nozzle[nozzle_info->extruder_id].insert(nozzle_info->group_id); + } + + std::map>custom_layer_sequence_map;// save the filament sequences of custom layer + for (size_t layer = 0; layer < layer_filaments.size(); ++layer){ + const auto& curr_lf = layer_filaments[layer]; + std::vector custom_filament_seq; + if (get_custom_seq && get_custom_seq(layer, custom_filament_seq) && !custom_filament_seq.empty()) { + std::vector unsign_custom_extruder_seq; + for (int extruder : custom_filament_seq) { + unsigned int unsign_extruder = static_cast(extruder) - 1; + auto it = std::find(layer_filaments[layer].begin(), layer_filaments[layer].end(), unsign_extruder); + if (it != layer_filaments[layer].end()) + unsign_custom_extruder_seq.emplace_back(unsign_extruder); + } + assert(layer_filaments[layer].size() == unsign_custom_extruder_seq.size()); + + custom_layer_sequence_map[layer] = unsign_custom_extruder_seq; + } + } + + + std::map>> nozzle_filament_sequences; + bool store_sequence = filament_sequences != nullptr; + + int cost = 0; + for(auto& group : nozzle_filament_groups){ + int nozzle_id = group.first; + auto& filament_in_nozzle = group.second; + + int extruder_id = 0; + for(auto& [ext, nozzle_set] : extruder_to_nozzle){ + if(nozzle_set.count(nozzle_id)){ + extruder_id = ext; + break; + } + } + + if(filament_in_nozzle.empty()) + continue; + + std::vector filament_vec_in_nozzle(filament_in_nozzle.begin(), filament_in_nozzle.end()); + + int initial_fil = initial_status.get_filament_in_nozzle(nozzle_id); + std::optional initial_fil_id = (initial_fil >= 0 && initial_fil < flush_matrix[extruder_id].size())? std::optional(initial_fil) : std::nullopt; + + std::vector> filament_seq; + cost += reorder_filaments_for_minimum_flush_volume_base(filament_vec_in_nozzle, layer_filaments, flush_matrix[extruder_id], get_custom_seq, + store_sequence ? &filament_seq : nullptr, initial_fil_id); + if(store_sequence) + nozzle_filament_sequences.emplace(nozzle_id, std::move(filament_seq)); + + } + + if(!store_sequence) + return cost; + + std::vector extruders; + std::map> nozzles_per_extruder; + for (auto& [extruder_id, nozzle_set] : extruder_to_nozzle) { + extruders.push_back(extruder_id); + nozzles_per_extruder[extruder_id] = std::vector( + nozzle_set.begin(), nozzle_set.end() + ); + } + + filament_sequences->clear(); + filament_sequences->resize(layer_filaments.size()); + + // No filament in filament_lists resolved to a nozzle in nozzle_group_result + // (e.g. a degenerate input where a layer references a filament index outside the range's + // grouping map). Emit each layer's filaments in their given order so the caller still gets a + // valid per-layer sequence, and skip the cross-nozzle reorder. Guards the unchecked + // max_element(extruders) below, which would dereference end() on an empty range. + if (extruders.empty()) { + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) + (*filament_sequences)[layer] = layer_filaments[layer]; + return cost; + } + + auto get_extruder_for_filament = [nozzle_group_result](unsigned int filament_idx) { + auto nozzle = nozzle_group_result.get_nozzle_for_filament(filament_idx, -1); + if (!nozzle) + return -1; + return nozzle->extruder_id; + }; + + auto get_nozzle_idx_for_filament = [nozzles_per_extruder, nozzle_group_result](unsigned int filament_idx)->int { + auto nozzle = nozzle_group_result.get_nozzle_for_filament(filament_idx, -1); + if (!nozzle) + return -1; + return std::find(nozzles_per_extruder.at(nozzle->extruder_id).begin(), nozzles_per_extruder.at(nozzle->extruder_id).end(), nozzle->group_id) - nozzles_per_extruder.at(nozzle->extruder_id).begin(); + }; + + int initial_extruder = initial_status.get_current_extruder_id(); + int last_extruder_idx = (initial_extruder >= 0 && initial_extruder < extruders.size())? initial_extruder : 0; + // set size to max extruder_id in case extruder_id is not continuous + std::vector last_nozzle_idx(*std::max_element(extruders.begin(),extruders.end()) + 1,0); + for (int ext_id = 0; ext_id < static_cast(last_nozzle_idx.size()); ext_id++) { + int initial_nozzle = initial_status.get_nozzle_in_extruder(ext_id); + auto ext_nozzles = nozzles_per_extruder[ext_id]; + auto it = std::find(ext_nozzles.begin(), ext_nozzles.end(), initial_nozzle); + if (it != ext_nozzles.end()) + last_nozzle_idx[ext_id] = static_cast(std::distance(ext_nozzles.begin(), it)); + } + + for (size_t layer = 0; layer < layer_filaments.size(); ++layer) { + auto& out_seq = (*filament_sequences)[layer]; + + if (custom_layer_sequence_map.find(layer) != custom_layer_sequence_map.end()) { + out_seq = custom_layer_sequence_map[layer]; + if (!out_seq.empty()) { + last_extruder_idx = get_extruder_for_filament(out_seq.back()); + for (auto filament : out_seq) { + int cur_ext_id = get_extruder_for_filament(filament); + last_nozzle_idx[cur_ext_id] = get_nozzle_idx_for_filament(filament); + } + } + continue; + } + + if (last_extruder_idx == -1) + last_extruder_idx = 0; + + int curr_last_extruder_idx = last_extruder_idx; + auto curr_last_nozzle_idx = last_nozzle_idx; + for (int i = 0; i < extruders.size(); ++i) { + int extruder_id = extruders[(last_extruder_idx + i) % extruders.size()]; + auto& base_nozzles = nozzles_per_extruder[extruder_id]; + + bool has_seq = false; + if (last_nozzle_idx[extruder_id] == -1) + last_nozzle_idx[extruder_id] = 0; + + for (int j = 0; j < base_nozzles.size(); ++j) { + int nozzle_idx = (last_nozzle_idx[extruder_id] + j) % base_nozzles.size(); + int nozzle_id = base_nozzles[nozzle_idx]; + const auto& frag = nozzle_filament_sequences[nozzle_id][layer]; + if (frag.empty()) + continue; + has_seq = true; + curr_last_nozzle_idx[extruder_id] = nozzle_idx; + out_seq.insert(out_seq.end(), frag.begin(), frag.end()); + } + + if (has_seq) + curr_last_extruder_idx = extruder_id; + } + last_extruder_idx = curr_last_extruder_idx; + last_nozzle_idx = curr_last_nozzle_idx; + } + return cost; + } } diff --git a/src/libslic3r/GCode/ToolOrderUtils.hpp b/src/libslic3r/GCode/ToolOrderUtils.hpp index 26c9a01186..7b103531b1 100644 --- a/src/libslic3r/GCode/ToolOrderUtils.hpp +++ b/src/libslic3r/GCode/ToolOrderUtils.hpp @@ -6,7 +6,10 @@ #include #include #include +#include #include +#include +#include "../MultiNozzleUtils.hpp" namespace Slic3r { @@ -15,21 +18,27 @@ using FlushMatrix = std::vector>; namespace MaxFlowGraph { const int INF = std::numeric_limits::max(); const int INVALID_ID = -1; + // Upper bound for MCMF edge cost to prevent int overflow in SPFA causing infinite loops + constexpr int MCMF_MAX_EDGE_COST = 10000000; } +// Namespace-scope edge shared by the max-flow / min-cost-max-flow solvers below. +// The default cost keeps the plain max-flow solvers (which never read cost) source-compatible. +struct Edge +{ + int from, to, capacity, cost, flow; + Edge(int u, int v, int cap, int cst = 0) : from(u), to(v), capacity(cap), cost(cst), flow(0) {} +}; + class MaxFlowSolver { -private: - struct Edge { - int from, to, capacity, flow; - Edge(int u, int v, int cap) :from(u), to(v), capacity(cap), flow(0) {} - }; public: MaxFlowSolver(const std::vector& u_nodes, const std::vector& v_nodes, const std::unordered_map>& uv_link_limits = {}, const std::unordered_map>& uv_unlink_limits = {}, const std::vector& u_capacity = {}, - const std::vector& v_capacity = {} + const std::vector& v_capacity = {}, + const std::vector, int>>& v_group_capacity = {} ); std::vector solve(); @@ -47,6 +56,7 @@ private: struct MinCostMaxFlow; +struct MaxFlowWithLowerBounds; class GeneralMinCostSolver { @@ -61,6 +71,84 @@ private: std::unique_ptr m_solver; }; +class GeneralMinCostLowerBoundsSolver +{ +public: + GeneralMinCostLowerBoundsSolver( + const std::vector &matrix_, + const std::vector& u_nodes, + const std::vector& v_nodes, + const std::vector& v_nodes_group, + const std::unordered_map>& uv_link_limits = {}, + const std::unordered_map>& uv_unlink_limits = {}); + + std::vector solve(); + ~GeneralMinCostLowerBoundsSolver(); + +private: + void build_feasible_graph(const std::unordered_set& no_lower_groups); + + void build_graph_with_feasible_result(); + + void add_edge_with_lower_bound(int from, int to, int lower, int upper, int cost); + + int get_distance(const int idx_in_left,const int idx_in_right); + +private: + std::unique_ptr m_solver_lower_bounds; + std::unique_ptr m_solver_min_cost; + + std::vector flush_matrix; + std::vector l_nodes; + std::vector r_nodes; + std::vector r_nodes_group; + std::unordered_map> m_uv_link_limits; + std::unordered_map> m_uv_unlink_limits; + int num_groups = 0; + + // support lower bounds + struct LowerBoundEdge{ + int edge_id; + int lower; + }; + + std::vector demand; + std::vector lower_bound_edges; + + int super_source = -1; + int super_sink = -1; + int source_id = -1; + int sink_id = -1; + int max_flow_edges = 0; +}; + +class GroupMinCostFlowSolver +{ +public: + GroupMinCostFlowSolver( + const std::vector &matrix_, + const std::vector &u_nodes, + const std::vector &v_nodes, + const std::vector &v_nodes_group, + const std::unordered_map> &uv_link_limits = {}, + const std::unordered_map> &uv_unlink_limits = {}); + + std::vector solve(); + ~GroupMinCostFlowSolver(); + +private: + void build_graph(); + int get_flush_cost(int l_idx, int r_idx); + + std::unique_ptr m_solver; + std::vector flush_matrix; + std::vector l_nodes; + std::vector r_nodes; + std::vector r_nodes_group; + std::unordered_map> m_uv_link_limits; + std::unordered_map> m_uv_unlink_limits; + int num_groups = 0; +}; class MinFlushFlowSolver { @@ -71,7 +159,8 @@ public: const std::unordered_map>& uv_link_limits = {}, const std::unordered_map>& uv_unlink_limits = {}, const std::vector& u_capacity = {}, - const std::vector& v_capacity = {} + const std::vector& v_capacity = {}, + const std::vector, int>>& v_group_capacity = {} ); std::vector solve(); ~MinFlushFlowSolver(); @@ -108,7 +197,19 @@ int reorder_filaments_for_minimum_flush_volume(const std::vector & const std::vector> &layer_filaments, const std::vector &flush_matrix, std::optional &)>> get_custom_seq, - std::vector> *filament_sequences); + std::vector> *filament_sequences, + const std::unordered_map& nozzle_status = {}); + +// Order filaments within a per-nozzle grouping result (multi-nozzle extruders). Threads a +// NozzleStatusRecorder describing the initial physical nozzle occupancy so the reorder can reward +// keeping an already-loaded filament in place. +int reorder_filaments_for_multi_nozzle_extruder(const std::vector& filament_lists, + const MultiNozzleUtils::LayeredNozzleGroupResult& nozzle_group_result, + const std::vector>& layer_filaments, + const std::vector& flush_matrix, + const std::function&)> get_custom_seq, + std::vector> * filament_sequences, + const MultiNozzleUtils::NozzleStatusRecorder& initial_status = {}); } #endif // !TOOL_ORDER_UTILS_HPP diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 5cb66ba5e5..e36c177a90 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -6,8 +6,12 @@ #include "ParameterUtils.hpp" #include "GCode/ToolOrderUtils.hpp" #include "FilamentGroupUtils.hpp" +#include "MultiNozzleUtils.hpp" +#include "Utils.hpp" #include "I18N.hpp" +#include + // #define SLIC3R_DEBUG // Make assert active if SLIC3R_DEBUG @@ -149,26 +153,47 @@ static double calc_max_layer_height(const PrintConfig &config, double max_object } //calculate the flush weight (first value) and filament change count(second value) -static FilamentChangeStats calc_filament_change_info_by_toolorder(const PrintConfig* config, const std::vector& filament_map, const std::vector& flush_matrix, const std::vector>& layer_sequences) +// Nozzle-aware flush-stat calculator. Resolves each +// filament in the print sequence to its physical nozzle via the grouping result and tracks a +// per-nozzle NozzleStatusRecorder, so flush weight and flush_filament_change_count are charged +// per physical nozzle. For single-nozzle-per-extruder printers (H2D/X1/...) nozzle_id == extruder_id, +// so every returned value is identical to the extruder-level calculation. Out-of-range +// filament ids resolve to no nozzle and are skipped. +static FilamentChangeStats calc_filament_change_info_by_toolorder(const PrintConfig* config, const MultiNozzleUtils::LayeredNozzleGroupResult& group_result, const std::vector& flush_matrix, const std::vector>& layer_sequences) { FilamentChangeStats ret; std::unordered_map flush_volume_per_filament; - int max_extruder_id = *std::max_element(filament_map.begin(), filament_map.end()); - assert(max_extruder_id >= 0); - std::vectorlast_filament_per_extruder(max_extruder_id + 1, -1); + MultiNozzleUtils::NozzleStatusRecorder recorder; int total_filament_change_count = 0; + int total_flush_filament_change_count = 0; float total_filament_flush_weight = 0; - for (const auto& ls : layer_sequences) { - for (const auto& item : ls) { - int extruder_id = filament_map[item]; - int last_filament = last_filament_per_extruder[extruder_id]; - if (last_filament != -1 && last_filament != item) { - int flush_volume = flush_matrix[extruder_id][last_filament][item]; - flush_volume_per_filament[item] += flush_volume; - total_filament_change_count += 1; + + int old_filament_id = -1; + for (size_t layer_idx = 0; layer_idx < layer_sequences.size(); ++layer_idx) { + const auto& ls = layer_sequences[layer_idx]; + for (const auto& filament : ls) { + auto nozzle = group_result.get_nozzle_for_filament(filament, layer_idx); + if (!nozzle) + continue; + + int new_extruder_id = nozzle->extruder_id; + int new_nozzle_id_in_extruder = nozzle->group_id; + int new_filament_id_in_nozzle = filament; + int old_filament_id_in_nozzle = recorder.get_filament_in_nozzle(new_nozzle_id_in_extruder); + + bool filament_in_nozzle_change = old_filament_id_in_nozzle != -1 && new_filament_id_in_nozzle != old_filament_id_in_nozzle; + bool filament_change = old_filament_id != -1 && old_filament_id != new_filament_id_in_nozzle; + + if (filament_in_nozzle_change) { + total_flush_filament_change_count++; + int flush_volume = flush_matrix[new_extruder_id][old_filament_id_in_nozzle][new_filament_id_in_nozzle]; + flush_volume_per_filament[filament] += flush_volume; } - last_filament_per_extruder[extruder_id] = item; + if (filament_change) + total_filament_change_count++; + old_filament_id = new_filament_id_in_nozzle; + recorder.set_nozzle_status(new_nozzle_id_in_extruder, new_filament_id_in_nozzle, new_extruder_id); } } @@ -177,8 +202,9 @@ static FilamentChangeStats calc_filament_change_info_by_toolorder(const PrintCon total_filament_flush_weight += weight; } - ret.filament_change_count = total_filament_change_count; - ret.filament_flush_weight = (int)total_filament_flush_weight; + ret.filament_change_count = total_filament_change_count; + ret.flush_filament_change_count = total_flush_filament_change_count; + ret.filament_flush_weight = (int)total_filament_flush_weight; return ret; } @@ -1104,27 +1130,47 @@ float get_flush_volume(const std::vector &filament_maps, const std::vector< return flush_volume; } -std::vector ToolOrdering::get_recommended_filament_maps(const std::vector>& layer_filaments, const Print* print, const FilamentMapMode mode,const std::vector>&physical_unprintables,const std::vector>&geometric_unprintables) +// Forward declaration — the single-nozzle-per-extruder nozzle list (defined below). +static std::vector build_default_nozzle_list(const PrintConfig &print_config, size_t extruder_nums); + +// Best-effort readers for the multi-nozzle dev config keys. These are registered in the ConfigDef +// but not (yet) static PrintConfig members, so the slicing PrintConfig reads them as inert defaults, +// which keeps the auto grouping path bit-exact (all these degrade to the flush-only, non-switcher, +// hybrid-flow case). +static bool cfg_bool(const ConfigBase& c, const char* key, bool def) { - using namespace FilamentGroupUtils; - if (!print || layer_filaments.empty()) - return std::vector(); + if (auto* o = c.option(key)) return o->value; + return def; +} +static double cfg_float(const ConfigBase& c, const char* key, double def) +{ + if (auto* o = c.option(key)) return o->value; + return def; +} +static std::vector cfg_ints(const ConfigBase& c, const char* key) +{ + if (auto* o = c.option(key)) return o->values; + return {}; +} - const auto& print_config = print->config(); - const unsigned int filament_nums = (unsigned int)(print_config.filament_colour.values.size() + EPSILON); - - // get flush matrix - std::vector nozzle_flush_mtx; +// Prepare per-extruder flush matrices. The prime_volume_mode==pvmFast branch: Default reads +// flush_multiplier, Fast reads flush_multiplier_fast. +static std::vector prepare_flush_matrices(const PrintConfig& print_config) +{ size_t extruder_nums = print_config.nozzle_diameter.values.size(); + size_t filament_nums = print_config.filament_colour.values.size(); + std::vector nozzle_flush_mtx; for (size_t nozzle_id = 0; nozzle_id < extruder_nums; ++nozzle_id) { - std::vector flush_matrix(cast(get_flush_volumes_matrix(print_config.flush_volumes_matrix.values, nozzle_id, extruder_nums))); + std::vector flush_matrix(cast(get_flush_volumes_matrix(print_config.flush_volumes_matrix.values, nozzle_id, extruder_nums))); std::vector> wipe_volumes; for (unsigned int i = 0; i < filament_nums; ++i) wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * filament_nums, flush_matrix.begin() + (i + 1) * filament_nums)); - nozzle_flush_mtx.emplace_back(wipe_volumes); } - auto flush_multiplies = print_config.flush_multiplier.values; + + // Fast purge mode uses flush_multiplier_fast; Default is inert. + auto flush_multiplies = (print_config.prime_volume_mode == PrimeVolumeMode::pvmFast) ? print_config.flush_multiplier_fast.values + : print_config.flush_multiplier.values; flush_multiplies.resize(extruder_nums, 1); for (size_t nozzle_id = 0; nozzle_id < extruder_nums; ++nozzle_id) { for (auto& vec : nozzle_flush_mtx[nozzle_id]) { @@ -1132,88 +1178,355 @@ std::vector ToolOrdering::get_recommended_filament_maps(const std::vector other_layers_seqs = get_other_layers_print_sequence(print_config.other_layers_print_sequence_nums.value, print_config.other_layers_print_sequence.values); - - // other_layers_seq: the layer_idx and extruder_idx are base on 1 - auto get_custom_seq = [&other_layers_seqs](int layer_idx, std::vector& out_seq) -> bool { - for (size_t idx = other_layers_seqs.size() - 1; idx != size_t(-1); --idx) { - const auto& other_layers_seq = other_layers_seqs[idx]; - if (layer_idx + 1 >= other_layers_seq.first.first && layer_idx + 1 <= other_layers_seq.first.second) { - out_seq = other_layers_seq.second; - return true; +// Per-extruder physical nozzle groups. +// Orca: bounds-guards the nozzle_volume_type / extruder_max_nozzle_count arrays, which may be +// shorter than the extruder count on some profiles. +static std::vector build_nozzle_groups(const PrintConfig& print_config, size_t extruder_nums) +{ + std::vector nozzle_groups; + auto extruder_nozzle_counts = get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values); + const auto& nozzle_volume_types = print_config.nozzle_volume_type.values; + for (size_t idx = 0; idx < extruder_nums; ++idx) { + std::string diameter = format_diameter_to_str(print_config.nozzle_diameter.values[idx]); + NozzleVolumeType vt = idx < nozzle_volume_types.size() ? NozzleVolumeType(nozzle_volume_types[idx]) : nvtStandard; + int max_count = idx < print_config.extruder_max_nozzle_count.values.size() ? print_config.extruder_max_nozzle_count.values[idx] : 1; + if (idx >= extruder_nozzle_counts.size() || extruder_nozzle_counts[idx].empty()) { + nozzle_groups.emplace_back(diameter, vt, (int)idx, max_count); + } else { + if (vt == nvtHybrid) { + for (auto& [volume_type, count] : extruder_nozzle_counts[idx]) + nozzle_groups.emplace_back(diameter, volume_type, (int)idx, count); + } else { + nozzle_groups.emplace_back(diameter, vt, (int)idx, extruder_nozzle_counts[idx][vt]); } } + } + return nozzle_groups; +} + +// Build the nozzle-centric FilamentGroupContext. +// Orca deviations, all inert for the shipping fleet: +// * no print->get_filament_usage_type() → FilamentInfo::usage_type stays ModelOnly (the default); +// * no print->get_filament_print_time() → speed_info.filament_print_time empty (TimeEvaluator → 0); +// * the fmmAutoForQuality and Bowden-PA-calibration limit blocks are omitted (Orca has no +// fmmAutoForQuality mode and no Calib_Params::has_bowden_extruder). +// prefer_non_model_filament (Bowden extruders) is all-false for the Direct-Drive BBL fleet, so the +// support-preference reward path stays dormant. +static FilamentGroupContext build_filament_group_context( + const Print* print, + const std::vector>& layer_filaments, + const std::vector>& physical_unprintables, + const std::vector>& geometric_unprintables, + const std::map>& unprintable_volumes, + FilamentMapMode mode, + const std::unordered_map& nozzle_status) +{ + using namespace MultiNozzleUtils; + using namespace FilamentGroupUtils; + + FilamentGroupContext context; + + const auto& print_config = print->config(); + const size_t filament_nums = print_config.filament_colour.values.size(); + const size_t extruder_nums = print_config.nozzle_diameter.values.size(); + bool has_multiple_nozzle = std::any_of(print_config.extruder_max_nozzle_count.values.begin(), print_config.extruder_max_nozzle_count.values.end(), + [](int v) { return v > 1; }); + + auto nozzle_flush_mtx = prepare_flush_matrices(print_config); + auto nozzle_groups = build_nozzle_groups(print_config, extruder_nums); + + std::vector> ext_unprintable_filaments; + collect_unprintable_limits(physical_unprintables, geometric_unprintables, ext_unprintable_filaments); + + bool ignore_ext_filament = false; + auto extruder_ams_counts = get_extruder_ams_count(print_config.extruder_ams_count.values); + std::vector group_size = calc_max_group_size(extruder_ams_counts, ignore_ext_filament); + + // When a filament switcher is connected, disable the AMS capacity limit for grouping. + const bool has_filament_switcher = cfg_bool(print_config, "has_filament_switcher", false); + if (has_filament_switcher) { + int total_filaments = (int)filament_nums; + for (auto& s : group_size) + s = std::max(s, total_filaments); + } + + std::vector prefer_non_model_filament(extruder_nums, false); + for (size_t idx = 0; idx < extruder_nums; ++idx) + if (idx < print_config.extruder_type.values.size()) + prefer_non_model_filament[idx] = (print_config.extruder_type.values[idx] == ExtruderType::etBowden); + + auto machine_filament_info = build_machine_filaments(print->get_extruder_filament_info(), extruder_ams_counts, ignore_ext_filament); + + std::vector filament_types = print_config.filament_type.values; + std::vector filament_colours = print_config.filament_colour.values; + std::vector filament_is_support = print_config.filament_is_support.values; + std::vector filament_ids = print_config.filament_ids.values; + + FGMode fg_mode = mode == FilamentMapMode::fmmAutoForMatch ? FGMode::MatchMode : FGMode::FlushMode; + context.model_info.flush_matrix = std::move(nozzle_flush_mtx); + context.model_info.unprintable_filaments = ext_unprintable_filaments; + context.model_info.layer_filaments = layer_filaments; + context.model_info.filament_ids = filament_ids; + context.model_info.unprintable_volumes = unprintable_volumes; + + for (size_t idx = 0; idx < filament_types.size(); ++idx) { + FilamentGroupUtils::FilamentInfo info; + info.color = filament_colours[idx]; + info.type = filament_types[idx]; + info.is_support = filament_is_support[idx]; + context.model_info.filament_info.emplace_back(std::move(info)); + } + + context.speed_info.group_with_time = cfg_bool(print_config, "group_algo_with_time", false); + context.speed_info.filament_change_time = print_config.machine_load_filament_time + print_config.machine_unload_filament_time; + context.speed_info.extruder_change_time = cfg_float(print_config, "machine_switch_extruder_time", 0.0); + { + double load_time = print_config.machine_load_filament_time; + double unload_time = print_config.machine_unload_filament_time; + context.speed_info.change_time_params.standard_load_time = static_cast(load_time); + context.speed_info.change_time_params.standard_unload_time = static_cast(unload_time); + context.speed_info.change_time_params.selector_load_time = static_cast(load_time / 2); + context.speed_info.change_time_params.selector_unload_time = static_cast(unload_time / 2); + } + + context.machine_info.machine_filament_info = machine_filament_info; + context.machine_info.max_group_size = std::move(group_size); + context.machine_info.master_extruder_id = print_config.master_extruder_id.value - 1; + context.machine_info.prefer_non_model_filament = prefer_non_model_filament; + + context.group_info.total_filament_num = (int)(filament_nums); + context.group_info.max_gap_threshold = 0.01; + context.group_info.strategy = FGStrategy::BestCost; + context.group_info.mode = fg_mode; + context.group_info.ignore_ext_filament = ignore_ext_filament; + context.group_info.has_filament_switcher = has_filament_switcher; + + // hybrid flow means no special per-filament nozzle-volume request. In manual mode we honour the + // config's per-filament volume map when it is present and correctly sized; otherwise (the key is + // not a static PrintConfig member) fall back to hybrid so rebuild_nozzle_unprintables + // never indexes out of range. + if (mode == FilamentMapMode::fmmManual) { + auto fvm = cfg_ints(print_config, "filament_volume_map"); + if (fvm.size() == filament_nums) + context.group_info.filament_volume_map = std::move(fvm); + else + context.group_info.filament_volume_map = std::vector(filament_nums, (int)(NozzleVolumeType::nvtHybrid)); + } else { + context.group_info.filament_volume_map = std::vector(filament_nums, (int)(NozzleVolumeType::nvtHybrid)); + } + + context.nozzle_info.nozzle_list = build_nozzle_list(nozzle_groups); + context.nozzle_info.extruder_nozzle_list = build_extruder_nozzle_list(context.nozzle_info.nozzle_list); + + if (context.nozzle_info.nozzle_list.empty()) + throw Slic3r::RuntimeError("No valid nozzle found. Please check nozzle count."); + + if (!nozzle_status.empty()) + context.nozzle_info.nozzle_status = nozzle_status; + + auto used_filaments = collect_sorted_used_filaments(layer_filaments); + + // add_volume_type_limits: only for single-nozzle-per-extruder machines (H2D and the like). A + // filament whose forbidden nozzle-volume-type matches an extruder's (only) nozzle becomes + // unprintable on that extruder; conflicts printable nowhere are dropped. + if (!has_multiple_nozzle) { + std::vector> ext_unprintable_filaments_with_volume = ext_unprintable_filaments; + for (auto& nozzle : context.nozzle_info.nozzle_list) { + for (auto fil_id : used_filaments) { + auto unprintable_vols = context.model_info.unprintable_volumes[fil_id]; + if (unprintable_vols.count(nozzle.volume_type) && nozzle.extruder_id >= 0 && nozzle.extruder_id < (int)ext_unprintable_filaments_with_volume.size()) + ext_unprintable_filaments_with_volume[nozzle.extruder_id].insert(fil_id); + } + } + for (auto fil_id : used_filaments) { + if (ext_unprintable_filaments_with_volume[0].count(fil_id) && ext_unprintable_filaments_with_volume[1].count(fil_id)) { + ext_unprintable_filaments_with_volume[0].erase(fil_id); + ext_unprintable_filaments_with_volume[1].erase(fil_id); + } + } + context.model_info.unprintable_filaments = ext_unprintable_filaments_with_volume; + } + + return context; +} + +// Orca: restore the master-extruder preference. Orca historically ran +// optimize_group_for_master_extruder / can_swap_groups after grouping so a light-filament print stays +// on the primary/master extruder. A weak in-enum penalty alone cannot overcome a pre-existing +// non-zero right-extruder self-flush term in the flush matrix (which otherwise pulls a lone filament +// onto the non-master extruder and changes H2D/H2C g-code). We re-apply the preference ONLY in this +// slicing wrapper — never in the FilamentGroup engine or the test harness — so existing prints keep +// their extruder assignment while the new engine's genuine multi-filament grouping deltas still land. +static bool can_swap_extruder_groups(int extruder_id_0, const std::set& group_0, int extruder_id_1, const std::set& group_1, const FilamentGroupContext& ctx) +{ + using namespace FilamentGroupUtils; + std::vector> extruder_unprintables(2); + { + std::vector> unprintable_filaments = ctx.model_info.unprintable_filaments; + if (unprintable_filaments.size() > 1) + remove_intersection(unprintable_filaments[0], unprintable_filaments[1]); + std::map> unplaceable_limits; + for (int group_id : {extruder_id_0, extruder_id_1}) + if (group_id >= 0 && group_id < (int)unprintable_filaments.size()) + for (auto f : unprintable_filaments[group_id]) + unplaceable_limits[f].emplace_back(group_id); + for (auto& elem : unplaceable_limits) sort_remove_duplicates(elem.second); + for (auto& elem : unplaceable_limits) + for (auto& eid : elem.second) { + if (eid == extruder_id_0) extruder_unprintables[0].insert(elem.first); + if (eid == extruder_id_1) extruder_unprintables[1].insert(elem.first); + } + } + for (auto fid : group_0) if (extruder_unprintables[1].count(fid) > 0) return false; + for (auto fid : group_1) if (extruder_unprintables[0].count(fid) > 0) return false; + const auto& mgs = ctx.machine_info.max_group_size; + if (extruder_id_0 < (int)mgs.size() && extruder_id_1 < (int)mgs.size() && + mgs[extruder_id_0] >= (int)group_0.size() && mgs[extruder_id_1] >= (int)group_1.size() && + (mgs[extruder_id_0] < (int)group_1.size() || mgs[extruder_id_1] < (int)group_0.size())) return false; + return true; +} + +// Balance a filament->nozzle map toward the master extruder (2-extruder machines only). If the +// non-master extruder holds strictly more used filaments than the master and the swap is valid, move +// each group's filaments onto nozzles of the opposite extruder. The exact nozzle within an extruder +// does not affect static g-code (which emits H-1), so re-nozzling round-robin is byte-safe. +static std::vector apply_master_extruder_preference(const FilamentGroupContext& ctx, const std::vector& used_filaments, std::vector nozzle_ret) +{ + const auto& extruder_nozzle_list = ctx.nozzle_info.extruder_nozzle_list; + int master = ctx.machine_info.master_extruder_id; + if (extruder_nozzle_list.size() != 2 || master < 0 || master > 1) return nozzle_ret; + int other = 1 - master; + if (extruder_nozzle_list.count(master) == 0 || extruder_nozzle_list.count(other) == 0) return nozzle_ret; + auto ext_of_nozzle = [&](int nid) -> int { + return (nid >= 0 && nid < (int)ctx.nozzle_info.nozzle_list.size()) ? ctx.nozzle_info.nozzle_list[nid].extruder_id : -1; + }; + std::set group_master, group_other; + for (auto fu : used_filaments) { + int f = (int)fu; + if (f >= (int)nozzle_ret.size()) continue; + int e = ext_of_nozzle(nozzle_ret[f]); + if (e == master) group_master.insert(f); + else if (e == other) group_other.insert(f); + } + if (group_other.size() > group_master.size() && + can_swap_extruder_groups(other, group_other, master, group_master, ctx)) { + const auto& master_nozzles = extruder_nozzle_list.at(master); + const auto& other_nozzles = extruder_nozzle_list.at(other); + if (!master_nozzles.empty() && !other_nozzles.empty()) { + int mi = 0, oi = 0; + for (auto f : group_other) nozzle_ret[f] = master_nozzles[(mi++) % master_nozzles.size()]; + for (auto f : group_master) nozzle_ret[f] = other_nozzles[(oi++) % other_nozzles.size()]; + } + } + return nozzle_ret; +} + +// Nozzle-centric grouping. Dispatches by FilamentMapMode and returns a nozzle-aware +// LayeredNozzleGroupResult. For single-extruder printers (X1/P1/A1/H2S) the grouping engine is not +// invoked — the trivial all-master map is wrapped in a single-nozzle result, so their g-code is +// unaffected. Multi-extruder (H2D) grouping runs the nozzle-centric FilamentGroup engine; +// multi-nozzle (H2C/A2L) resolves to a nozzle-granular result. +MultiNozzleUtils::LayeredNozzleGroupResult ToolOrdering::get_recommended_filament_maps(const std::vector>& layer_filaments, const Print* print, const FilamentMapMode mode, const std::vector>& physical_unprintables, const std::vector>& geometric_unprintables, const std::map>& unprintable_volumes, const std::unordered_map& nozzle_status) +{ + using namespace FilamentGroupUtils; + using namespace MultiNozzleUtils; + + if (!print || layer_filaments.empty()) + return LayeredNozzleGroupResult(); + + const auto& print_config = print->config(); + size_t filament_nums = print_config.filament_colour.values.size(); + size_t extruder_nums = print_config.nozzle_diameter.values.size(); + auto used_filaments = collect_sorted_used_filaments(layer_filaments); + bool has_multiple_nozzle = std::any_of(print_config.extruder_max_nozzle_count.values.begin(), print_config.extruder_max_nozzle_count.values.end(), + [](int v) { return v > 1; }); + bool has_multiple_extruder = extruder_nums > 1; + + auto nozzle_list = build_default_nozzle_list(print_config, extruder_nums); + + // Manual mode: build directly from the user's filament->extruder map. + if (mode == FilamentMapMode::fmmManual && !has_multiple_nozzle) { + auto manual_filament_map = print_config.filament_map.values; + std::transform(manual_filament_map.begin(), manual_filament_map.end(), manual_filament_map.begin(), [](int v) { return v - 1; }); + auto result = LayeredNozzleGroupResult::create(manual_filament_map, nozzle_list, used_filaments); + return result ? *result : LayeredNozzleGroupResult(); + } + + // Fully-manual mode: build the nozzle-granular result from the config nozzle map. + if (mode == FilamentMapMode::fmmNozzleManual) { + auto manual_filament_map = print_config.filament_map.values; + std::transform(manual_filament_map.begin(), manual_filament_map.end(), manual_filament_map.begin(), [](int v) { return v - 1; }); + float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : (float)print_config.nozzle_diameter.values.front(); + auto nozzle_result = LayeredNozzleGroupResult::create(used_filaments, manual_filament_map, cfg_ints(print_config, "filament_volume_map"), cfg_ints(print_config, "filament_nozzle_map"), get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter); + return nozzle_result ? *nozzle_result : LayeredNozzleGroupResult(); + } + + int master_extruder_id = print_config.master_extruder_id.value - 1; + std::vector ret(filament_nums, master_extruder_id); + + // Non-BBL multi-extruder printers do not support filament grouping: filament id == extruder id. + if (has_multiple_extruder && !print->is_BBL_printer()) { + for (size_t i = 0; i < filament_nums && i < extruder_nums; i++) + ret[i] = (int)i; + auto result_opt = LayeredNozzleGroupResult::create(ret, nozzle_list, used_filaments); + return result_opt ? *result_opt : LayeredNozzleGroupResult(); + } + + if (has_multiple_extruder || has_multiple_nozzle) { + auto context = build_filament_group_context(print, layer_filaments, physical_unprintables, geometric_unprintables, unprintable_volumes, mode, nozzle_status); + + // other_layers_seq custom-sequence lambda (1-based layer/extruder). Only threaded for the + // single-nozzle-per-extruder engine. + std::vector other_layers_seqs = get_other_layers_print_sequence(print_config.other_layers_print_sequence_nums.value, print_config.other_layers_print_sequence.values); + auto get_custom_seq = [other_layers_seqs](int layer_idx, std::vector& out_seq) -> bool { + for (size_t idx = other_layers_seqs.size() - 1; idx != size_t(-1); --idx) { + const auto& other_layers_seq = other_layers_seqs[idx]; + if (layer_idx + 1 >= other_layers_seq.first.first && layer_idx + 1 <= other_layers_seq.first.second) { + out_seq = other_layers_seq.second; + return true; + } + } + return false; }; - int master_extruder_id = print_config.master_extruder_id.value -1; // switch to 0 based idx - std::vectorret(filament_nums, master_extruder_id); - bool ignore_ext_filament = false; // TODO: read from config - // if mutli_extruder, calc group,otherwise set to 0 - if (extruder_nums == 2 && print->is_BBL_printer()) { - std::vector extruder_ams_count_str = print_config.extruder_ams_count.values; - auto extruder_ams_counts = get_extruder_ams_count(extruder_ams_count_str); - std::vector group_size = calc_max_group_size(extruder_ams_counts, ignore_ext_filament); - - auto machine_filament_info = build_machine_filaments(print->get_extruder_filament_info(), extruder_ams_counts, ignore_ext_filament); - - std::vector filament_types = print_config.filament_type.values; - std::vector filament_colours = print_config.filament_colour.values; - std::vector filament_is_support = print_config.filament_is_support.values; - std::vector filament_ids = print_config.filament_ids.values; - // speacially handle tpu filaments - auto used_filaments = collect_sorted_used_filaments(layer_filaments); - auto tpu_filaments = get_filament_by_type(used_filaments, &print_config, "TPU"); - FGMode fg_mode = mode == FilamentMapMode::fmmAutoForMatch ? FGMode::MatchMode: FGMode::FlushMode; - - std::vector> ext_unprintable_filaments; - collect_unprintable_limits(physical_unprintables, geometric_unprintables, ext_unprintable_filaments); - - FilamentGroupContext context; - { - context.model_info.flush_matrix = std::move(nozzle_flush_mtx); - context.model_info.unprintable_filaments = ext_unprintable_filaments; - context.model_info.layer_filaments = layer_filaments; - context.model_info.filament_ids = filament_ids; - - for (size_t idx = 0; idx < filament_types.size(); ++idx) { - FilamentGroupUtils::FilamentInfo info; - info.color = filament_colours[idx]; - info.type = filament_types[idx]; - info.is_support = filament_is_support[idx]; - context.model_info.filament_info.emplace_back(std::move(info)); + if (has_multiple_nozzle && mode == FilamentMapMode::fmmManual) { + auto manual_filament_map = print_config.filament_map.values; + std::transform(manual_filament_map.begin(), manual_filament_map.end(), manual_filament_map.begin(), [](int v) { return v - 1; }); + ret = calc_filament_group_for_manual_multi_nozzle(manual_filament_map, context); + } else if (has_multiple_nozzle && mode == FilamentMapMode::fmmAutoForMatch) { + ret = calc_filament_group_for_match_multi_nozzle(context); + } else { + // TPU: keep the dedicated TPU split for single-nozzle-per-extruder printers. + auto tpu_filaments = get_filament_by_type(used_filaments, &print_config, "TPU"); + if (!has_multiple_nozzle && !tpu_filaments.empty()) { + ret = std::vector(context.group_info.total_filament_num, context.machine_info.master_extruder_id); + for (size_t fidx = 0; fidx < (size_t)context.group_info.total_filament_num; ++fidx) + ret[fidx] = tpu_filaments.count((int)fidx) ? context.machine_info.master_extruder_id : (1 - context.machine_info.master_extruder_id); + } else { + FilamentGroup fg(context); + if (!has_multiple_nozzle) + fg.get_custom_seq = get_custom_seq; + ret = fg.calc_filament_group(); + // Flush-mode auto grouping: restore the master-extruder preference + // (optimize_group_for_master_extruder). Match mode assigns by AMS colour and never had + // it. Kept out of the FilamentGroup engine so the test harness is unaffected. + if (context.group_info.mode == FGMode::FlushMode) + ret = apply_master_extruder_preference(context, used_filaments, ret); } - - context.machine_info.machine_filament_info = machine_filament_info; - context.machine_info.max_group_size = std::move(group_size); - context.machine_info.master_extruder_id = master_extruder_id; - - context.group_info.total_filament_num = (int)(filament_nums); - context.group_info.max_gap_threshold = 0.01; - context.group_info.strategy = FGStrategy::BestCost; - context.group_info.mode = fg_mode; - context.group_info.ignore_ext_filament = ignore_ext_filament; } - - if (!tpu_filaments.empty()) { - ret = calc_filament_group_for_tpu(tpu_filaments, context.group_info.total_filament_num, context.machine_info.master_extruder_id); - } - else { - FilamentGroup fg(context); - fg.get_custom_seq = get_custom_seq; - ret = fg.calc_filament_group(); - } - } else if (extruder_nums > 1) { - // For non-bbl multi-extruder printers we don't support filament group yet, and we use filament id as extruder id - assert(extruder_nums == filament_nums); - for (int i = 0; i < filament_nums; i++) { - ret[i] = i; + if (has_multiple_nozzle) { + auto result_opt = LayeredNozzleGroupResult::create(ret, context.nozzle_info.nozzle_list, used_filaments); + return result_opt ? *result_opt : LayeredNozzleGroupResult(); } } - return ret; + auto result_opt = LayeredNozzleGroupResult::create(ret, nozzle_list, used_filaments); + return result_opt ? *result_opt : LayeredNozzleGroupResult(); } FilamentChangeStats ToolOrdering::get_filament_change_stats(FilamentChangeMode mode) @@ -1232,6 +1545,319 @@ FilamentChangeStats ToolOrdering::get_filament_change_stats(FilamentChangeMode m return m_stats_by_single_extruder; } +// Build one logical nozzle per extruder. This is the single-nozzle grouping: +// nozzle group_id == extruder_id. Kept file-local. +static std::vector build_default_nozzle_list(const PrintConfig &print_config, size_t extruder_nums) +{ + using namespace MultiNozzleUtils; + std::vector nozzle_list; + for (size_t idx = 0; idx < extruder_nums; ++idx) { + NozzleInfo tmp; + tmp.diameter = format_diameter_to_str(print_config.nozzle_diameter.values[idx]); + tmp.group_id = static_cast(idx); + tmp.extruder_id = static_cast(idx); + // nozzle_volume_type may be shorter than nozzle_diameter on some Orca profiles; default to Standard. + tmp.volume_type = idx < print_config.nozzle_volume_type.values.size() + ? NozzleVolumeType(print_config.nozzle_volume_type.values[idx]) + : nvtStandard; + nozzle_list.emplace_back(std::move(tmp)); + } + return nozzle_list; +} + +// Build a LayeredNozzleGroupResult from an already-resolved 0-based +// filament->extruder map. Used by the by-object (sequential) path, whose grouping is decided +// earlier in Print.cpp — here we only wrap the config map. For single-nozzle-per-extruder printers +// (the common case incl. H2D) each filament resolves to its extruder's one logical nozzle +// (nozzle_id == extruder_id). For a multi-nozzle printer the config's per-filament nozzle/volume +// choice is resolved via the 6-argument create (the per-layer engine owns the auto +// sequential path proper). +static MultiNozzleUtils::LayeredNozzleGroupResult build_group_result_from_map( + const PrintConfig& print_config, + const std::vector& filament_map_0based, + const std::vector& used_filaments) +{ + using namespace MultiNozzleUtils; + const size_t extruder_nums = print_config.nozzle_diameter.values.size(); + const bool has_multiple_nozzle = std::any_of(print_config.extruder_max_nozzle_count.values.begin(), print_config.extruder_max_nozzle_count.values.end(), + [](int v) { return v > 1; }); + if (has_multiple_nozzle) { + float diameter = print_config.nozzle_diameter.values.empty() ? 0.4f : static_cast(print_config.nozzle_diameter.values.front()); + if (auto g = LayeredNozzleGroupResult::create(used_filaments, filament_map_0based, cfg_ints(print_config, "filament_volume_map"), cfg_ints(print_config, "filament_nozzle_map"), get_extruder_nozzle_stats(print_config.extruder_nozzle_stats.values), diameter)) + return *g; + } + auto nozzle_list = build_default_nozzle_list(print_config, extruder_nums); + if (auto group = LayeredNozzleGroupResult::create(filament_map_0based, nozzle_list, used_filaments)) + return *group; + return LayeredNozzleGroupResult(); +} + +// Per-layer nozzle-state refinement. Given a per-range grouping result and the +// physical nozzle occupancy (nozzles_state: nozzle_id -> filament currently loaded), it re-matches +// each logical nozzle to a physical nozzle *within its extruder* by a MinFlushFlowSolver that +// rewards keeping an already-loaded filament (cost -1) and otherwise charges the averaged flush. +// Returns a new result carrying the remapped default filament->nozzle map (falls back to the input +// result if the remap cannot be built). File-local: only the per-layer engine below calls it. +static MultiNozzleUtils::LayeredNozzleGroupResult refine_groups_by_Nozzle_State( + const FilamentGroupContext& ctx, + const MultiNozzleUtils::LayeredNozzleGroupResult& group, + const std::unordered_map& nozzles_state) +{ + std::vector> nozzle_fils(ctx.nozzle_info.nozzle_list.size()); + auto fils = group.get_used_filaments(0); + auto fil_noz_map = group.get_layer_filament_nozzle_map(0); + + for (auto fil : fils) + nozzle_fils[fil_noz_map[fil]].emplace_back(fil); + + // 1. Collect the nozzles each filament may NOT use. + std::map> fil_unplaceable_nozs; + for (auto fil : fils) { + std::set unprintable_volumes; + if (ctx.model_info.unprintable_volumes.count(fil)) + unprintable_volumes = ctx.model_info.unprintable_volumes.at(fil); + auto expected_volume = ctx.group_info.filament_volume_map[fil]; + + for (int noz = 0; noz < (int) ctx.nozzle_info.nozzle_list.size(); noz++) { + auto noz_info = ctx.nozzle_info.nozzle_list[noz]; + int ext_id = noz_info.extruder_id; + auto ext_unprintable_fils = ctx.model_info.unprintable_filaments[ext_id]; + if (ext_unprintable_fils.count(fil) > 0 || + (expected_volume != nvtHybrid && expected_volume != noz_info.volume_type) || (unprintable_volumes.count(noz_info.volume_type) != 0)) + fil_unplaceable_nozs[fil].insert(noz); + } + } + + // 2. Global nozzle-match result. + std::unordered_map global_uv_match; + + // 3. Solve one min-cost flow per extruder. + for (const auto& [ext_id, ext_nozzles] : ctx.nozzle_info.extruder_nozzle_list) { + if (ext_nozzles.empty()) continue; + + // 3.1. u_nodes / v_nodes for this extruder. + std::vector u_nodes = ext_nozzles; + std::vector v_nodes = ext_nozzles; + + // 3.2. global nozzle id -> local index. + std::unordered_map global_to_local; + for (size_t i = 0; i < ext_nozzles.size(); ++i) + global_to_local[ext_nozzles[i]] = static_cast(i); + + // 3.3. cost matrix for this extruder. + std::vector> cost_matrix(u_nodes.size(), std::vector(v_nodes.size(), std::numeric_limits::max())); + std::unordered_map> uv_unlink_limits; + + for (size_t local_u = 0; local_u < u_nodes.size(); ++local_u) { + int u_node = u_nodes[local_u]; + std::set unlink_v_local; + auto u_fils = nozzle_fils[u_node]; + + // Collect the v_nodes this u_node may NOT connect to (as local indices). + for (auto fil : u_fils) { + for (auto unplaceable_noz : fil_unplaceable_nozs[fil]) { + if (global_to_local.count(unplaceable_noz)) + unlink_v_local.insert(global_to_local[unplaceable_noz]); + } + } + uv_unlink_limits[static_cast(local_u)].assign(unlink_v_local.begin(), unlink_v_local.end()); + + // 3.4. compute costs. + for (size_t local_v = 0; local_v < v_nodes.size(); ++local_v) { + int v_node = v_nodes[local_v]; + float cost = 0; + if (unlink_v_local.count(static_cast(local_v))) continue; + + std::optional v_fil_opt = std::nullopt; + if (nozzles_state.count(v_node)) + v_fil_opt = nozzles_state.at(v_node); + + if (!v_fil_opt.has_value() || v_fil_opt.value() >= ctx.model_info.filament_info.size()) { + cost = 0; + } else { + int v_fil = v_fil_opt.value(); + if (std::find(u_fils.begin(), u_fils.end(), v_fil) != u_fils.end()) + cost = -1; + else { + for (auto u_fil : u_fils) + cost += ctx.model_info.flush_matrix[ext_id][u_fil][v_fil]; + if (u_fils.size() > 0) + cost /= u_fils.size(); + } + } + + cost_matrix[local_u][local_v] = cost; + } + } + + // 3.5. min-cost flow -> nozzle match for this extruder. + std::vector local_u_nodes(u_nodes.size()); + std::vector local_v_nodes(v_nodes.size()); + std::iota(local_u_nodes.begin(), local_u_nodes.end(), 0); + std::iota(local_v_nodes.begin(), local_v_nodes.end(), 0); + + MinFlushFlowSolver solver(cost_matrix, local_u_nodes, local_v_nodes, {}, uv_unlink_limits); + auto local_match = solver.solve(); + + // 3.6. local match -> global match. + for (size_t local_u = 0; local_u < u_nodes.size(); ++local_u) { + int global_u = u_nodes[local_u]; + int local_v = local_match[static_cast(local_u)]; + if (local_v == MaxFlowGraph::INVALID_ID || local_v < 0 || local_v >= static_cast(v_nodes.size())) + continue; + int global_v = v_nodes[local_v]; + global_uv_match[global_u] = global_v; + } + } + + // 4. Build the new group_result. + std::vector new_default_filament_nozzle_maps = group.get_layer_filament_nozzle_map(-1); + + for (auto fil : fils) { + int ori_noz = new_default_filament_nozzle_maps[fil]; + if (global_uv_match.count(ori_noz)) + new_default_filament_nozzle_maps[fil] = global_uv_match[ori_noz]; + } + + auto new_group = MultiNozzleUtils::LayeredNozzleGroupResult::create(new_default_filament_nozzle_maps, ctx.nozzle_info.nozzle_list, fils); + if (!new_group.has_value()) new_group = group; + + return *new_group; +} + +// Used as an unordered_map key over a filament-set (the per-layer filament combo). +struct VectorHash +{ + size_t operator()(const std::vector& v) const + { + size_t seed = v.size(); + for (auto& elem : v) + seed ^= std::hash()(elem) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +// The per-layer regroup engine. Layers are grouped into +// contiguous runs sharing the same filament set ("combo ranges"); a NozzleStatusRecorder carries the +// physical nozzle occupancy across ranges so the selector rewards keeping an already-loaded filament. +// Per range: get_recommended_filament_maps -> refine_groups_by_Nozzle_State (nozzle re-match) -> +// reorder_filaments_for_multi_nozzle_extruder (in-range ordering). Emits a per-layer +// filament->nozzle match + filament order. Orca: there is no ToolOrdering::OrderingContext here, so +// the custom-sequence function is passed directly instead. Only the dynamic branch +// (H2C selector, is_dynamic_group_reorder) calls this. +static std::vector plan_filament_mapping_and_order_by_combo_ranges( + Print* print, + const FilamentGroupContext& ctx, + const std::function&)> get_custom_seq, + const FilamentMapMode mode, + const std::vector>& physical_unprintables, + const std::vector>& geometric_unprintables, + const std::map>& unprintable_volumes, + MultiNozzleUtils::NozzleStatusRecorder* io_nozzle_status) +{ + std::vector results; + + const auto& layer_fils = ctx.model_info.layer_filaments; + if (layer_fils.empty()) + return results; + + results.resize(layer_fils.size()); + + // key: the sorted+deduped filament set used by a layer; value: the contiguous [start,end] runs. + std::unordered_map, std::vector>, VectorHash> filament_combo_ranges; + for (int layer_idx = 0; layer_idx < static_cast(layer_fils.size()); ++layer_idx) { + std::vector cur_combo = layer_fils[layer_idx]; + std::sort(cur_combo.begin(), cur_combo.end()); + cur_combo.erase(std::unique(cur_combo.begin(), cur_combo.end()), cur_combo.end()); + if (cur_combo.empty()) + continue; + + auto& ranges = filament_combo_ranges[cur_combo]; + if (ranges.empty() || ranges.back().second != layer_idx - 1) + ranges.emplace_back(layer_idx, layer_idx); + else + ranges.back().second = layer_idx; + } + + std::map, std::vector> range_filas_map; + for (auto& [combo, ranges] : filament_combo_ranges) + for (auto& range : ranges) + range_filas_map[range] = combo; + + std::set used_filaments; + + // Per combo range: build the range's layer_filaments, group + refine + reorder. + MultiNozzleUtils::NozzleStatusRecorder tool_status; + if (io_nozzle_status) tool_status = *io_nozzle_status; + + std::vector fil_noz_map(ctx.group_info.total_filament_num, -1); // global filament -> nozzle map + std::unordered_map fil_first_nozzle_map; // filament -> first nozzle it used + for (auto& [range, combo] : range_filas_map) { + auto [start_layer, end_layer] = range; + // 1. layer_filaments for this range. + std::vector> range_layer_fils; + range_layer_fils.reserve(end_layer - start_layer + 1); + for (int layer_idx = start_layer; layer_idx <= end_layer; ++layer_idx) + range_layer_fils.push_back(layer_fils[layer_idx]); + used_filaments.insert(combo.begin(), combo.end()); + + // 2. group the range. + auto nozzle_filament_map = tool_status.get_nozzle_filament_map(); + auto group_result = ToolOrdering::get_recommended_filament_maps(range_layer_fils, print, mode, physical_unprintables, geometric_unprintables, unprintable_volumes, nozzle_filament_map); + + // 3. re-match logical nozzles to physical nozzles by the current nozzle state. + auto new_group_result = refine_groups_by_Nozzle_State(ctx, group_result, nozzle_filament_map); + + auto range_seq_function = [&get_custom_seq, start_layer_ = start_layer, end_layer_ = end_layer](int layer_idx, std::vector& out_seq) -> bool { + if (layer_idx <= end_layer_ - start_layer_) { + int global_idx = start_layer_ + layer_idx; + return get_custom_seq ? get_custom_seq(global_idx, out_seq) : false; + } + return false; + }; + + // 4. order the filaments within the range. + std::vector> fils_sequences; + reorder_filaments_for_multi_nozzle_extruder(range_layer_fils.front(), new_group_result, range_layer_fils, ctx.model_info.flush_matrix, range_seq_function, + &fils_sequences, tool_status); + + // 5. store the range result + advance the nozzle state. + for (auto fil_id : fils_sequences.back()) { + auto noz = new_group_result.get_nozzle_for_filament(fil_id); + if (noz.has_value()) { + int noz_id = noz->group_id; + int ext_id = noz->extruder_id; + + fil_noz_map[fil_id] = noz_id; + fil_first_nozzle_map.emplace(static_cast(fil_id), noz_id); + + tool_status.set_current_extruder_id(ext_id); + tool_status.set_nozzle_status(noz_id, fil_id, ext_id); + } + } + + assert(fils_sequences.size() == range_layer_fils.size()); + for (size_t layer_id = 0; layer_id < fils_sequences.size(); ++layer_id) { + int g_layer_id = start_layer + static_cast(layer_id); + results[g_layer_id].fil_nozzle_match = fil_noz_map; + results[g_layer_id].fil_order = std::vector(fils_sequences[layer_id].begin(), fils_sequences[layer_id].end()); + } + } + + // Fill any never-assigned slot with the filament's first nozzle (or nozzle 0). + for (auto& res : results) { + for (int fil_id = 0; fil_id < (int) res.fil_nozzle_match.size(); fil_id++) { + auto& noz_id = res.fil_nozzle_match[fil_id]; + if (noz_id == -1) + noz_id = (used_filaments.count(fil_id) && fil_first_nozzle_map.count(fil_id)) ? fil_first_nozzle_map[fil_id] : 0; + } + } + + if (io_nozzle_status) *io_nozzle_status = tool_status; + + return results; +} + void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first_layer) { const PrintConfig* print_config = m_print_config_ptr; @@ -1263,7 +1889,9 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first nozzle_flush_mtx.emplace_back(wipe_volumes); } - auto flush_multiplies = print_config->flush_multiplier.values; + // Fast purge mode uses flush_multiplier_fast; Default is inert. + auto flush_multiplies = (print_config->prime_volume_mode == PrimeVolumeMode::pvmFast) ? print_config->flush_multiplier_fast.values + : print_config->flush_multiplier.values; flush_multiplies.resize(nozzle_nums, 1); for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) { for (auto& vec : nozzle_flush_mtx[nozzle_id]) { @@ -1287,31 +1915,14 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first filament_maps = m_print->get_filament_maps(); map_mode = m_print->get_filament_map_mode(); - // only check and map in sequence mode, in by object mode, we check the map in print.cpp - if (print_config->print_sequence != PrintSequence::ByObject || m_print->objects().size() == 1) { - if (map_mode < FilamentMapMode::fmmManual) { - const PrintConfig* print_config = m_print_config_ptr; - if (!print_config && m_print_object_ptr) { - print_config = &(m_print_object_ptr->print()->config()); - } - filament_maps = ToolOrdering::get_recommended_filament_maps(layer_filaments, m_print, map_mode, physical_unprintables, geometric_unprintables); - - if (filament_maps.empty()) - return; - std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value + 1; }); - m_print->update_filament_maps_to_config(filament_maps); - } - std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; }); - - if (m_print->is_BBL_printer()) - check_filament_printable_after_group(used_filaments, filament_maps, print_config); - } - else { - // we just need to change the map to 0 based - std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) {return value - 1; }); - } + // Grouping now yields a nozzle-aware LayeredNozzleGroupResult; the + // extruder-level filament_maps that feeds the ordering/stats below is derived from it. + MultiNozzleUtils::LayeredNozzleGroupResult grouping_result; + // The custom-sequence machinery is built before the grouping decision so both the static reorder + // and the dynamic per-layer plan can share it. Pure local setup (no dependency on the + // grouping result), so hoisting it above the branch does not change the static path's output. std::vector>filament_sequences; std::vectorfilament_lists(number_of_extruders); std::iota(filament_lists.begin(), filament_lists.end(), 0); @@ -1346,20 +1957,108 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first return false; }; + // Dynamic (per-layer filament-selector) regroup. is_dynamic_group_reorder() + // gates on enable_filament_dynamic_map (unset on every current profile), so this is closed for the + // whole shipping fleet AND H2C static mode — the static branch below is the only one they take, so + // their g-code is byte-identical. Only an H2C profile that enables the selector opens this branch. + const bool dynamic_reorder = m_print && m_print->is_dynamic_group_reorder(); + + if (dynamic_reorder) { + // Build the grouping context, plan per-combo-range nozzle maps + filament orders, then wrap the + // per-layer maps in a selector (4-arg create) result — which sets support_dynamic_nozzle_map and + // lights the GCode per-layer hotend/nozzle placeholders. filament_sequences is produced here, so + // the static reorder below is skipped for this branch. + auto grouping_context = build_filament_group_context(m_print, layer_filaments, physical_unprintables, geometric_unprintables, {}, FilamentMapMode::fmmAutoForFlush, + m_initial_nozzle_status.get_nozzle_filament_map()); + // The time estimator's per-extruder print times are global and do not apply to per-range + // grouping. + grouping_context.speed_info.group_with_time = false; + + m_nozzle_status = m_initial_nozzle_status; + auto dynamic_plan_res = plan_filament_mapping_and_order_by_combo_ranges(m_print, grouping_context, get_custom_seq, FilamentMapMode::fmmAutoForFlush, + physical_unprintables, geometric_unprintables, {}, &m_nozzle_status); + + std::vector> nozzle_map_per_layer; + for (auto& res : dynamic_plan_res) { + filament_sequences.emplace_back(cast(res.fil_order)); + nozzle_map_per_layer.emplace_back(res.fil_nozzle_match); + } + + auto result = MultiNozzleUtils::LayeredNozzleGroupResult::create(nozzle_map_per_layer, grouping_context.nozzle_info.nozzle_list, used_filaments, filament_sequences); + grouping_result = result ? *result : MultiNozzleUtils::LayeredNozzleGroupResult(); + + // Derive the extruder-level map (0-based) for the stats path + config write-back. The full + // per-nozzle config write-back is not yet wired. + std::vector derived_maps = grouping_result.get_extruder_map(false); // 1-based + if (!derived_maps.empty()) { + filament_maps = derived_maps; + m_print->update_filament_maps_to_config(filament_maps); + } + std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; }); + } + // only check and map in sequence mode, in by object mode, we check the map in print.cpp + else if (print_config->print_sequence != PrintSequence::ByObject || m_print->objects().size() == 1) { + grouping_result = ToolOrdering::get_recommended_filament_maps(layer_filaments, m_print, map_mode, physical_unprintables, geometric_unprintables); + std::vector derived_maps = grouping_result.get_extruder_map(false); // 1-based extruder map + + if (map_mode < FilamentMapMode::fmmManual) { + if (derived_maps.empty()) + return; + filament_maps = derived_maps; + m_print->update_filament_maps_to_config(filament_maps); + } else if (!derived_maps.empty()) { + // Manual modes: the result mirrors the user's config map; adopt it for consistency. + filament_maps = derived_maps; + } + std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; }); + + if (m_print->is_BBL_printer()) + check_filament_printable_after_group(used_filaments, filament_maps, print_config); + } + else { + // by-object: grouping was decided in Print.cpp; just wrap the (0-based) config map. + std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) {return value - 1; }); + grouping_result = build_group_result_from_map(*print_config, filament_maps, used_filaments); + } + + // The grouping result comes from the nozzle-centric engine. For single-nozzle-per-extruder printers + // (incl. H2D) each filament resolves to nozzle_id == extruder_id, so GCode's static hotend/nozzle + // placeholders are unchanged; H2C/A2L resolve to a nozzle-granular result (dynamic mode + // resolves per-layer). GCode consumes this via Print::get_layered_nozzle_group_result(). + m_nozzle_group_result = grouping_result; + { + // Orca: the ToolOrdering member is stored unconditionally, but the Print-level store is gated + // behind a not-sequential check. There is no is_sequential_print() here, so it is mirrored + // with the same predicate the branch above uses. + const bool not_sequential = print_config->print_sequence != PrintSequence::ByObject || + (m_print && m_print->objects().size() == 1); + if (m_print != nullptr && not_sequential) + m_print->set_nozzle_group_result(std::make_shared(m_nozzle_group_result)); + } + auto maps_without_group = filament_maps; for (auto& item : maps_without_group) item = 0; - reorder_filaments_for_minimum_flush_volume( - filament_lists, - m_print->is_BBL_printer() ? filament_maps : maps_without_group, // non-bbl printers do not support filament group yet - layer_filaments, - nozzle_flush_mtx, - get_custom_seq, - &filament_sequences - ); + // The dynamic branch produced filament_sequences itself (per-layer selector plan); only the static + // path needs the extruder-map flush reorder here. + if (!dynamic_reorder) { + reorder_filaments_for_minimum_flush_volume( + filament_lists, + m_print->is_BBL_printer() ? filament_maps : maps_without_group, // non-bbl printers do not support filament group yet + layer_filaments, + nozzle_flush_mtx, + get_custom_seq, + &filament_sequences + ); + } - auto curr_flush_info = calc_filament_change_info_by_toolorder(print_config, filament_maps, nozzle_flush_mtx, filament_sequences); + // The three-mode flush-stat caches are now computed from the nozzle-aware grouping result via the + // nozzle-aware calc_filament_change_info_by_toolorder. Stats are GUI-only (surfaced by + // get_filament_change_stats for the mode comparison); they never feed g-code, so this block is + // byte-inert. For single-nozzle-per-extruder printers (H2D/X1/...) nozzle_id == extruder_id, so + // every cached value equals the extruder-level stats. + auto curr_flush_info = calc_filament_change_info_by_toolorder(print_config, grouping_result, nozzle_flush_mtx, filament_sequences); if (nozzle_nums <= 1) m_stats_by_single_extruder = curr_flush_info; else { @@ -1368,35 +2067,71 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first m_stats_by_multi_extruder_best = curr_flush_info; } - // in multi extruder mode,collect data with other mode + // in multi extruder mode, collect data under the other modes (for the GUI mode comparison) if (nozzle_nums > 1) { - // always calculate the info by one extruder + // always calculate the info as if a single extruder were used { - std::vector>filament_sequences_one_extruder; + std::vector> single_extruder_sequences; reorder_filaments_for_minimum_flush_volume( filament_lists, maps_without_group, layer_filaments, nozzle_flush_mtx, get_custom_seq, - &filament_sequences_one_extruder + &single_extruder_sequences ); - m_stats_by_single_extruder = calc_filament_change_info_by_toolorder(print_config, maps_without_group, nozzle_flush_mtx, filament_sequences_one_extruder); + // One logical nozzle (extruder 0, nozzle 0); every filament resolves to it. + // diameter/volume_type are unused by the stat calc. + MultiNozzleUtils::NozzleInfo single_nozzle; + single_nozzle.volume_type = NozzleVolumeType::nvtStandard; + single_nozzle.extruder_id = 0; + single_nozzle.group_id = 0; + auto single_result = MultiNozzleUtils::LayeredNozzleGroupResult::create(maps_without_group, {single_nozzle}, used_filaments); + if (single_result) + m_stats_by_single_extruder = calc_filament_change_info_by_toolorder(print_config, *single_result, nozzle_flush_mtx, single_extruder_sequences); } - // if not in best for flush mode,also calculate the info by best for flush mode + // if not already in best-for-flush mode, also calculate the info under best-for-flush grouping if (map_mode != fmmAutoForFlush) { - std::vector>filament_sequences_one_extruder; - std::vectorfilament_maps_auto = get_recommended_filament_maps(layer_filaments, m_print, fmmAutoForFlush, physical_unprintables, geometric_unprintables); - reorder_filaments_for_minimum_flush_volume( - filament_lists, - filament_maps_auto, - layer_filaments, - nozzle_flush_mtx, - get_custom_seq, - &filament_sequences_one_extruder - ); - m_stats_by_multi_extruder_best = calc_filament_change_info_by_toolorder(print_config, filament_maps_auto, nozzle_flush_mtx, filament_sequences_one_extruder); + std::vector> best_sequences; + if (dynamic_reorder) { + // When the filament selector is active the "best" plan + // is the per-combo-range dynamic regroup, computed over a *copy* of the initial nozzle + // status so it cannot perturb the chosen m_nozzle_status / primary result. NOTE: + // is_dynamic_group_reorder() implies filament_map_mode == fmmAutoForFlush, contradicting + // this map_mode != fmmAutoForFlush guard, so this sub-branch is unreachable under the + // current predicate. It is provably inert. + auto best_context = build_filament_group_context(m_print, layer_filaments, physical_unprintables, geometric_unprintables, {}, FilamentMapMode::fmmAutoForFlush, + m_initial_nozzle_status.get_nozzle_filament_map()); + best_context.speed_info.group_with_time = false; + MultiNozzleUtils::NozzleStatusRecorder best_nozzle_status = m_initial_nozzle_status; + auto best_plan = plan_filament_mapping_and_order_by_combo_ranges(m_print, best_context, get_custom_seq, FilamentMapMode::fmmAutoForFlush, + physical_unprintables, geometric_unprintables, {}, &best_nozzle_status); + std::vector> best_nozzle_map_per_layer; + for (auto& res : best_plan) { + best_sequences.emplace_back(cast(res.fil_order)); + best_nozzle_map_per_layer.emplace_back(res.fil_nozzle_match); + } + auto best_result = MultiNozzleUtils::LayeredNozzleGroupResult::create(best_nozzle_map_per_layer, best_context.nozzle_info.nozzle_list, used_filaments, best_sequences); + if (best_result) + m_stats_by_multi_extruder_best = calc_filament_change_info_by_toolorder(print_config, *best_result, nozzle_flush_mtx, best_sequences); + } + else { + // Best-for-flush grouping (nozzle-aware result). The extruder-level map fed to the flush + // reorder is derived exactly as before, so best_sequences (and the flush weight) are + // identical; only flush_filament_change_count is now charged per physical nozzle. + auto best_group_result = get_recommended_filament_maps(layer_filaments, m_print, fmmAutoForFlush, physical_unprintables, geometric_unprintables); + std::vector best_maps = best_group_result.get_extruder_map(); + reorder_filaments_for_minimum_flush_volume( + filament_lists, + best_maps, + layer_filaments, + nozzle_flush_mtx, + get_custom_seq, + &best_sequences + ); + m_stats_by_multi_extruder_best = calc_filament_change_info_by_toolorder(print_config, best_group_result, nozzle_flush_mtx, best_sequences); + } } } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 11e351b99a..b67fea119a 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -9,6 +9,7 @@ #include #include "../FilamentGroup.hpp" +#include "../MultiNozzleUtils.hpp" #include "../ExtrusionEntity.hpp" #include "../PrintConfig.hpp" @@ -98,19 +99,23 @@ private: struct FilamentChangeStats { int filament_flush_weight{0}; + // flush_filament_change_count counts filament changes that actually flush a physical nozzle. + // It replaces the former (dead, never populated) extruder_change_count. For single-nozzle-per- + // extruder printers it equals the per-extruder filament_change_count, so GUI stat displays are + // unchanged. + int flush_filament_change_count{0}; int filament_change_count{0}; - int extruder_change_count{0}; void clear(){ filament_flush_weight = 0; filament_change_count = 0; - extruder_change_count = 0; + flush_filament_change_count = 0; } FilamentChangeStats& operator+=(const FilamentChangeStats& other) { this->filament_flush_weight += other.filament_flush_weight; this->filament_change_count += other.filament_change_count; - this->extruder_change_count += other.extruder_change_count; + this->flush_filament_change_count += other.flush_filament_change_count; return *this; } @@ -118,7 +123,7 @@ struct FilamentChangeStats FilamentChangeStats ret; ret.filament_flush_weight = this->filament_flush_weight + other.filament_flush_weight; ret.filament_change_count = this->filament_change_count + other.filament_change_count; - ret.extruder_change_count = this->extruder_change_count + other.extruder_change_count; + ret.flush_filament_change_count = this->flush_filament_change_count + other.flush_filament_change_count; return ret; } @@ -236,12 +241,21 @@ public: bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().has_wipe_tower; } int get_most_used_extruder() const { return most_used_extruder; } + + // Logical (extruder, nozzle) grouping of the used filaments, built during reorder. + // For single-nozzle printers this is one logical nozzle per extruder (nozzle id == extruder id). + // Consumed by GCode (get_nozzle_id / get_first_nozzle_for_filament). + const MultiNozzleUtils::LayeredNozzleGroupResult &get_layered_nozzle_group_result() const { return m_nozzle_group_result; } /* * called in single extruder mode, the value in map are all 0 * called in dual extruder mode, the value in map will be 0 or 1 * 0 based group id */ - static std::vector get_recommended_filament_maps(const std::vector>& layer_filaments, const Print* print,const FilamentMapMode mode, const std::vector>& physical_unprintables, const std::vector>& geometric_unprintables); + // Nozzle-centric grouping. Returns a nozzle-aware LayeredNozzleGroupResult instead of a plain + // extruder-level std::vector. Callers derive the 0/1-based extruder map via + // result.get_extruder_map(). unprintable_volumes / nozzle_status default empty for the static + // path; the per-layer engine supplies non-empty values. + static MultiNozzleUtils::LayeredNozzleGroupResult get_recommended_filament_maps(const std::vector>& layer_filaments, const Print* print,const FilamentMapMode mode, const std::vector>& physical_unprintables, const std::vector>& geometric_unprintables, const std::map>& unprintable_volumes = {}, const std::unordered_map& nozzle_status = {}); // should be called after doing reorder FilamentChangeStats get_filament_change_stats(FilamentChangeMode mode); @@ -283,6 +297,13 @@ private: FilamentChangeStats m_stats_by_single_extruder; FilamentChangeStats m_stats_by_multi_extruder_curr; FilamentChangeStats m_stats_by_multi_extruder_best; + MultiNozzleUtils::LayeredNozzleGroupResult m_nozzle_group_result; + // Physical nozzle occupancy threaded through the per-layer selector regroup. + // m_initial_nozzle_status seeds the first combo range (empty for a fresh slice — there is no + // device continuation state); m_nozzle_status carries the running state out of the plan. Inert + // for every printer except an H2C profile that enables the filament selector (is_dynamic_group_reorder). + MultiNozzleUtils::NozzleStatusRecorder m_initial_nozzle_status; + MultiNozzleUtils::NozzleStatusRecorder m_nozzle_status; int most_used_extruder; }; diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 13807c191b..38b7b56176 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -1493,6 +1494,21 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value) { m_flat_ironing = (m_flat_ironing && m_use_gap_wall); + + // Prime-tower heating during wipe. m_is_multiple_nozzle mirrors the gate used in ToolOrdering/GCode + // (std::any_of extruder_max_nozzle_count > 1); it is false for every current printer, so the + // heating-during-wipe logic in toolchange_wipe_new is inert. + m_hotend_heating_rate = config.hotend_heating_rate.values; + m_physical_extruder_map = config.physical_extruder_map.values; + m_is_multiple_nozzle = std::any_of(config.extruder_max_nozzle_count.values.begin(), + config.extruder_max_nozzle_count.values.end(), + [](int v) { return v > 1; }); + + // Per-extruder printable-height clamp. Empty for single-extruder printers + // (extruder_printable_height = []), so is_valid_last_layer is inert there. + m_printable_height = config.extruder_printable_height.values; + m_last_layer_id.assign(config.nozzle_diameter.size(), -1); + // Read absolute value of first layer speed, if given as percentage, // it is taken over following default. Speeds from config are not // easily accessible here. @@ -1558,8 +1574,12 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config) } m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx); + // PETG pre-extrusion offset reuses the tower-interface pre-extrusion distance. Only read by the + // has_filament_switcher-gated PETG branch in get_next_pos (inert fleet-wide). + m_filpar[idx].petg_pre_extrusion_offset_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx); m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx); m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx); + m_filpar[idx].filament_cooling_before_tower = config.filament_cooling_before_tower.get_at(idx); // If this is a single extruder MM printer, we will use all the SE-specific config values. // Otherwise, the defaults will be used to turn off the SE stuff. @@ -1651,6 +1671,27 @@ Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, fl break; default: break; } + // Shift the wipe start outward for a PETG pre-extrusion on filament-switcher devices, clamped to the + // shared printable bed. Gated on m_has_filament_switcher, which is false for the whole shipping fleet + // (no profile sets the key), so is_petg_pre_extrusion is always false and res is returned unchanged. + // The tower-interface contact branch is deliberately NOT applied here (enable_tower_interface_features + // DOES ship on H2C/X2D; applying it would change their g-code); is_contact_pre_extrusion is computed + // only as the guard that gives the contact path priority over PETG. + bool is_contact_pre_extrusion = interface_layer && m_enable_tower_interface_features; + bool is_petg_pre_extrusion = !is_contact_pre_extrusion && is_petg_filament(m_current_tool) && m_has_filament_switcher; + if (is_petg_pre_extrusion) { + Vec2f stop_pos = res; + float offset_dist = m_filpar[m_current_tool].petg_pre_extrusion_offset_dist; + auto printer_bbx = unscaled(get_extents(m_shared_print_bed)); // BoundingBoxBase + printer_bbx.translate((-m_wipe_tower_pos - m_rib_offset).cast()); + if (stop_pos.x() < m_wipe_tower_width / 2.f) + stop_pos = Vec2f(stop_pos.x() - offset_dist, stop_pos.y()); + else + stop_pos = Vec2f(stop_pos.x() + offset_dist, stop_pos.y()); + if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = printer_bbx.min[0]; + if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = printer_bbx.max[0]; + res = stop_pos; + } return res; } @@ -2645,6 +2686,11 @@ bool WipeTower::is_tpu_filament(int filament_id) const return m_filpar[filament_id].material == "TPU"; } +bool WipeTower::is_petg_filament(int filament_id) const +{ + return m_filpar[filament_id].material == "PETG"; +} + // BBS: consider both soluable and support properties // Return index of first toolchange that switches to non-soluble and non-support extruder // ot -1 if there is no such toolchange. @@ -2717,6 +2763,9 @@ void WipeTower::get_wall_skip_points(const WipeTowerInfo &layer) float spacing = m_layer_info->extra_spacing; if (has_tpu_filament() && m_layer_info->extra_spacing < m_tpu_fixed_spacing) spacing = 1; float nozzle_change_depth = tool_change.nozzle_change_depth * spacing; + // Drop the nozzle-change depth on an extruder's final layer above its printable height + // (inert unless is_valid_last_layer clamps, i.e. multi-extruder near Z-max). + if (!is_valid_last_layer(old_filament, m_cur_layer_id, layer.z)) nozzle_change_depth = 0.f; //float nozzle_change_depth = tool_change.nozzle_change_depth * (has_tpu_filament() ? m_tpu_fixed_spacing : layer.extra_spacing); auto* block = get_block_by_category(m_filpar[new_filament].category, false); if (!block) @@ -2760,7 +2809,10 @@ void WipeTower::get_wall_skip_points(const WipeTowerInfo &layer) WipeTower::ToolChangeResult WipeTower::tool_change_new(size_t new_tool, bool solid_toolchange,bool solid_nozzlechange) { m_nozzle_change_result.gcode.clear(); - if (!m_filament_map.empty() && new_tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[new_tool]) { + // Skip the cross-extruder nozzle change (ramming) on an extruder's final layer above its printable + // height. is_valid_last_layer is inert unless multi-extruder near Z-max. + if (!m_filament_map.empty() && new_tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[new_tool] + && is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) { m_nozzle_change_result = nozzle_change_new(m_current_tool, new_tool, solid_nozzlechange); } @@ -3411,23 +3463,103 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat x_to_wipe = solid_tool_toolchange ? std::numeric_limits::max(): x_to_wipe; float target_speed = is_first_layer() ? std::min(m_first_layer_speed * 60.f, 4800.f) : 4800.f; target_speed = solid_tool_toolchange ? 20.f * 60.f : target_speed; - float wipe_speed = 0.33f * target_speed; + // Nominal wipe-speed schedule. The applied wipe_speed is nominal_speed * speed_factor; speed_factor + // stays 1.0 unless the H2C prime-tower heating-during-wipe model below slows the wipe so the hotend + // can reach temperature (nominal_speed == wipe_speed when speed_factor == 1, i.e. single-nozzle). + float nominal_speed = 0.33f * target_speed; m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2); bool is_from_up = (m_cur_layer_id % 2 == 1); + // Prime-tower heating during wipe. Everything here is gated on m_is_multiple_nozzle (false for every + // current printer); the lambdas emit nothing until add_M104_by_requirement's gate opens, so the + // single-nozzle wipe is untouched. + // WipeSpeedMap mirrors the nominal schedule above and is read only by estimate_wipe_time. It is a + // std::array (stack, no per-call heap allocation); values depend on runtime target_speed so it + // cannot be static const. + const std::array WipeSpeedMap{0.33f * target_speed, 0.375f * target_speed, 0.458f * target_speed, + 0.875f * target_speed, std::min(target_speed, 0.875f * target_speed + 50.f)}; + auto estimate_wipe_time = [&cleaning_box, &x_to_wipe, &xr, &xl, &dy, &WipeSpeedMap, &solid_tool_toolchange]() -> float { + int n = std::ceil(x_to_wipe / (xr - xl)); + if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy; + float one_line_len = xr - xl; + float time = std::numeric_limits::max(); + if (n <= 1) + time = one_line_len / WipeSpeedMap[0]; + else if (n <= 2) + time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1]; + else if (n <= 3) + time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2]; + else if (n <= 4) + time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2] + one_line_len / WipeSpeedMap[3]; + else { + time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2] + one_line_len / WipeSpeedMap[3]; + time += (n - 4) * one_line_len / WipeSpeedMap[4]; + } + return time * 60.f; + }; + // Emit the arriving-hotend pre-heat inside the M632/M633 nozzle-change barrier. `M632 S[ H] + // M N` opens the barrier (M = firmware nozzle-change flag, N = slicer generated), the M104 sets the + // arriving hotend temp, and `M633` closes it. H2C's grouping is static (no dynamic nozzle map), so the + // H field is omitted (a dynamic nozzle map would supply a real nozzle id, a static map -1 => no + // H). The counterproductive fan-on (M106 S255) used for departing-tool cooldown is intentionally + // omitted, since this is a pre-HEAT of the arriving tool. The whole helper is only ever called from + // add_M104_by_requirement, which is gated on m_is_multiple_nozzle (extruder_max_nozzle_count>1) => H2C + // only; every other printer's wipe tower is untouched. The M632 M-flag is itself a firmware barrier, so + // a preceding M400 wait is subsumed. + auto format_line_M104 = [this](int target_temp, int target_extruder = -1, bool wait_for_moves = true, const std::string &comment = "") { + std::string buffer; + buffer += "M632 S" + std::to_string(m_current_tool) + " M N\n"; + buffer += "M104"; + if (target_extruder != -1 && target_extruder < (int) m_physical_extruder_map.size()) + buffer += (" T" + std::to_string(m_physical_extruder_map[target_extruder])); + buffer += " S" + std::to_string(target_temp) + " N0"; // N0 means the gcode is generated by the slicer + if (!comment.empty()) buffer += " ;" + comment; + buffer += '\n'; + buffer += "M633\n"; + (void) wait_for_moves; // the M632 M-flag barrier replaces the former M400 wait + return buffer; + }; + // Suppress the pre-heat M104 on the first layer and on solid (contact) toolchanges (should_heating). + // m_is_multiple_nozzle folds in the H2C gate so single-nozzle output is untouched. + // Orca: the arriving extruder id is resolved as m_filament_map[tool]-1 (layer-static) because Orca's + // wipe tower is extruder-level rather than tracking a per-layer nozzle map. + bool should_heating = m_is_multiple_nozzle && m_filpar[m_current_tool].filament_cooling_before_tower > EPSILON && + !solid_tool_toolchange && !is_first_layer(); + auto add_M104_by_requirement = [&writer, &format_line_M104, &should_heating, this]() { + if (m_filpar[m_current_tool].filament_cooling_before_tower < EPSILON) return; + if (!should_heating) return; + float target_temp = is_first_layer() ? m_filpar[m_current_tool].nozzle_temperature_initial_layer : m_filpar[m_current_tool].nozzle_temperature; + writer.append(format_line_M104(target_temp, m_filament_map[m_current_tool] - 1)); + }; + float speed_factor = 1.f; + if (should_heating) { + // The heating-slowdown scaling is disabled — no additional heating time is required, so + // speed_factor stays 1.0. The structure and estimate_wipe_time/WipeSpeedMap are retained for + // future H2C tuning; the divide-by-zero/bounds guard is preserved in the commented body below. + // int extruder_id = m_filament_map[m_current_tool] - 1; + // if (extruder_id >= 0 && extruder_id < (int) m_hotend_heating_rate.size() && m_hotend_heating_rate[extruder_id] > 0.) { + // float estimate_time = estimate_wipe_time(); + // float heat_time = m_filpar[m_current_tool].filament_cooling_before_tower / m_hotend_heating_rate[extruder_id]; + // if (estimate_time < heat_time) speed_factor = estimate_time / heat_time; + // } + (void) estimate_wipe_time; // retain scaffolding above without an unused-lambda warning + } + float wipe_speed = nominal_speed * speed_factor; + // now the wiping itself: for (int i = 0; true; ++i) { if (i != 0) { - if (wipe_speed < 0.34f * target_speed) - wipe_speed = 0.375f * target_speed; - else if (wipe_speed < 0.377 * target_speed) - wipe_speed = 0.458f * target_speed; - else if (wipe_speed < 0.46f * target_speed) - wipe_speed = 0.875f * target_speed; + if (nominal_speed < 0.34f * target_speed) + nominal_speed = 0.375f * target_speed; + else if (nominal_speed < 0.377 * target_speed) + nominal_speed = 0.458f * target_speed; + else if (nominal_speed < 0.46f * target_speed) + nominal_speed = 0.875f * target_speed; else - wipe_speed = std::min(target_speed, wipe_speed + 50.f); + nominal_speed = std::min(target_speed, nominal_speed + 50.f); + wipe_speed = nominal_speed * speed_factor; } bool need_change_flow = need_thick_bridge_flow(writer.y()); @@ -3453,6 +3585,7 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat } else writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.); writer.retract(-retract_length, retract_speed); + add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); } else { float dx = xl - wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x(); @@ -3468,9 +3601,11 @@ void WipeTower::toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinat }else writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.); writer.retract(-retract_length, retract_speed); + add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); } } else { + if (i == 0) add_M104_by_requirement(); // Pre-heat the arriving hotend during the wipe if (m_left_to_right) writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed); else @@ -3571,6 +3706,47 @@ bool WipeTower::is_in_same_extruder(int filament_id_1, int filament_id_2) return m_filament_map[filament_id_1] == m_filament_map[filament_id_2]; } +// Per-extruder printable-height clamp: is an extruder still allowed to print on this wipe-tower layer, +// or is it its final layer above the extruder's printable height? +// Orca: the arriving extruder id is resolved as m_filament_map[tool]-1 (1-based map, layer-static), +// because Orca's wipe tower is extruder-level rather than tracking a per-layer nozzle map (the same +// idiom the pre-heat path uses in toolchange_wipe_new). Gated on m_is_multi_extruder so that +// single-extruder printers (including ones whose extruder_printable_height defaults to {0}) always +// return true and leave wipe-tower g-code unchanged. +bool WipeTower::is_valid_last_layer(int tool, int layer_id, double layer_z) const +{ + if (!m_is_multi_extruder) + return true; + int extruder_id = (tool >= 0 && tool < (int) m_filament_map.size()) ? m_filament_map[tool] - 1 : -1; + if (extruder_id < 0 || extruder_id >= (int) m_printable_height.size() || extruder_id >= (int) m_last_layer_id.size()) + return true; + if (m_last_layer_id[extruder_id] == layer_id && layer_z > m_printable_height[extruder_id]) + return false; + return true; +} + +// Records, per extruder, the last wipe-tower layer index that uses it, so is_valid_last_layer can +// recognise the extruder's final layer. Inert for single-extruder printers (early return); +// bounds-checked because m_filament_map may be empty/short. +void WipeTower::set_nozzle_last_layer_id() +{ + if (!m_is_multi_extruder) + return; + for (int idx = 0; idx < (int) m_plan.size(); ++idx) { + const auto &info = m_plan[idx]; + for (const auto &tc : info.tool_changes) { + int old_tool = (int) tc.old_tool; + int new_tool = (int) tc.new_tool; + int old_ext = (old_tool >= 0 && old_tool < (int) m_filament_map.size()) ? m_filament_map[old_tool] - 1 : -1; + int new_ext = (new_tool >= 0 && new_tool < (int) m_filament_map.size()) ? m_filament_map[new_tool] - 1 : -1; + if (old_ext >= 0 && old_ext < (int) m_last_layer_id.size()) + m_last_layer_id[old_ext] = idx; + if (new_ext >= 0 && new_ext < (int) m_last_layer_id.size()) + m_last_layer_id[new_ext] = idx; + } + } +} + void WipeTower::reset_block_status() { for (auto &block : m_wipe_tower_blocks) { @@ -3797,6 +3973,7 @@ void WipeTower::plan_tower_new() } update_all_layer_depth(max_depth); + set_nozzle_last_layer_id(); // record per-extruder last layer for is_valid_last_layer float diagonal = sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width); m_rib_length = std::max({m_rib_length, diagonal}); m_rib_length += m_extra_rib_length; @@ -3916,9 +4093,12 @@ void WipeTower::generate_new(std::vector m_hotend_heating_rate; // config.hotend_heating_rate (deg/s per extruder) + std::vector m_physical_extruder_map; // logical extruder -> physical tool number (M104 T param) + + // Per-extruder printable-height clamp. m_printable_height = config.extruder_printable_height + // (per-extruder Z limit; empty for single-extruder printers, [320,325] for H2D). m_last_layer_id + // records, per extruder, the last wipe-tower layer that uses it. is_valid_last_layer() is gated on + // m_is_multi_extruder so single-extruder wipe-tower g-code is unchanged; the clamp only bites a + // multi-extruder wipe tower whose final per-extruder layer exceeds that extruder's printable + // height (near the Z limit). + std::vector m_printable_height; + std::vector m_last_layer_id; + // Bed properties enum { RectangularBed, @@ -501,6 +530,11 @@ private: bool m_flat_ironing=false; bool m_enable_tower_interface_features=false; bool m_enable_tower_interface_cooldown_during_tower=false; + // Filament-switcher device flag + shared printable bed for the PETG pre-extrusion offset. + // m_has_filament_switcher is false for the whole shipping fleet (no profile sets the key), so + // the PETG branch in get_next_pos never runs -> no change fleet-wide. + bool m_has_filament_switcher=false; + Polygons m_shared_print_bed; bool m_prev_layer_had_interface=false; bool m_current_layer_has_interface=false; // Calculates length of extrusion line to extrude given volume @@ -520,6 +554,7 @@ private: void save_on_last_wipe(); bool is_tpu_filament(int filament_id) const; + bool is_petg_filament(int filament_id) const; // BBS box_coordinates align_perimeter(const box_coordinates& perimeter_box); @@ -586,6 +621,12 @@ private: const box_coordinates &cleaning_box, float wipe_volume); void get_wall_skip_points(const WipeTowerInfo &layer); + + // Per-extruder printable-height clamp (see m_printable_height). is_valid_last_layer returns + // false only for a multi-extruder wipe tower's final per-extruder layer that exceeds that + // extruder's printable height; returns true (no clamp) in every other case. + bool is_valid_last_layer(int tool, int layer_id, double layer_z) const; + void set_nozzle_last_layer_id(); }; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index a3d8e66ac3..f32840f614 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -632,6 +632,25 @@ std::string GCodeWriter::toolchange(unsigned int filament_id) return gcode.str(); } +// Current parked-retract length of the filament's extruder, share-aware. m_filament_extruders is +// sorted by id (see toolchange), so a lower_bound lookup finds the entry; unknown filament ids +// degrade to 0 rather than dereferencing end(). +double GCodeWriter::get_extruder_retracted_length(const int filament_id) +{ + double res = 0.0; + auto filament_extruder_iter = Slic3r::lower_bound_by_predicate(m_filament_extruders.begin(), m_filament_extruders.end(), + [filament_id](const Extruder &e) { return (int) e.id() < filament_id; }); + if (filament_extruder_iter == m_filament_extruders.end() || (int) filament_extruder_iter->id() != filament_id) + return res; + + if (filament_extruder_iter->is_share_extruder()) + res = filament_extruder_iter->get_share_retracted_length(); + else + res = filament_extruder_iter->get_single_retracted_length(); + + return res; +} + std::string GCodeWriter::set_speed(double F, const std::string &comment, const std::string &cooling_marker) { assert(F > 0.); @@ -1101,7 +1120,7 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std return gcode; } -std::string GCodeWriter::unretract() +std::string GCodeWriter::unretract(float extra_retract) { std::string gcode; @@ -1117,7 +1136,9 @@ std::string GCodeWriter::unretract() //BBS // use G1 instead of G0 because G0 will blend the restart with the previous travel move GCodeG1Formatter w; - w.emit_e(filament()->E()); + // extra_retract over-extrudes for the PETG pre-extrusion; 0 by + // default -> identical to the plain deretract E position. + w.emit_e(filament()->E() + extra_retract); w.emit_f(filament()->deretract_speed() * 60.); //BBS w.emit_comment(GCodeWriter::full_gcode_comment, " ; unretract"); diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index d3f419df7c..205ad0cfbb 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -66,6 +66,9 @@ public: bool need_toolchange(unsigned int filament_id) const; std::string set_extruder(unsigned int filament_id); void init_extruder(unsigned int filament_id); + // Current parked-retract length of a filament's extruder (share-aware). Used for the + // new_extruder_retracted_length change-filament placeholder. Returns 0 if the filament is unknown. + double get_extruder_retracted_length(const int filament_id); // Prefix of the toolchange G-code line, to be used by the CoolingBuffer to separate sections of the G-code // printed with the same extruder. std::string toolchange_prefix() const; @@ -83,7 +86,9 @@ public: std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string(), bool force_no_extrusion = false); std::string retract(bool before_wipe = false, double retract_length = 0); std::string retract_for_toolchange(bool before_wipe = false, double retract_length = 0); - std::string unretract(); + // extra_retract adds a small over-extrusion to the deretract move (PETG pre-extrusion). + // Default 0 -> byte-identical to the plain deretract. + std::string unretract(float extra_retract = 0.f); // do lift instantly std::string eager_lift(const LiftType type); // record a lift request, do realy lift in next travel diff --git a/src/libslic3r/MultiNozzleUtils.cpp b/src/libslic3r/MultiNozzleUtils.cpp new file mode 100644 index 0000000000..e8ceadbbb7 --- /dev/null +++ b/src/libslic3r/MultiNozzleUtils.cpp @@ -0,0 +1,922 @@ +#include "MultiNozzleUtils.hpp" +#include "Utils.hpp" +#include "ProjectTask.hpp" // Slic3r::FilamentInfo (StaticNozzleGroupResult / load_nozzle_infos_with_compatibility) +#include +#include +#include +#include +#include +#include + +// Multi-nozzle support. + +namespace Slic3r { namespace MultiNozzleUtils { +// ==================== tool function implementations ==================== +std::vector build_nozzle_list(std::vector nozzle_groups) +{ + std::vector ret; + std::sort(nozzle_groups.begin(), nozzle_groups.end()); + int nozzle_id = 0; + for (auto& group : nozzle_groups) { + for (int i = 0; i < group.nozzle_count; ++i) { + NozzleInfo tmp; + tmp.diameter = group.diameter; + tmp.extruder_id = group.extruder_id; + tmp.volume_type = group.volume_type; + tmp.group_id = nozzle_id++; + ret.emplace_back(std::move(tmp)); + } + } + return ret; +} + +std::vector build_nozzle_list(double diameter, const std::vector& filament_nozzle_map, const std::vector& filament_volume_map, const std::vector& filament_map) +{ + std::string diameter_str = format_diameter_to_str(diameter); + std::map> nozzle_to_filaments; + for(size_t idx = 0; idx < filament_nozzle_map.size(); ++idx){ + int nozzle_id = filament_nozzle_map[idx]; + nozzle_to_filaments[nozzle_id].emplace_back(static_cast(idx)); + } + std::vector ret; + for(auto& elem : nozzle_to_filaments){ + int nozzle_id = elem.first; + auto& filaments = elem.second; + NozzleInfo info; + info.diameter = diameter_str; + info.group_id = nozzle_id; + info.extruder_id = filament_map[filaments.front()]; + info.volume_type = NozzleVolumeType(filament_volume_map[filaments.front()]); + ret.emplace_back(std::move(info)); + } + return ret; +} + +// ==================== LayeredNozzleGroupResult ==================== +static bool has_filament_mapped_to_multiple_nozzles(const std::vector> &layer_filament_nozzle_maps, + const std::vector &used_filaments) +{ + if (layer_filament_nozzle_maps.empty() || used_filaments.empty()) + return false; + + for (auto filament_id_u : used_filaments) { + int filament_id = static_cast(filament_id_u); + std::set nozzle_ids; + + for (size_t layer_id = 0; layer_id < layer_filament_nozzle_maps.size(); ++layer_id) { + const auto &map = layer_filament_nozzle_maps[layer_id]; + if (filament_id < 0 || filament_id >= static_cast(map.size())) + continue; + + int nozzle_id = map[filament_id]; + if (nozzle_id < 0) + continue; + + nozzle_ids.insert(nozzle_id); + if (nozzle_ids.size() > 1) + return true; + } + } + + return false; +} + +std::optional LayeredNozzleGroupResult::create( + const std::vector& filament_nozzle_map, + const std::vector& nozzle_list, + const std::vector& used_filaments) +{ + if (filament_nozzle_map.empty() || nozzle_list.empty()) { + return std::nullopt; + } + + LayeredNozzleGroupResult result(false); + result._default_filament_nozzle_map = filament_nozzle_map; + result._nozzle_list = nozzle_list; + result._used_filaments = used_filaments; + + return result; +} + +std::optional LayeredNozzleGroupResult::create( + const std::vector>& layer_filament_nozzle_maps, + const std::vector& nozzle_list, + const std::vector& used_filaments, + const std::vector>& layer_filament_sequences) +{ + if (layer_filament_nozzle_maps.empty() || nozzle_list.empty()) { + return std::nullopt; + } + + bool support_dynamic_nozzle_map = has_filament_mapped_to_multiple_nozzles(layer_filament_nozzle_maps, used_filaments); + LayeredNozzleGroupResult result(support_dynamic_nozzle_map); + result._layer_filament_nozzle_maps = layer_filament_nozzle_maps; + result._layer_filament_sequences = layer_filament_sequences; + result._nozzle_list = nozzle_list; + result._used_filaments = used_filaments; + + if (!layer_filament_nozzle_maps.empty()) { + result._default_filament_nozzle_map = layer_filament_nozzle_maps[0]; + } + + return result; +} + +std::optional LayeredNozzleGroupResult::create( + const std::vector& used_filaments, + const std::vector& filament_map, + const std::vector& filament_volume_map, + const std::vector& filament_nozzle_map, + const std::vector> &nozzle_count, + float diameter) +{ + std::vector nozzle_groups; + for (size_t extruder_id = 0; extruder_id < nozzle_count.size(); ++extruder_id) { + for (auto elem : nozzle_count[extruder_id]) { + NozzleGroupInfo group_info; + group_info.diameter = format_diameter_to_str(diameter); + group_info.volume_type = elem.first; + group_info.nozzle_count = elem.second; + group_info.extruder_id = static_cast(extruder_id); + nozzle_groups.emplace_back(group_info); + } + } + + auto nozzle_list = build_nozzle_list(nozzle_groups); + std::vector used_nozzle(nozzle_list.size(), false); + std::map input_nozzle_id_to_output; + std::vector output_nozzle_map(filament_nozzle_map.size(), 0); + + for (auto filament_idx : used_filaments) { + NozzleVolumeType req_type = NozzleVolumeType(filament_volume_map[filament_idx]); + int req_extruder = filament_map[filament_idx]; + int input_nozzle_idx = filament_nozzle_map[filament_idx]; + + if (input_nozzle_id_to_output.find(input_nozzle_idx) != input_nozzle_id_to_output.end()) { + output_nozzle_map[filament_idx] = input_nozzle_id_to_output[input_nozzle_idx]; + continue; + } + + int output_nozzle_idx = -1; + for (size_t nozzle_idx = 0; nozzle_idx < nozzle_list.size(); ++nozzle_idx) { + if (used_nozzle[nozzle_idx]) continue; + + auto &nozzle_info = nozzle_list[nozzle_idx]; + if (!(nozzle_info.extruder_id == req_extruder && nozzle_info.volume_type == req_type)) continue; + + output_nozzle_idx = static_cast(nozzle_idx); + input_nozzle_id_to_output[input_nozzle_idx] = output_nozzle_idx; + used_nozzle[nozzle_idx] = true; + break; + } + + if (output_nozzle_idx == -1) { return std::nullopt; } + output_nozzle_map[filament_idx] = output_nozzle_idx; + } + + return create(output_nozzle_map, nozzle_list, used_filaments); +} + +bool LayeredNozzleGroupResult::are_filaments_same_extruder(int filament_id1, int filament_id2, int layer_id) const +{ + std::optional nozzle_info1 = get_nozzle_for_filament(filament_id1, layer_id); + std::optional nozzle_info2 = get_nozzle_for_filament(filament_id2, layer_id); + + if (!nozzle_info1 || !nozzle_info2) return false; + + return nozzle_info1->extruder_id == nozzle_info2->extruder_id; +} + +bool LayeredNozzleGroupResult::are_filaments_same_nozzle(int filament_id1, int filament_id2, int layer_id) const +{ + std::optional nozzle_info1 = get_nozzle_for_filament(filament_id1, layer_id); + std::optional nozzle_info2 = get_nozzle_for_filament(filament_id2, layer_id); + if (!nozzle_info1 || !nozzle_info2) return false; + + return nozzle_info1->group_id == nozzle_info2->group_id; +} + +int LayeredNozzleGroupResult::get_extruder_count() const +{ + std::set extruder_ids; + for (const auto &nozzle : _nozzle_list) { extruder_ids.insert(nozzle.extruder_id); } + return static_cast(extruder_ids.size()); +} + +std::vector LayeredNozzleGroupResult::get_used_nozzles_in_extruder(int target_extruder_id) const +{ + return get_used_nozzles_in_extruder(target_extruder_id, -1); +} + +std::vector LayeredNozzleGroupResult::get_used_nozzles_in_extruder(int target_extruder_id, int layer_id) const +{ + std::set nozzle_ids; + std::vector result; + + std::vector target_filaments = get_used_filaments(layer_id); + + for (unsigned int filament_id : target_filaments) { + if (layer_id != -1) { + auto nozzle_opt = get_nozzle_for_filament(static_cast(filament_id), layer_id); + if (nozzle_opt) { + if (target_extruder_id == -1 || nozzle_opt->extruder_id == target_extruder_id) { nozzle_ids.insert(nozzle_opt->group_id); } + } + } else { + auto nozzles = get_nozzles_for_filament(static_cast(filament_id)); + for (const auto &nozzle : nozzles) { + if (target_extruder_id == -1 || nozzle.extruder_id == target_extruder_id) { nozzle_ids.insert(nozzle.group_id); } + } + } + } + for (int nozzle_id : nozzle_ids) { + if (nozzle_id >= 0 && nozzle_id < static_cast(_nozzle_list.size())) { result.push_back(_nozzle_list[nozzle_id]); } + } + return result; +} + +std::vector LayeredNozzleGroupResult::get_used_extruders() const +{ + return get_used_extruders(-1); +} + +std::vector LayeredNozzleGroupResult::get_used_extruders(int layer_id) const +{ + std::set used_extruders; + // used filaments on the given layer (or globally) + std::vector target_filaments = get_used_filaments(layer_id); + for (auto filament_id : target_filaments) { + if (layer_id != -1) { + // single-layer: nozzle used by this filament on this layer + auto nozzle_opt = get_nozzle_for_filament(static_cast(filament_id), layer_id); + if (nozzle_opt) { used_extruders.insert(nozzle_opt->extruder_id); } + } else { + // global: every nozzle this filament uses across all layers + auto nozzles = get_nozzles_for_filament(static_cast(filament_id)); + for (const auto &nozzle : nozzles) { used_extruders.insert(nozzle.extruder_id); } + } + } + return std::vector(used_extruders.begin(), used_extruders.end()); +} + +std::vector LayeredNozzleGroupResult::get_extruder_map(bool zero_based, int layer_id) const +{ + const std::vector &filament_nozzle_map = get_layer_filament_nozzle_map(layer_id); + std::vector extruder_map(filament_nozzle_map.size()); + for (size_t idx = 0; idx < filament_nozzle_map.size(); ++idx) { + int nozzle_id = filament_nozzle_map[idx]; + if (nozzle_id >= 0 && nozzle_id < static_cast(_nozzle_list.size())) { + extruder_map[idx] = _nozzle_list[nozzle_id].extruder_id; + } else { + extruder_map[idx] = -1; + } + } + + if (zero_based) return extruder_map; + + auto new_filament_map = extruder_map; + std::transform(new_filament_map.begin(), new_filament_map.end(), new_filament_map.begin(), [](int val) { return val + 1; }); + return new_filament_map; +} + +std::vector LayeredNozzleGroupResult::get_nozzle_map(int layer_id) const +{ + const std::vector &filament_nozzle_map = get_layer_filament_nozzle_map(layer_id); + std::vector nozzle_map(filament_nozzle_map.size()); + for (size_t idx = 0; idx < filament_nozzle_map.size(); ++idx) { + int nozzle_id = filament_nozzle_map[idx]; + if (nozzle_id >= 0 && nozzle_id < static_cast(_nozzle_list.size())) { + nozzle_map[idx] = _nozzle_list[nozzle_id].group_id; + } else { + nozzle_map[idx] = -1; + } + } + return nozzle_map; +} + +std::vector LayeredNozzleGroupResult::get_volume_map(int layer_id) const +{ + const std::vector &filament_nozzle_map = get_layer_filament_nozzle_map(layer_id); + std::vector volume_map(filament_nozzle_map.size()); + for (size_t idx = 0; idx < filament_nozzle_map.size(); ++idx) { + int nozzle_id = filament_nozzle_map[idx]; + if (nozzle_id >= 0 && nozzle_id < static_cast(_nozzle_list.size())) { + volume_map[idx] = _nozzle_list[nozzle_id].volume_type; + } else { + volume_map[idx] = -1; + } + } + return volume_map; +} + +std::vector LayeredNozzleGroupResult::get_used_filaments(int layer_id) const +{ + if (layer_id < 0) { return _used_filaments; } + if (layer_id >= static_cast(_layer_filament_nozzle_maps.size())) { return _used_filaments; } + + if (!_layer_filament_sequences.empty() && layer_id < static_cast(_layer_filament_sequences.size())) { + return _layer_filament_sequences[layer_id]; + } + return {}; +} + +std::optional LayeredNozzleGroupResult::get_nozzle_for_filament(int filament_id, int layer_id) const +{ + const std::vector &filament_nozzle_map = get_layer_filament_nozzle_map(layer_id); + + if (filament_id < 0 || filament_id >= static_cast(filament_nozzle_map.size())) { return std::nullopt; } + + int nozzle_id = filament_nozzle_map[filament_id]; + return get_nozzle_from_id(nozzle_id); +} + +std::vector LayeredNozzleGroupResult::get_nozzles_for_filament(int filament_id) const +{ + std::set nozzle_ids; + + if (!support_dynamic_nozzle_map) { + if (filament_id >= 0 && filament_id < static_cast(_default_filament_nozzle_map.size())) { + nozzle_ids.insert(_default_filament_nozzle_map[filament_id]); + } + } else { + int start_layer = 0; + int end_layer = static_cast(_layer_filament_nozzle_maps.size()); + + for (int i = start_layer; i < end_layer; ++i) { + const auto &map = _layer_filament_nozzle_maps[i]; + if (filament_id >= 0 && filament_id < static_cast(map.size())) { + nozzle_ids.insert(map[filament_id]); + } + } + } + + std::vector result; + for (int id : nozzle_ids) { + if (id >= 0 && id < static_cast(_nozzle_list.size())) { result.push_back(_nozzle_list[id]); } + } + return result; +} + +std::optional LayeredNozzleGroupResult::get_first_nozzle_for_filament(int filament_id) const +{ + if (filament_id < 0) return std::nullopt; + + if (!support_dynamic_nozzle_map) { + if (filament_id >= static_cast(_default_filament_nozzle_map.size())) return std::nullopt; + return get_nozzle_from_id(_default_filament_nozzle_map[filament_id]); + } + + for (size_t layer = 0; layer < _layer_filament_nozzle_maps.size(); ++layer) { + auto layer_used_filaments = get_used_filaments(layer); + if (std::find(layer_used_filaments.begin(), layer_used_filaments.end(), static_cast(filament_id)) == layer_used_filaments.end()){ + continue; + } + const auto &map = _layer_filament_nozzle_maps[layer]; + if (filament_id >= 0 && filament_id < static_cast(map.size())) { + int nozzle_id = map[filament_id]; + auto nozzle = get_nozzle_from_id(nozzle_id); + if (nozzle) return nozzle; + } + } + + return std::nullopt; +} + +std::optional LayeredNozzleGroupResult::get_nozzle_from_id(int nozzle_id) const +{ + if (nozzle_id < 0 || nozzle_id >= static_cast(_nozzle_list.size())) { return std::nullopt; } + return _nozzle_list[nozzle_id]; +} + +int LayeredNozzleGroupResult::get_extruder_id(int filament_id, int layer_id) const +{ + auto nozzle_info = get_nozzle_for_filament(filament_id, layer_id); + return nozzle_info ? nozzle_info->extruder_id : -1; +} + +int LayeredNozzleGroupResult::get_nozzle_id(int filament_id, int layer_id) const +{ + auto nozzle_info = get_nozzle_for_filament(filament_id, layer_id); + return nozzle_info ? nozzle_info->group_id : -1; +} + +const std::vector &LayeredNozzleGroupResult::get_layer_filament_nozzle_map(int layer_id) const +{ + if (layer_id >= 0 && layer_id < static_cast(_layer_filament_nozzle_maps.size())) { return _layer_filament_nozzle_maps[layer_id]; } + return _default_filament_nozzle_map; +} + +// ==================== filament-change-time model ==================== +FilamentChangeSimResult simulate_filament_change_time( + const std::vector& logical_filaments, + const std::vector& nozzle_list, + const std::vector& filament_change_seq, + const std::vector& nozzle_change_seq, + const std::vector& group_of_filament, + const FilamentChangeTimeParams& time_params, + const std::vector& ams_preload_enabled, + bool calc_sliced_time) +{ + FilamentChangeSimResult result; + if (logical_filaments.empty() || nozzle_list.empty() || filament_change_seq.empty() || nozzle_change_seq.empty()) + return result; + + // Re-map the parameter semantics: + // standard = AMS -> selector -> extruder (full path), selector = selector -> extruder (short path) + // so AMS -> selector = standard - selector + const float load_ams_to_selector = time_params.standard_load_time - time_params.selector_load_time; + const float unload_ams_to_selector = time_params.standard_unload_time - time_params.selector_unload_time; + const float load_selector_to_ext = time_params.selector_load_time; + const float unload_ext_to_selector = time_params.selector_unload_time; + + // nozzle_id -> extruder_id + std::unordered_map nozzle_to_extruder; + nozzle_to_extruder.reserve(nozzle_list.size()); + for (const auto& nozzle : nozzle_list) + nozzle_to_extruder[nozzle.group_id] = nozzle.extruder_id; + + // filament_id -> AMS group + std::unordered_map filament_to_group; + filament_to_group.reserve(logical_filaments.size()); + for (size_t i = 0; i < logical_filaments.size(); ++i) + filament_to_group[logical_filaments[i]] = group_of_filament[i]; + + const auto get_group = [&](int filament_id) -> int { + auto it = filament_to_group.find(filament_id); + return it != filament_to_group.end() ? it->second : -1; + }; + + const auto is_preload_enabled = [&](int group_id) -> bool { + if (group_id < 0 || group_id >= static_cast(ams_preload_enabled.size())) + return false; + return ams_preload_enabled[group_id]; + }; + + // Filament location states + enum class Location { IN_AMS, IN_SELECTOR, IN_EXTRUDER }; + std::unordered_map filament_location; // filament_id -> current location + std::unordered_map filament_extruder; // filament_id -> extruder it sits in (only valid when IN_EXTRUDER) + std::unordered_map extruder_filament; // extruder_id -> currently loaded filament + // group_id -> filaments currently occupying that AMS channel (IN_SELECTOR or IN_EXTRUDER) + std::unordered_map> ams_group_occupied; + + filament_location.reserve(logical_filaments.size()); + filament_extruder.reserve(logical_filaments.size()); + + // Initial state: every filament is in the AMS, every extruder is empty + for (int f : logical_filaments) + filament_location[f] = Location::IN_AMS; + + // Slicer-estimate simulator: use NozzleStatusRecorder to track what each nozzle/extruder holds during slicing + NozzleStatusRecorder sliced_recorder; + + const size_t seq_len = std::min(filament_change_seq.size(), nozzle_change_seq.size()); + double actual_time = 0.0; + double sliced_time = 0.0; + + for (size_t i = 0; i < seq_len; ++i) { + int B = filament_change_seq[i]; + int nozzle_id = nozzle_change_seq[i]; + + auto nozzle_iter = nozzle_to_extruder.find(nozzle_id); + if (nozzle_iter == nozzle_to_extruder.end()) continue; + + int E = nozzle_iter->second; // target extruder + + // Step 0: compute the slicer-estimated time + // Slicer estimate: simulate the slicer's view (no selector awareness); + // count a load/unload when nozzle_in_extruder_change || filament_in_nozzle_change + if (calc_sliced_time) { + int old_nozzle_in_E = sliced_recorder.get_nozzle_in_extruder(E); + int old_filament_in_nozzle = sliced_recorder.get_filament_in_nozzle(nozzle_id); + int old_filament_in_ext = sliced_recorder.get_filament_in_nozzle(old_nozzle_in_E); + + bool nozzle_change = (old_nozzle_in_E != nozzle_id); + bool filament_change = (old_filament_in_nozzle != B); + + if (nozzle_change || filament_change) { + if (old_filament_in_ext != -1) + sliced_time += time_params.standard_unload_time; + sliced_time += time_params.standard_load_time; + } + sliced_recorder.set_nozzle_status(nozzle_id, B, E); + } + + // Step 1: find the filament A currently loaded in the target extruder E + int A = -1; + { + auto it = extruder_filament.find(E); + if (it != extruder_filament.end()) + A = it->second; + } + + int group_B = get_group(B); + int group_A = (A != -1) ? get_group(A) : -1; + + // Step 2: clear B's AMS-channel occupancy + auto group_it = ams_group_occupied.find(group_B); + if (group_it != ams_group_occupied.end()) { + for (int X : group_it->second) { + if (X == B) continue; + // X shares B's AMS channel, retreat it to the AMS to make way + Location loc_X = filament_location[X]; + if (loc_X == Location::IN_EXTRUDER) { + actual_time += unload_ext_to_selector + unload_ams_to_selector; + int E2 = filament_extruder[X]; + extruder_filament.erase(E2); + filament_extruder.erase(X); + } else if (loc_X == Location::IN_SELECTOR) { + actual_time += unload_ams_to_selector; + } + filament_location[X] = Location::IN_AMS; + } + group_it->second.clear(); + } + + // Step 3: A exits E (while A is still in the extruder) + // Step 3.5: pre-load B (in parallel with Step 3) + // actual time = max(Step 3, Step 3.5) + bool step3_executed = false; + float step3_time = 0.0f; + if (A != -1 && A != B && filament_location[A] == Location::IN_EXTRUDER) { + if (is_preload_enabled(group_A) && group_A != group_B) { + step3_time = unload_ext_to_selector; + filament_location[A] = Location::IN_SELECTOR; + } else { + step3_time = unload_ext_to_selector + unload_ams_to_selector; + filament_location[A] = Location::IN_AMS; + ams_group_occupied[group_A].erase(A); + } + extruder_filament.erase(E); + filament_extruder.erase(A); + step3_executed = true; + } + + float step3_5_time = 0.0f; + if (step3_executed && + filament_location[B] == Location::IN_AMS && + group_A != group_B && + is_preload_enabled(group_B)) { + step3_5_time = load_ams_to_selector; + filament_location[B] = Location::IN_SELECTOR; + ams_group_occupied[group_B].insert(B); + } + + actual_time += std::max(step3_time, step3_5_time); + + // Step 4: push B into E + // Step 6: pre-load the next filament C (in parallel with Step 4) + // actual time = max(Step 4, Step 6) + float step4_time = 0.0f; + Location loc_B = filament_location[B]; + if (loc_B == Location::IN_AMS) { + step4_time = load_ams_to_selector + load_selector_to_ext; + } else if (loc_B == Location::IN_SELECTOR) { + step4_time = load_selector_to_ext; + } + + // Step 5: update state + extruder_filament[E] = B; + filament_location[B] = Location::IN_EXTRUDER; + filament_extruder[B] = E; + ams_group_occupied[group_B].insert(B); + + float step6_time = 0.0f; + if (i + 1 < seq_len) { + int C = filament_change_seq[i + 1]; + int group_C = get_group(C); + if (filament_location[C] == Location::IN_AMS && + group_C != group_B && + is_preload_enabled(group_C) && + ams_group_occupied[group_C].empty()) { + step6_time = load_ams_to_selector; + filament_location[C] = Location::IN_SELECTOR; + ams_group_occupied[group_C].insert(C); + } + } + + actual_time += std::max(step4_time, step6_time); + } + + result.actual_time = actual_time; + result.sliced_time = sliced_time; + return result; +} + +// ==================== NozzleStatusRecorder implementation ==================== + +bool NozzleStatusRecorder::is_nozzle_empty(int nozzle_id) const +{ + auto iter = nozzle_filament_status.find(nozzle_id); + if (iter == nozzle_filament_status.end()) return true; + return false; +} + +int NozzleStatusRecorder::get_filament_in_nozzle(int nozzle_id) const +{ + auto iter = nozzle_filament_status.find(nozzle_id); + if (iter == nozzle_filament_status.end()) return -1; + return iter->second; +} + +int NozzleStatusRecorder::get_nozzle_in_extruder(int extruder_id) const +{ + auto iter = extruder_nozzle_status.find(extruder_id); + if (iter == extruder_nozzle_status.end()) return -1; + return iter->second; +} + +void NozzleStatusRecorder::set_nozzle_status(int nozzle_id, int filament_id, int extruder_id) +{ + nozzle_filament_status[nozzle_id] = filament_id; + if (extruder_id != -1) { + extruder_nozzle_status[extruder_id] = nozzle_id; + } +} + +void NozzleStatusRecorder::clear_nozzle_status(int nozzle_id) +{ + auto iter = nozzle_filament_status.find(nozzle_id); + if (iter == nozzle_filament_status.end()) return; + nozzle_filament_status.erase(iter); +} + +int LayeredNozzleGroupResult::estimate_seq_flush_weight(const std::vector>>& flush_matrix, const std::vector& filament_change_seq) const +{ + auto get_weight_from_volume = [](float volume){ + return static_cast(volume * 1.26 * 0.01); + }; + + float total_flush_volume = 0; + NozzleStatusRecorder recorder; + for(auto filament: filament_change_seq){ + auto nozzle = get_nozzle_for_filament(filament, -1); + if(!nozzle) + continue; + + int extruder_id = nozzle->extruder_id; + int nozzle_id = nozzle->group_id; + int last_filament = recorder.get_filament_in_nozzle(nozzle_id); + + if(last_filament!= -1 && last_filament != filament){ + // bounds check to avoid out-of-range access + if (extruder_id >= 0 && extruder_id < static_cast(flush_matrix.size()) && + last_filament >= 0 && last_filament < static_cast(flush_matrix[extruder_id].size()) && + filament >= 0 && filament < static_cast(flush_matrix[extruder_id][last_filament].size())) { + float flush_volume = flush_matrix[extruder_id][last_filament][filament]; + total_flush_volume += flush_volume; + } + } + recorder.set_nozzle_status(nozzle_id, filament); + } + + return get_weight_from_volume(total_flush_volume); +} + +// ==================== StaticNozzleGroupResult ==================== + +std::optional StaticNozzleGroupResult::create( + const std::vector& filaments_info, + const std::vector& nozzles_info, + const std::vector& filament_change_seq, + const std::vector& nozzle_change_seq, + bool support_dynamic_nozzle_map) +{ + if (filaments_info.empty() || nozzles_info.empty()) return std::nullopt; + + std::map nozzle_list_map; + std::map> filament_to_nozzles; + + for (auto nozzle_info : nozzles_info) + nozzle_list_map[nozzle_info.group_id] = nozzle_info; + + for (auto filament_info : filaments_info) { + auto fil_id = filament_info.id; + auto nozzles_id = filament_info.group_id; + std::set nozzles_set(nozzles_id.begin(), nozzles_id.end()); + // Backward compat with older (single-nozzle) gcode.3mf: filament has no group_id, avoid an empty map. + if (nozzles_set.empty()) { + for (const auto& nozzle_entry : nozzle_list_map) + nozzles_set.insert(nozzle_entry.first); + } + filament_to_nozzles[fil_id] = nozzles_set; + } + + StaticNozzleGroupResult result(support_dynamic_nozzle_map); + result._filament_to_nozzles = filament_to_nozzles; + result._nozzle_list_map = nozzle_list_map; + result._filament_change_seq = filament_change_seq; + result._nozzle_change_seq = nozzle_change_seq; + + return result; +} + +std::optional StaticNozzleGroupResult::get_nozzle_from_id(int nozzle_id) const +{ + auto iter = _nozzle_list_map.find(nozzle_id); + if (iter == _nozzle_list_map.end()) { return std::nullopt; } + return iter->second; +} + +int StaticNozzleGroupResult::get_extruder_count() const +{ + std::set extruder_ids; + for (const auto &elem : _nozzle_list_map) { extruder_ids.insert(elem.second.extruder_id); } + return static_cast(extruder_ids.size()); +} + +std::vector StaticNozzleGroupResult::get_used_nozzles_in_extruder(int target_extruder_id) const +{ + std::vector result; + for (const auto &elem : _nozzle_list_map) { + const auto &nozzle = elem.second; + if (target_extruder_id == -1 || nozzle.extruder_id == target_extruder_id) { + result.push_back(nozzle); + } + } + return result; +} + +std::vector StaticNozzleGroupResult::get_used_extruders() const +{ + std::set used_extruders; + for (const auto &elem : _nozzle_list_map) { used_extruders.insert(elem.second.extruder_id); } + return std::vector(used_extruders.begin(), used_extruders.end()); +} + +std::vector StaticNozzleGroupResult::get_used_filaments() const +{ + std::vector used_filaments; + used_filaments.reserve(_filament_to_nozzles.size()); + for (const auto &elem : _filament_to_nozzles) { + if (elem.first >= 0) { + used_filaments.push_back(static_cast(elem.first)); + } + } + return used_filaments; +} + +std::vector StaticNozzleGroupResult::get_nozzles_for_filament(int filament_id) const +{ + auto iter = _filament_to_nozzles.find(filament_id); + if (iter == _filament_to_nozzles.end()) { return std::vector(); } + + std::vector result; + for (int nozzle_id : iter->second) { + auto nozzle_iter = _nozzle_list_map.find(nozzle_id); + if (nozzle_iter != _nozzle_list_map.end()) { + result.push_back(nozzle_iter->second); + } + } + return result; +} + +std::optional StaticNozzleGroupResult::get_first_nozzle_for_filament(int filament_id) const +{ + if (filament_id < 0) return std::nullopt; + + if (!_filament_change_seq.empty() && _filament_change_seq.size() == _nozzle_change_seq.size()) { + for (size_t idx = 0; idx < _filament_change_seq.size(); ++idx) { + if (_filament_change_seq[idx] == filament_id) { + int nozzle_id = _nozzle_change_seq[idx]; + auto nozzle = get_nozzle_from_id(nozzle_id); + if (nozzle) return nozzle; + } + } + } + + auto iter = _filament_to_nozzles.find(filament_id); + if (iter == _filament_to_nozzles.end()) return std::nullopt; + + for (int nozzle_id : iter->second) { + auto nozzle = get_nozzle_from_id(nozzle_id); + if (nozzle) return nozzle; + } + + return std::nullopt; +} + +// ==================== serialization ==================== + +std::string NozzleInfo::serialize() const +{ + std::ostringstream oss; + oss << "id=\"" << group_id << "\" " + << "extruder_id=\"" << extruder_id + 1 << "\" " + << "nozzle_diameter=\"" << diameter << "\" " + << "volume_type=\"" << get_nozzle_volume_type_string(volume_type) << "\""; + return oss.str(); +} + +std::string NozzleGroupInfo::serialize() const +{ + std::ostringstream oss; + oss << extruder_id << "-" + << std::setprecision(2) << diameter << "-" + << get_nozzle_volume_type_string(volume_type) << "-" + << nozzle_count; + return oss.str(); +} + +std::optional NozzleGroupInfo::deserialize(const std::string &str) +{ + std::istringstream iss(str); + std::string token; + std::vector tokens; + + while (std::getline(iss, token, '-')) { tokens.push_back(token); } + + if (tokens.size() != 4) { return std::nullopt; } + + try { + int extruder_id = std::stoi(tokens[0]); + std::string diameter = tokens[1]; + NozzleVolumeType volume_type = NozzleVolumeType(ConfigOptionEnum::get_enum_values().at(tokens[2])); + int nozzle_count = std::stoi(tokens[3]); + + return NozzleGroupInfo(diameter, volume_type, extruder_id, nozzle_count); + } catch (const std::exception &) { + return std::nullopt; + } +} + +std::vector load_nozzle_infos_with_compatibility( + const std::vector& nozzle_infos, + const std::vector& filament_infos, + const std::vector& filament_map, + const std::vector& extruder_volume_types, + const std::vector& nozzle_diameter +) +{ + bool has_nozzle_info = !nozzle_infos.empty(); + bool has_valid_filament_info = !filament_infos.empty() && std::all_of(filament_infos.begin(), filament_infos.end(), [](const FilamentInfo& info){ + return info.group_id.size() == 1; + }); + + if(!has_nozzle_info && !has_valid_filament_info){ + BOOST_LOG_TRIVIAL(warning)<<__FUNCTION__ << ": building nozzle list from filament map and volume types"; + + // Backward compatibility for older gcode.3mf: + // - nozzle_diameter is always present and its size defines extruder count. + // - filament_map may be missing; treat it as [0, 0, ...] for each extruder. + // - extruder_volume_types may be missing; treat it as all Standard. + const size_t extruder_count = nozzle_diameter.size(); + + std::vector volume_types_fixed = extruder_volume_types; + volume_types_fixed.resize(extruder_count, NozzleVolumeType::nvtStandard); + + std::vector result; + result.reserve(extruder_count); + for (size_t extruder_id = 0; extruder_id < extruder_count; ++extruder_id) { + NozzleInfo info; + info.diameter = format_diameter_to_str(nozzle_diameter[extruder_id]); + info.group_id = static_cast(extruder_id); + info.extruder_id = static_cast(extruder_id); + info.volume_type = volume_types_fixed[extruder_id]; + result.emplace_back(std::move(info)); + } + return result; + } + + if(!has_nozzle_info){ + BOOST_LOG_TRIVIAL(info)<<__FUNCTION__ << ": building nozzle list from filament info"; + std::map nozzle_map; // group_id -> NozzleInfo + for(auto& filament : filament_infos){ + int group_id = filament.group_id.front(); + if(group_id < 0 || nozzle_map.find(group_id) != nozzle_map.end()){ + continue; + } + + auto volume_type_str_to_enum = ConfigOptionEnum::get_enum_values(); + + NozzleInfo info; + info.diameter = format_diameter_to_str(filament.nozzle_diameter); + info.group_id = group_id; + // Orca: bounds-check filament_map[filament.id] so a malformed 3mf (filament id + // beyond the map) degrades to extruder 0 instead of dereferencing out of range. + info.extruder_id = (filament.id >= 0 && filament.id < static_cast(filament_map.size())) + ? filament_map[filament.id] - 1 + : 0; // to 0-based + + if (volume_type_str_to_enum.count(filament.nozzle_volume_type)) + info.volume_type = NozzleVolumeType(volume_type_str_to_enum.at(filament.nozzle_volume_type)); + else { + info.volume_type = NozzleVolumeType::nvtStandard; + } + + nozzle_map[group_id] = std::move(info); + } + + std::vector ret; + for(auto& elem : nozzle_map){ + ret.emplace_back(elem.second); + } + return ret; + } + + auto result = nozzle_infos; + std::sort(result.begin(), result.end()); + BOOST_LOG_TRIVIAL(info)<<__FUNCTION__ << ": using new 3mf format with " << result.size() << " nozzle infos."; + return result; +} + +}} // namespace Slic3r::MultiNozzleUtils diff --git a/src/libslic3r/MultiNozzleUtils.hpp b/src/libslic3r/MultiNozzleUtils.hpp new file mode 100644 index 0000000000..f9b96bd79a --- /dev/null +++ b/src/libslic3r/MultiNozzleUtils.hpp @@ -0,0 +1,288 @@ +#ifndef MULTI_NOZZLE_UTILS_HPP +#define MULTI_NOZZLE_UTILS_HPP + +#include +#include +#include +#include +#include +#include "PrintConfig.hpp" + +// Multi-nozzle support types. +// Declares the filament-grouping result types the slicing pipeline needs, plus the analytic +// filament-change-time model (FilamentChangeTimeParams, NozzleStatusRecorder, +// FilamentChangeSimResult, simulate_filament_change_time) — self-contained analytic code that +// never touches the time estimator; its first consumer is the filament_group golden harness. +// The gcode.3mf serialization surface lives here too: NozzleInfo/NozzleGroupInfo +// serialize+deserialize, the device-side StaticNozzleGroupResult, +// load_nozzle_infos_with_compatibility (the backward-compat 3mf reader) and +// LayeredNozzleGroupResult::estimate_seq_flush_weight. The change-time-tuning helpers +// calc_filament_change_gap_for_assignment / find_optimal_physical_assignment (used only by the +// AMS pre-load optimizer, a later feature) are not implemented here. + +namespace Slic3r { +struct FilamentInfo; // Slic3r::FilamentInfo (ProjectTask.hpp) — consumed by StaticNozzleGroupResult / the 3mf reader +namespace MultiNozzleUtils { + +// Information about a single logical nozzle. +struct NozzleInfo +{ + std::string diameter; + NozzleVolumeType volume_type; + int extruder_id{-1}; // logical extruder id + int group_id{-1}; // logical nozzle id + + std::string serialize() const; + + bool operator<(const NozzleInfo& other) const { + if(group_id != other.group_id) return group_id < other.group_id; + if(extruder_id != other.extruder_id) return extruder_id < other.extruder_id; + if(volume_type != other.volume_type) return volume_type < other.volume_type; + return diameter < other.diameter; + } +}; + +// A group of identical nozzles on one extruder (diameter + volume type + count). +struct NozzleGroupInfo +{ + std::string diameter; + NozzleVolumeType volume_type; + int extruder_id; + int nozzle_count; + + NozzleGroupInfo() = default; + + NozzleGroupInfo(const std::string& nozzle_diameter_, const NozzleVolumeType volume_type_, const int extruder_id_, const int nozzle_count_) + : diameter(nozzle_diameter_), volume_type(volume_type_), extruder_id(extruder_id_), nozzle_count(nozzle_count_) + {} + + inline bool operator<(const NozzleGroupInfo &rhs) const + { + if (extruder_id != rhs.extruder_id) return extruder_id < rhs.extruder_id; + if (diameter != rhs.diameter) return diameter < rhs.diameter; + if (volume_type != rhs.volume_type) return volume_type < rhs.volume_type; + return nozzle_count < rhs.nozzle_count; + } + + bool is_same_type(const NozzleGroupInfo &rhs) const + { + return diameter == rhs.diameter && volume_type == rhs.volume_type && extruder_id == rhs.extruder_id; + } + + inline bool operator==(const NozzleGroupInfo &rhs) const + { + return diameter == rhs.diameter && volume_type == rhs.volume_type && extruder_id == rhs.extruder_id && nozzle_count == rhs.nozzle_count; + } + + std::string serialize() const; + static std::optional deserialize(const std::string& str); +}; + +// Load/unload time constants used by the filament-change-time model. +// Consumed by simulate_filament_change_time() below and carried by the grouping-context +// substrate (FilamentGroupContext::SpeedInfo). +struct FilamentChangeTimeParams +{ + float selector_load_time{0.0f}; + float selector_unload_time{0.0f}; + float standard_load_time{0.0f}; + float standard_unload_time{0.0f}; +}; + +/** + * @brief Abstract base for a nozzle-grouping result. + */ +class NozzleGroupResultBase +{ +protected: + bool support_dynamic_nozzle_map{false}; // whether dynamic (selector) mapping is used + +public: + NozzleGroupResultBase(bool support_dynamic_map = false) : support_dynamic_nozzle_map(support_dynamic_map) {} + virtual ~NozzleGroupResultBase() = default; + + virtual std::optional get_nozzle_from_id(int nozzle_id) const = 0; + virtual std::optional get_first_nozzle_for_filament(int filament_id) const = 0; // logical nozzle a filament first uses + + virtual std::vector get_nozzles_for_filament(int filament_id) const = 0; // every nozzle a filament may use (across all layers) + + bool is_support_dynamic_nozzle_map() const { return support_dynamic_nozzle_map; } + + virtual int get_extruder_count() const = 0; + + virtual std::vector get_used_nozzles_in_extruder(int extruder_id =-1) const = 0; + virtual std::vector get_used_extruders() const = 0; + virtual std::vector get_used_filaments() const = 0; +}; + +/** + * @brief Layer-aware nozzle-grouping result. + * Used by the back-end slicing code; supports per-layer nozzle mapping. + */ +class LayeredNozzleGroupResult : public NozzleGroupResultBase +{ +private: + std::vector> _layer_filament_nozzle_maps; // per-layer filament -> nozzle map + std::vector> _layer_filament_sequences; // per-layer filament print order + std::vector _default_filament_nozzle_map; // global filament -> nozzle map + std::vector _used_filaments; // all used filament indices + std::vector _nozzle_list; // global nozzle list + +public: + LayeredNozzleGroupResult(bool support_dynamic_map = false) : NozzleGroupResultBase(support_dynamic_map) {} + + // No selector: one global filament->nozzle map. + static std::optional create( + const std::vector& filament_nozzle_map, + const std::vector& nozzle_list, + const std::vector& used_filaments); + + // Selector: built from per-layer maps (each layer may differ). + static std::optional create( + const std::vector>& layer_filament_nozzle_maps, + const std::vector& nozzle_list, + const std::vector& used_filaments, + const std::vector>& layer_filament_sequences); + + // Multi-nozzle without selector: resolve each requested logical nozzle to a physical nozzle. + static std::optional create( + const std::vector& used_filaments, + const std::vector& filament_map, + const std::vector& filament_volume_map, + const std::vector& filament_nozzle_map, + const std::vector>& nozzle_count, + float diameter); + + bool are_filaments_same_extruder(int filament_id1, int filament_id2, int layer_id = -1) const; + bool are_filaments_same_nozzle(int filament_id1, int filament_id2, int layer_id = -1) const; + int get_extruder_count() const override; + + std::vector get_used_nozzles_in_extruder(int target_extruder_id = -1) const override; + std::vector get_used_nozzles_in_extruder(int target_extruder_id, int layer_id) const; // layer_id=-1 uses default map + std::vector get_used_extruders() const override; + std::vector get_used_extruders(int layer_id) const; // layer_id=-1 returns global extruders + + std::vector get_extruder_map(bool zero_based = true, int layer_id = -1) const; + std::vector get_nozzle_map(int layer_id = -1) const; + std::vector get_volume_map(int layer_id = -1) const; + + std::vector get_used_filaments() const override { return _used_filaments; } + std::vector get_used_filaments(int layer_id) const; + + std::optional get_nozzle_for_filament(int filament_id, int layer_id = -1) const; + std::vector get_nozzles_for_filament(int filament_id) const override; + + std::optional get_nozzle_from_id(int nozzle_id) const override; + std::optional get_first_nozzle_for_filament(int filament_id) const override; + int get_extruder_id(int filament_id, int layer_id = -1) const; + int get_nozzle_id(int filament_id, int layer_id = -1) const; + + size_t get_layer_count() const { return _layer_filament_nozzle_maps.size(); } + const std::vector& get_layer_filament_nozzle_map(int layer_id) const; + const std::vector> &get_layer_filament_nozzle_maps() const { return _layer_filament_nozzle_maps; } + const std::vector>& get_layer_filament_sequences() const { return _layer_filament_sequences; } + + // Estimate the flush weight of a filament-change sequence given the per-extruder flush matrix + // (extruder -> from-filament -> to-filament). + int estimate_seq_flush_weight(const std::vector>>& flush_matrix, const std::vector& filament_change_seq) const; +}; + +/** + * @brief Layer-less nozzle-grouping result for the device side (static nozzle mapping only). + * Reconstructed from a loaded gcode.3mf together with the filament/nozzle change sequences. + */ +class StaticNozzleGroupResult : public NozzleGroupResultBase +{ +private: + std::map> _filament_to_nozzles; // every nozzle a filament may map to + std::map _nozzle_list_map; // used nozzles, keyed by logical nozzle id + std::vector _filament_change_seq; // filament sequence used to resolve first-use + std::vector _nozzle_change_seq; // logical-nozzle sequence paired with the filament sequence + +public: + StaticNozzleGroupResult(bool support_dynamic_map) : NozzleGroupResultBase(support_dynamic_map) {} + // Build from a loaded 3mf, with the filament/nozzle change sequences. + static std::optional create( + const std::vector& filaments_info, + const std::vector& nozzles_info, + const std::vector& filament_change_seq, + const std::vector& nozzle_change_seq, + bool support_dynamic_map); + + int get_extruder_count() const override; + std::vector get_used_nozzles_in_extruder(int extruder_id = -1) const override; + std::vector get_used_extruders() const override; + std::vector get_used_filaments() const override; + + std::optional get_nozzle_from_id(int nozzle_id) const override; + + std::vector get_nozzles_for_filament(int filament_id) const override; + std::optional get_first_nozzle_for_filament(int filament_id) const override; +}; + +// Tracks, during the filament-change simulation, which filament sits in each physical nozzle +// and which nozzle each extruder currently carries. +class NozzleStatusRecorder +{ +private: + std::unordered_map nozzle_filament_status; // Track filament in each nozzle + std::unordered_map extruder_nozzle_status; // Track nozzle for each extruder + int current_extruder_id_ = -1; // Track current extruder id + +public: + NozzleStatusRecorder() = default; + bool is_nozzle_empty(int nozzle_id) const; + int get_filament_in_nozzle(int nozzle_id) const; + int get_nozzle_in_extruder(int extruder_id) const; + int get_current_extruder_id() const { return current_extruder_id_; } + + void clear_nozzle_status(int nozzle_id); + void set_current_extruder_id(int extruder_id) { current_extruder_id_ = extruder_id; } + + // Update the status of a nozzle with new filament and extruder information + void set_nozzle_status(int nozzle_id, int filament_id, int extruder_id = -1); + + // key: nozzle id, value: filament id (-1 = the nozzle carries no filament) + const std::unordered_map& get_nozzle_filament_map() const { return nozzle_filament_status; } + // key: extruder id, value: nozzle id (-1 = the extruder carries no nozzle) + const std::unordered_map& get_extruder_nozzle_map() const { return extruder_nozzle_status; } +}; + +struct FilamentChangeSimResult { + double actual_time = 0.0; + double sliced_time = 0.0; +}; + +// Analytic filament-change-time model. Given the used filaments, the nozzle +// list, the filament/nozzle change sequences, each filament's AMS group and the load/unload time +// constants, it simulates AMS->selector->extruder transport (with optional AMS pre-load overlap) +// and returns the actual print time plus the slicer-estimated time. Self-contained: it never +// touches the g-code time estimator. +FilamentChangeSimResult simulate_filament_change_time( + const std::vector& logical_filaments, + const std::vector& nozzle_list, + const std::vector& filament_change_seq, + const std::vector& nozzle_change_seq, + const std::vector& group_of_filament, + const FilamentChangeTimeParams& time_params, + const std::vector& ams_preload_enabled = {}, + bool calc_sliced_time = false); + +// ==================== tool functions ==================== +std::vector build_nozzle_list(std::vector info); +std::vector build_nozzle_list(double diameter, const std::vector& filament_nozzle_map, + const std::vector& filament_volume_map, const std::vector& filament_map); +// Load nozzle infos from a gcode.3mf, handling backward compatibility with older 3mf that did not +// record standalone tags: falls back to the per-filament group_id/diameter/volume_type, and +// (for the oldest single-nozzle 3mf) to the filament_map + extruder volume types + nozzle diameters. +std::vector load_nozzle_infos_with_compatibility( + const std::vector& nozzle_infos, + const std::vector& filament_infos, + const std::vector& filament_map, + const std::vector& extruder_volume_types, + const std::vector& nozzle_diameter +); +} // namespace MultiNozzleUtils +} // namespace Slic3r + +#endif // MULTI_NOZZLE_UTILS_HPP diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 98a5a4fcb6..dea9e78906 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -252,7 +252,7 @@ void extend_default_config_length(DynamicPrintConfig& config, const bool set_nil auto replace_nil_and_resize = [&](const std::string & key, int length){ ConfigOption* raw_ptr = config.option(key); ConfigOptionVectorBase* opt_vec = static_cast(raw_ptr); - if(set_nil_to_default && raw_ptr->is_nil() && defaults.has(key) && std::find(filament_extruder_override_keys.begin(), filament_extruder_override_keys.end(), key) == filament_extruder_override_keys.end()){ + if(set_nil_to_default && raw_ptr->is_nil() && defaults.has(key) && !is_filament_extruder_override_key(key)){ opt_vec->clear(); opt_vec->resize(length, defaults.option(key)); } @@ -1312,7 +1312,7 @@ static std::vector s_Preset_print_options{ }; static std::vector s_Preset_filament_options {/*"filament_colour", */ "default_filament_colour", "required_nozzle_HRC", "filament_diameter", "pellet_flow_coefficient", "volumetric_speed_coefficients", "filament_type", - "filament_soluble", "filament_is_support", "filament_printable", + "filament_soluble", "filament_is_support", "filament_printable", "filament_extruder_compatibility", "filament_max_volumetric_speed", "filament_adaptive_volumetric_speed", "filament_flow_ratio", "filament_density", "filament_adhesiveness_category", "filament_cost", "filament_minimal_purge_on_wipe_tower", "filament_tower_interface_pre_extrusion_dist", "filament_tower_interface_pre_extrusion_length", "filament_tower_ironing_area", "filament_tower_interface_purge_volume", @@ -1347,7 +1347,13 @@ static std::vector s_Preset_filament_options {/*"filament_colour", "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control", "chamber_minimal_temperature", "filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature", //BBS filament change length while the extruder color - "filament_change_length","filament_flush_volumetric_speed","filament_flush_temp", "filament_cooling_before_tower", + "filament_change_length","filament_flush_volumetric_speed","filament_flush_temp","filament_flush_temp_fast", "filament_cooling_before_tower", + // Multi-nozzle pre-cooling / ramming / nozzle-change (nc) filament overrides + "filament_ramming_volumetric_speed", "filament_ramming_volumetric_speed_nc", + "filament_ramming_travel_time", "filament_ramming_travel_time_nc", + "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" }; @@ -1358,6 +1364,8 @@ static std::vector s_Preset_machine_limits_options { "machine_min_extruding_rate", "machine_min_travel_rate", "machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e", "machine_max_junction_deviation", + // Bedslinger mass/force limits + "machine_max_force_Y", "machine_bed_mass_Y", "machine_max_printed_mass", //resonance avoidance ported from qidi slicer "resonance_avoidance", "min_resonance_avoidance_speed", "max_resonance_avoidance_speed", // Orca: input shaping @@ -1375,7 +1383,7 @@ static std::vector s_Preset_printer_options { "default_print_profile", "inherits", "silent_mode", "scan_first_layer", "enable_power_loss_recovery", "wrapping_detection_layers", "wrapping_exclude_area", "machine_load_filament_time", "machine_unload_filament_time", "machine_tool_change_time", "time_cost", "machine_pause_gcode", "template_custom_gcode", - "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "travel_slope", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","printer_structure", + "nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "travel_slope", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","cooling_filter_enabled","printer_structure","farthest_point_timelapse", "best_object_pos", "head_wrap_detect_zone", "host_type", "print_host", "printhost_apikey", "flashforge_serial_number", "bbl_use_printhost", "printer_agent", "print_host_webui", @@ -1387,7 +1395,13 @@ static std::vector s_Preset_printer_options { "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "wipe_tower_type", "purge_in_prime_tower", "enable_filament_ramming", "tool_change_on_wipe_tower", "z_offset", "disable_m73", "preferred_orientation", "emit_machine_limits_to_gcode", "pellet_modded_printer", "support_multi_bed_types", "use_3mf", "default_bed_type", "bed_mesh_min","bed_mesh_max","bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut", - "bed_temperature_formula", "nozzle_flush_dataset" + "bed_temperature_formula", "nozzle_flush_dataset", + // Multi-nozzle count + pre-heat model printer options + "extruder_max_nozzle_count", "group_algo_with_time", "enable_pre_heating", "hotend_heating_rate", "hotend_cooling_rate", + "machine_hotend_change_time", "machine_prepare_compensation_time", + // Fast-purge printer flag + device/firmware-facing per-variant extruder-change + // deretraction speed (unconsumed by the slicer; carried by H2D/A2L/X2D/P2S machine profiles). + "support_fast_purge_mode", "deretract_speed_extruder_change" }; static std::vector s_Preset_sla_print_options { diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index bbbdc6c5ff..75150f85c9 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -72,6 +72,7 @@ #define BBL_JSON_KEY_BOTTOM_TEXTURE_END_NAME "bottom_texture_end_name" #define BBL_JSON_KEY_USE_DOUBLE_EXTRUDER_DEFAULT_TEXTURE "use_double_extruder_default_texture" #define BBL_JSON_KEY_BOTTOM_TEXTURE_RECT "bottom_texture_rect" +#define BBL_JSON_KEY_BOTTOM_TEXTURE_RECT_LONGER "bottom_texture_rect_longer" #define BBL_JSON_KEY_MIDDLE_TEXTURE_RECT "middle_texture_rect" #define BBL_JSON_KEY_HOTEND_MODEL "hotend_model" @@ -150,6 +151,7 @@ public: std::string bottom_texture_end_name; std::string use_double_extruder_default_texture; std::string bottom_texture_rect; + std::string bottom_texture_rect_longer; std::string middle_texture_rect; std::string hotend_model; PrinterVariant* variant(const std::string &name) { diff --git a/src/libslic3r/PresetBundle.cpp b/src/libslic3r/PresetBundle.cpp index fccbd13b98..610ca41619 100644 --- a/src/libslic3r/PresetBundle.cpp +++ b/src/libslic3r/PresetBundle.cpp @@ -52,6 +52,9 @@ static std::vector s_project_options { "wipe_tower_rotation_angle", "curr_bed_type", "flush_multiplier", + // Fast-purge mode: project-level purge control, inert at Default. + "flush_multiplier_fast", + "prime_volume_mode", "nozzle_volume_type", "filament_map_mode", "filament_map" @@ -348,7 +351,7 @@ PresetBundle::PresetBundle() auto& default_config = this->filaments.default_preset().config; for(const std::string& opt_key : default_config.keys()){ ConfigOption* opt = default_config.optptr(opt_key, false); - bool is_override_key = std::find(filament_extruder_override_keys.begin(),filament_extruder_override_keys.end(), opt_key) != filament_extruder_override_keys.end(); + bool is_override_key = is_filament_extruder_override_key(opt_key); if(!is_override_key || !opt->nullable()) continue; opt->deserialize("nil",ForwardCompatibilitySubstitutionRule::Disable); @@ -721,6 +724,8 @@ std::optional PresetBundle::get_filament_by_filament_id(const auto iter = std::find(compatible_printers.begin(), compatible_printers.end(), printer_name); if (iter != compatible_printers.end() && config.has("filament_printable")) { info.filament_printable = config.option("filament_printable")->values[0]; + if (config.has("filament_extruder_compatibility")) + info.set_filament_extruder_compatibility(config.option("filament_extruder_compatibility")->values[0]); return info; } } @@ -3872,10 +3877,46 @@ DynamicPrintConfig PresetBundle::full_config_secure(std::optional>> PresetBundle::get_full_flush_matrix(bool with_multiplier) const +{ + auto full_config = this->full_config(); + int extruder_nums = full_config.option("nozzle_diameter")->values.size(); + std::vector flush_volume_value = full_config.option("flush_volumes_matrix")->values; + int filament_nums = full_config.option("filament_type")->values.size(); + + std::vector>> matrix; + for (size_t extruder_id = 0; extruder_id < extruder_nums; ++extruder_id) { + std::vector flush_matrix(cast(get_flush_volumes_matrix(flush_volume_value, extruder_id, extruder_nums))); + std::vector> wipe_volumes; + for (unsigned int i = 0; i < filament_nums; ++i) + wipe_volumes.push_back(std::vector(flush_matrix.begin() + i * filament_nums, flush_matrix.begin() + (i + 1) * filament_nums)); + + matrix.emplace_back(wipe_volumes); + } + + if (with_multiplier) { + // Fast purge mode uses flush_multiplier_fast; the default prime_volume_mode==Default + // (or the key absent) reads flush_multiplier, so this is inert. + auto* mode_opt = project_config.option>("prime_volume_mode"); + const bool use_fast = mode_opt && mode_opt->value == PrimeVolumeMode::pvmFast; + auto* mult_opt = project_config.option(use_fast ? "flush_multiplier_fast" : "flush_multiplier"); + auto flush_multiplies = mult_opt ? mult_opt->values : project_config.option("flush_multiplier")->values; + flush_multiplies.resize(extruder_nums, 1); + for (size_t extruder_id = 0; extruder_id < extruder_nums; ++extruder_id) { + for (auto& vec : matrix[extruder_id]) { + for (auto& v : vec) + v *= flush_multiplies[extruder_id]; + } + } + } + + return matrix; +} + const std::set ignore_settings_list ={ "inherits", "print_settings_id", "filament_settings_id", "printer_settings_id" @@ -4770,6 +4811,8 @@ std::pair PresetBundle::load_vendor_configs_ model.use_double_extruder_default_texture = it.value(); } else if (boost::iequals(it.key(), BBL_JSON_KEY_BOTTOM_TEXTURE_RECT)) { model.bottom_texture_rect = it.value(); + } else if (boost::iequals(it.key(), BBL_JSON_KEY_BOTTOM_TEXTURE_RECT_LONGER)) { + model.bottom_texture_rect_longer = it.value(); } else if (boost::iequals(it.key(), BBL_JSON_KEY_MIDDLE_TEXTURE_RECT)) { model.middle_texture_rect = it.value(); } diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index fc03ff8d3b..4bdccd4663 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -72,6 +72,25 @@ struct FilamentBaseInfo bool is_support{ false }; bool is_system{ true }; int filament_printable = 3; + + // filament_extruder_compatibility packs one compatibility level per extruder into a single + // 32-bit int, 3 bits per extruder (up to 10 extruders). Levels: 0 = printable, 1 = error, + // 2 = critical warning, 3 = warning (4-7 reserved). extruder_id is 0-based. + int get_extruder_compatibility(int extruder_id) const { + constexpr int bits_per_extruder = 3; + constexpr int extruder_mask = (1 << bits_per_extruder) - 1; // 0x7 + constexpr int max_extruder_count = 32 / bits_per_extruder; // 10 + + if (extruder_id < 0 || extruder_id >= max_extruder_count) + return 0; + return (m_filament_extruder_compatibility >> (bits_per_extruder * extruder_id)) & extruder_mask; + } + + void set_filament_extruder_compatibility(int value) { m_filament_extruder_compatibility = value; } + int get_filament_extruder_compatibility() const { return m_filament_extruder_compatibility; } + +private: + int m_filament_extruder_compatibility = 0; }; enum BundleType{ @@ -368,6 +387,11 @@ public: // full_config() with the some "useless" config removed. DynamicPrintConfig full_config_secure(std::optional>filament_maps = std::nullopt) const; + // Per-extruder flush matrix [extruder_id][from_filament][to_filament] in mm^3, optionally scaled + // by the per-extruder flush_multiplier (or flush_multiplier_fast when prime_volume_mode==Fast). + // Used by the print-dispatch nozzle-mapping flush-weight estimate. + std::vector>> get_full_flush_matrix(bool with_multiplier = true) const; + //BBS: add some functions for multiple extruders int get_printer_extruder_count() const; bool support_different_extruders() const; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index a676d24cc0..19be87bc32 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -2506,9 +2506,14 @@ void Print::process(long long *time_cost_with_cache, bool use_cache) auto map_mode = get_filament_map_mode(); // get recommended filament map if (map_mode < FilamentMapMode::fmmManual) { - filament_maps = ToolOrdering::get_recommended_filament_maps(all_filaments, this, map_mode, physical_unprintables, geometric_unprintables); - std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value + 1; }); - update_filament_maps_to_config(filament_maps); + // Grouping returns a nozzle-aware result; the 1-based extruder map + // for the by-object path is derived from it. + auto grouping_result = ToolOrdering::get_recommended_filament_maps(all_filaments, this, map_mode, physical_unprintables, geometric_unprintables); + auto derived_maps = grouping_result.get_extruder_map(false); + if (!derived_maps.empty()) { + filament_maps = derived_maps; + update_filament_maps_to_config(filament_maps); + } } // check map valid both in auto and mannual mode std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) {return value - 1; }); @@ -2658,8 +2663,14 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor gcode.do_export(this, path.c_str(), result, thumbnail_cb); gcode.export_layer_filaments(result); //BBS - if (result != nullptr) + if (result != nullptr) { result->conflict_result = m_conflict_result; + // Surface the slicer's per-filament nozzle grouping onto the post-slice result + // the device GUI reads. This is the static L/R + rack subset the multi-nozzle path computes; + // null for single-nozzle prints where nothing computes it. It is assigned after g-code + // generation and read by no emitter, so it does not affect the emitted g-code. + result->nozzle_group_result = this->get_layered_nozzle_group_result(); + } return path.c_str(); } @@ -3306,6 +3317,47 @@ size_t Print::get_extruder_id(unsigned int filament_id) const return 0; } +// Region reachable by every extruder = intersection of all per-extruder printable areas. +// For single-nozzle printers, or whenever extruder_printable_area is unpopulated / degenerate (all +// current single/dual profiles), fall back to the full printable_area so the wipe-tower-center clamp +// is identical to the previous full-bed clamp. +Polygons Print::get_extruder_shared_printable_polygon() const +{ + const std::vector& extruder_printable_areas = m_config.extruder_printable_area.values; + if (m_config.nozzle_diameter.size() < 2 || extruder_printable_areas.empty()) + return {Polygon::new_scale(m_config.printable_area.values)}; + for (const Vec2ds& area : extruder_printable_areas) + if (area.size() < 3) + return {Polygon::new_scale(m_config.printable_area.values)}; + + Polygons shared_printable_polys = {Polygon::new_scale(extruder_printable_areas.front())}; + for (size_t i = 1; i < extruder_printable_areas.size(); ++i) + shared_printable_polys = intersection(shared_printable_polys, Polygons{Polygon::new_scale(extruder_printable_areas[i])}); + return shared_printable_polys; +} + +// Narrow the stored grouping result to the layer-aware type the slicing pipeline uses. +std::shared_ptr Print::get_layered_nozzle_group_result() const +{ + return std::dynamic_pointer_cast(m_nozzle_group_result); +} + +// Dynamic (per-layer selector) regroup predicate. +// Orca: enable_filament_dynamic_map is a develop-only config key registered in the ConfigDef but NOT +// a static PrintConfig member, so it is read from the applied full config; it is absent for every +// shipping printer/profile -> nullptr -> false, which keeps the static grouping path (identical +// output) the only one the current fleet takes. There is no mixed-colour-filament guard (mixed-colour +// filaments are not supported). The remaining gates (auto-for-flush mode, multi-extruder machine) +// read the static PrintConfig members. +bool Print::is_dynamic_group_reorder() const +{ + const auto *opt = m_full_print_config.option("enable_filament_dynamic_map"); + const bool enabled = opt && opt->value; + if (!enabled || m_config.filament_map_mode != FilamentMapMode::fmmAutoForFlush || m_config.nozzle_diameter.size() <= 1) + return false; + return true; +} + // Wipe tower support. bool Print::has_wipe_tower() const { @@ -3466,6 +3518,14 @@ void Print::_make_wipe_tower() m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z, m_wipe_tower_data.tool_ordering.all_extruders()); wipe_tower.set_has_tpu_filament(this->has_tpu_filament()); wipe_tower.set_filament_map(this->get_filament_maps()); + // Feed the has_filament_switcher device flag (develop-only dynamic key, read defensively from + // the full config — no shipping profile sets it) and the shared printable bed used by the PETG + // pre-extrusion offset clamp. Both are inert unless has_filament_switcher is set. + { + const ConfigOptionBool* hfs = m_full_print_config.option("has_filament_switcher"); + wipe_tower.set_has_filament_switcher(hfs && hfs->value); + } + wipe_tower.set_shared_print_bed(this->get_extruder_shared_printable_polygon()); // Set the extruder & material properties at the wipe tower object. for (size_t i = 0; i < number_of_extruders; ++i) wipe_tower.set_extruder(i, m_config); @@ -3517,7 +3577,10 @@ void Print::_make_wipe_tower() float volume_to_purge = 0; if (pre_filament_id != (unsigned int)(-1) && pre_filament_id != filament_id) { volume_to_purge = multi_extruder_flush[nozzle_id][pre_filament_id][filament_id]; - volume_to_purge *= m_config.flush_multiplier.get_at(nozzle_id); + // Fast purge mode uses flush_multiplier_fast; Default is inert. + float flush_multiplier = (m_config.prime_volume_mode == PrimeVolumeMode::pvmFast) ? m_config.flush_multiplier_fast.get_at(nozzle_id) + : m_config.flush_multiplier.get_at(nozzle_id); + volume_to_purge *= flush_multiplier; volume_to_purge = pre_filament_id == -1 ? 0 : layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_filament_id, filament_id, volume_to_purge); } @@ -3526,8 +3589,10 @@ void Print::_make_wipe_tower() float grab_purge_volume = m_config.grab_length.get_at(nozzle_id) * 2.4; //(diameter/2)^2*PI=2.4 volume_to_purge = std::max(0.f, volume_to_purge - grab_purge_volume); + // Saving mode reduces the prime volume to 15 mm3; Default is inert. + float prime_volume = (m_config.prime_volume_mode == PrimeVolumeMode::pvmSaving) ? 15.f : (float) m_config.prime_volume; wipe_tower.plan_toolchange((float)layer_tools.print_z, (float)layer_tools.wipe_tower_layer_height, current_filament_id, filament_id, - m_config.prime_volume, volume_to_purge); + prime_volume, volume_to_purge); current_filament_id = filament_id; nozzle_cur_filament_ids[nozzle_id] = filament_id; } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index b9f70506fb..bf9b5bfd48 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -38,6 +38,7 @@ class SupportLayer; class TreeSupportData; class TreeSupport; class ExtrusionLayers; +namespace MultiNozzleUtils { class NozzleGroupResultBase; class LayeredNozzleGroupResult; } #define MAX_OUTER_NOZZLE_DIAMETER 4 // BBS: move from PrintObjectSlice.cpp @@ -1012,6 +1013,25 @@ public: // get the group label of filament size_t get_extruder_id(unsigned int filament_id) const; + // The region every extruder can reach, + // i.e. the intersection of all per-extruder printable areas. Falls back to the full printable_area + // for single-nozzle printers and whenever extruder_printable_area is not populated (all current + // single/dual profiles), so the wipe-tower-center clamp is byte-identical to full-bed clamping there. + Polygons get_extruder_shared_printable_polygon() const; + + // Logical (extruder, nozzle) grouping result produced by ToolOrdering during reorder. + // Consumed by GCode via get_layered_nozzle_group_result()->get_nozzle_id(filament, layer) etc. + void set_nozzle_group_result(std::shared_ptr result) { m_nozzle_group_result = result; } + std::shared_ptr get_nozzle_group_result() const { return m_nozzle_group_result; } + std::shared_ptr get_layered_nozzle_group_result() const; + + // True only when the printer opts into the per-layer filament selector + // (enable_filament_dynamic_map) in auto-for-flush mode on a multi-extruder machine. Gates the + // dynamic (per-layer) regroup branch in ToolOrdering::reorder_extruders_for_minimum_flush_volume. + // Closed for every current profile, so the static grouping path (byte-identical output) is the + // only one taken by the shipping fleet. + bool is_dynamic_group_reorder() const; + const std::vector>& get_extruder_filament_info() const { return m_extruder_filament_info; } void set_extruder_filament_info(const std::vector>& filament_info) { m_extruder_filament_info = filament_info; } @@ -1176,6 +1196,9 @@ private: std::vector> m_extruder_filament_info; + // Logical (extruder, nozzle) grouping result, set by ToolOrdering during reorder. + std::shared_ptr m_nozzle_group_result; + // Following section will be consumed by the GCodeGenerator. ToolOrdering m_tool_ordering; WipeTowerData m_wipe_tower_data {m_tool_ordering}; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index dda24e4e5b..d324553868 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -83,6 +83,15 @@ const std::vector filament_extruder_override_keys = { "filament_retraction_distances_when_cut" }; +// Some filament override parameters are generated from filament_extruder_override_keys, +// while filament_retract_length_nc is defined separately. Keep the generator list +// unchanged and use this helper for behavior checks that need the full override set. +bool is_filament_extruder_override_key(const std::string &opt_key) +{ + return std::find(filament_extruder_override_keys.begin(), filament_extruder_override_keys.end(), opt_key) != filament_extruder_override_keys.end() || + opt_key == "filament_retract_length_nc"; +} + size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id) { if (filament_id < config.filament_map.size()) { @@ -569,17 +578,28 @@ CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(ExtruderType) static const t_config_enum_values s_keys_map_NozzleVolumeType = { { "Standard", nvtStandard }, - { "High Flow", nvtHighFlow } + { "High Flow", nvtHighFlow }, + { "TPU High Flow", nvtTPUHighFlow }, + { "Hybrid", nvtHybrid } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NozzleVolumeType) static const t_config_enum_values s_keys_map_FilamentMapMode = { { "Auto For Flush", fmmAutoForFlush }, { "Auto For Match", fmmAutoForMatch }, - { "Manual", fmmManual } + { "Manual", fmmManual }, + { "Nozzle Manual", fmmNozzleManual } }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FilamentMapMode) +// PrimeVolumeMode. Serialized string keys must stay stable; they round-trip through .3mf. +static const t_config_enum_values s_keys_map_PrimeVolumeMode = { + { "Default", pvmDefault }, + { "Saving", pvmSaving }, + { "Fast", pvmFast } +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrimeVolumeMode) + //BBS std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type) @@ -650,6 +670,60 @@ std::vector save_extruder_ams_count_to_string(const std::vector#". Empty string => no per-type stats for that extruder. +std::vector> get_extruder_nozzle_stats(const std::vector &strs) +{ + std::vector> extruder_nozzle_counts; + for (const std::string &str : strs) { + std::map nozzle_count_map; + if (str.empty()) { + extruder_nozzle_counts.emplace_back(nozzle_count_map); + continue; + } + std::vector nozzle_infos; + boost::algorithm::split(nozzle_infos, str, boost::algorithm::is_any_of("|")); + for (auto &nozzle_info : nozzle_infos) { + std::vector attr; + boost::algorithm::split(attr, nozzle_info, boost::algorithm::is_any_of("#")); + // Guard against malformed device/project data: skip tokens without a "#" + // shape or with an unknown volume-type key instead of throwing (.at) or reading attr[1] + // out of bounds. Corrupt tokens are dropped and logged; the rest still parse. + if (attr.size() < 2) { + BOOST_LOG_TRIVIAL(warning) << "get_extruder_nozzle_stats: skipping malformed token '" << nozzle_info << "'"; + continue; + } + auto it = s_keys_map_NozzleVolumeType.find(attr[0]); + if (it == s_keys_map_NozzleVolumeType.end()) { + BOOST_LOG_TRIVIAL(warning) << "get_extruder_nozzle_stats: skipping unknown nozzle volume type '" << attr[0] << "'"; + continue; + } + NozzleVolumeType volume_type = NozzleVolumeType(it->second); + int nozzle_count = std::atoi(attr[1].c_str()); + nozzle_count_map[volume_type] = nozzle_count; + } + extruder_nozzle_counts.emplace_back(nozzle_count_map); + } + return extruder_nozzle_counts; +} + +std::vector save_extruder_nozzle_stats_to_string(const std::vector> &extruder_nozzle_stats) +{ + std::vector extruder_nozzle_count_str; + for (size_t idx = 0; idx < extruder_nozzle_stats.size(); ++idx) { + std::ostringstream oss; + const auto &item = extruder_nozzle_stats[idx]; + for (auto it = item.begin(); it != item.end(); ++it) { + oss << get_nozzle_volume_type_string(it->first) << "#" << it->second; + if (std::next(it) != item.end()) + oss << "|"; + } + extruder_nozzle_count_str.emplace_back(oss.str()); + } + return extruder_nozzle_count_str; +} + static void assign_printer_technology_to_unknown(t_optiondef_map &options, PrinterTechnology printer_technology) { for (std::pair &kvp : options) @@ -2548,6 +2622,25 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionInts{1}); + // Multi-nozzle: per-filament map to the config slot identified by (extruder, nozzle_volume_type). + // Forward-compat-only registration with no consumer yet. + // Orca: resolves per-variant slots via get_index_for_extruder at PrintApply time rather than a + // read-time filament-config-index lookup, so nothing in src/ reads this key. Kept registered so an + // H2C project/config that carries it loads without an unknown-option substitution warning. + // Internal use only, no translation. + def = this->add("filament_map_2", coInts); + def->label = "Filament map plus for multi nozzle"; + def->tooltip = "Filament map to the index identified by extruder and nozzle_volume_type"; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{1}); + + // Per-filament nozzle-volume-type override (multi-volume/Hybrid). Registered so the value + // round-trips through .3mf plate metadata (filament_volume_maps); load/save-only for now and + // inert for existing printers (unread by slicing until the multi-volume pipeline lands). + def = this->add("filament_volume_map", coInts); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{(int)(NozzleVolumeType::nvtStandard)}); + def = this->add("physical_extruder_map",coInts); // internal use only, don't need translation def->label = "Map the logical extruder to physical extruder"; @@ -2563,14 +2656,22 @@ void PrintConfigDef::init_fff_params() def->enum_values.push_back("Auto For Flush"); def->enum_values.push_back("Auto For Match"); def->enum_values.push_back("Manual"); + def->enum_values.push_back("Nozzle Manual"); def->enum_values.push_back("Default"); def->enum_labels.push_back(L("Auto For Flush")); def->enum_labels.push_back(L("Auto For Match")); def->enum_labels.push_back(L("Manual")); + def->enum_labels.push_back(L("Nozzle Manual")); def->enum_labels.push_back(L("Default")); def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(fmmAutoForFlush)); + // Fully-manual mode (fmmNozzleManual): per-filament -> physical-nozzle assignment. + // Inert until the nozzle-assignment engine consumes it. Internal use only, no translation. + def = this->add("filament_nozzle_map", coInts); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{1}); + def = this->add("filament_flush_temp", coInts); def->label = L("Flush temperature"); def->tooltip = L("Temperature when flushing filament. 0 indicates the upper bound of the recommended nozzle temperature range."); @@ -2581,6 +2682,19 @@ void PrintConfigDef::init_fff_params() def->sidetext = L(u8"\u2103" /* °C */); // degrees Celsius, CIS languages need translation def->set_default_value(new ConfigOptionIntsNullable{0}); + // Fast-purge flush temperature: used only when prime_volume_mode==Fast. + // Default 0 (fall back to the recommended-range upper bound, identical to filament_flush_temp), + // so the key is inert for the shipping fleet. Kept out of the g-code config block (banned_keys). + def = this->add("filament_flush_temp_fast", coInts); + def->label = L("Flush temperature"); + def->tooltip = L("Flush temperature used in fast purge mode."); + def->mode = comAdvanced; + def->nullable = true; + def->min = 0; + def->max = max_temp; + def->sidetext = L(u8"℃" /* °C */); // degrees Celsius, CIS languages need translation + def->set_default_value(new ConfigOptionIntsNullable{0}); + def = this->add("filament_flush_volumetric_speed", coFloats); def->label = L("Flush volumetric speed"); def->tooltip = L("Volumetric speed when flushing filament. 0 indicates the max volumetric speed."); @@ -2954,6 +3068,18 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionInts{3}); + // A single 32-bit int encodes the compatibility level of a filament across all extruders (up to 10). + // Every 3 bits represent one extruder: bits [3*i, 3*i+2] -> extruder i. + // Compatibility levels: 0 = printable, 1 = error, 2 = critical warning, 3 = warning (4-7 reserved). + // Default 0 (printable) keeps the key inert for filaments/printers that do not declare it. + def = this->add("filament_extruder_compatibility", coInts); + def->label = L("Filament-extruder compatibility"); + def->tooltip = L("A single 32-bit int encoding the compatibility level of a filament across all extruders (up to 10). " + "Every 3 bits represent one extruder (bits [3*i, 3*i+2] for extruder i). " + "0: printable, 1: error, 2: critical warning, 3: warning, 4-7: reserved."); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{0}); + // BBS def = this->add("temperature_vitrification", coInts); def->label = L("Softening temperature"); @@ -3857,6 +3983,12 @@ void PrintConfigDef::init_fff_params() def->mode=comDevelop; def->set_default_value(new ConfigOptionBool(true)); + def = this->add("cooling_filter_enabled", coBool); + def->label = L("Use cooling filter"); + def->tooltip = L("Enable this if printer support cooling filter"); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("gcode_flavor", coEnum); def->label = L("G-code flavor"); def->tooltip = L("What kind of G-code the printer is compatible with."); @@ -4659,6 +4791,39 @@ void PrintConfigDef::init_fff_params() def->mode = comDevelop; def->set_default_value(new ConfigOptionFloats{ 0., 0. }); + // Bedslinger mass/force limits. + // Consumed by GCode::mass_load_limited_machine_acceleration (curr_y_acceleration_limit) + // and the printed-mass check. Default 0 keeps them inactive for existing printers. + def = this->add("machine_max_force_Y", coFloat); + def->full_label = L("Maximum force of the Y axis"); + def->category = L("Machine limits"); + def->readonly = false; + def->tooltip = L("The allowed maximum output force of Y axis"); + def->sidetext = L("N"); + def->min = 0; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("machine_bed_mass_Y", coFloat); + def->full_label = L("Bed mass of the Y axis"); + def->category = L("Machine limits"); + def->readonly = false; + def->tooltip = L("The machine bed mass load of Y axis"); + def->sidetext = L("g"); + def->min = 0; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionFloat(0)); + + def = this->add("machine_max_printed_mass", coFloat); + def->full_label = L("The allowed max printed mass"); + def->category = L("Machine limits"); + def->readonly = false; + def->tooltip = L("The allowed max printed mass on a plate"); + def->sidetext = L("g"); + def->min = 0; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionFloat(0)); + // M204 P... [mm/sec^2] def = this->add("machine_max_acceleration_extruding", coFloats); def->full_label = L("Maximum acceleration for extruding"); @@ -5404,10 +5569,15 @@ void PrintConfigDef::init_fff_params() def->label = "Nozzle Volume Type"; def->tooltip = "Nozzle volume type for extruders."; def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + // Order must match the NozzleVolumeType enum values (Standard=0, High Flow=1, Hybrid=2, TPU High Flow=3). def->enum_values.push_back(L("Standard")); def->enum_values.push_back(L("High Flow")); + def->enum_values.push_back(L("Hybrid")); + def->enum_values.push_back(L("TPU High Flow")); def->enum_labels.push_back(L("Standard")); def->enum_labels.push_back(L("High Flow")); + def->enum_labels.push_back(L("Hybrid")); + def->enum_labels.push_back(L("TPU High Flow")); def->mode = comSimple; def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard }); @@ -5418,8 +5588,12 @@ void PrintConfigDef::init_fff_params() def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back(L("Standard")); def->enum_values.push_back(L("High Flow")); + def->enum_values.push_back(L("Hybrid")); + def->enum_values.push_back(L("TPU High Flow")); def->enum_labels.push_back(L("Standard")); def->enum_labels.push_back(L("High Flow")); + def->enum_labels.push_back(L("Hybrid")); + def->enum_labels.push_back(L("TPU High Flow")); def->mode = comDevelop; def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard }); @@ -5436,6 +5610,43 @@ void PrintConfigDef::init_fff_params() def->tooltip = "AMS counts per extruder."; def->set_default_value(new ConfigOptionStrings { }); + // Multi-nozzle: per-extruder physical nozzle inventory by volume type, + // "#" tokens joined by "|". Internal use only, no translation. + def = this->add("extruder_nozzle_stats", coStrings); + def->label = "Extruder nozzle stats"; + def->tooltip = "Physical nozzle counts per extruder, keyed by nozzle volume type."; + def->set_default_value(new ConfigOptionStrings { }); + + // Multi-nozzle: number of physical nozzles per extruder. Forward-compat-only registration + // with no slicing consumer: the nozzle-assignment engine derives its per-extruder physical nozzle + // inventory from the richer `extruder_nozzle_stats` key, not from this scalar count, so nothing in + // src/ reads it. Kept registered so an H2C project/config that carries the key loads without an + // unknown-option substitution warning. Default {1} == today's single-nozzle-per-extruder assumption, + // so absent/default is a no-op for every shipping printer. Internal use only, no translation. + def = this->add("extruder_nozzle_count", coInts); + def->label = "extruder nozzle count"; + def->tooltip = "extruder nozzle count"; + def->mode = comDevelop; + def->set_default_value(new ConfigOptionInts{1}); + + // Per-nozzle volume type. Forward-compat-only registration with no slicing consumer — nothing in + // src/ reads it; the engine resolves per-nozzle volume types from `extruder_nozzle_stats` tokens + // instead. Kept registered so a project/config carrying it loads without an unknown-option + // substitution warning. Registers Standard/High Flow/TPU High Flow only (no Hybrid). + // Internal use only, no translation. + def = this->add("extruder_nozzle_volume_type", coEnums); + def->label = "Extruder nozzle volume type"; + def->tooltip = "Nozzle volume type per physical nozzle of an extruder."; + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("Standard"); + def->enum_values.push_back("High Flow"); + def->enum_values.push_back("TPU High Flow"); + def->enum_labels.push_back("Standard"); + def->enum_labels.push_back("High Flow"); + def->enum_labels.push_back("TPU High Flow"); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionEnumsGeneric{ NozzleVolumeType::nvtStandard }); + def = this->add("enable_filament_dynamic_map", coBool); def->label = L("Enable filament dynamic map"); def->tooltip = L("Enable dynamic filament mapping during print."); @@ -5534,6 +5745,19 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionFloats { 0. }); + // Per-(extruder,variant) deretraction speed at an extruder change. This value + // ships in multi-extruder machine profiles but has no slicer consumer — it is a device/firmware-facing + // profile key. Registered here (ConfigDef-only, no FullPrintConfig static member) so X2D/P2S profiles + // that already carry it — and the H2D/A2L leaves — validate as a known key; unread by the slicer. + // nullable so absent leaves stay nil (excluded from the g-code config block). + def = this->add("deretract_speed_extruder_change", coFloats); + def->label = L("Deretraction speed (extruder change)"); + def->tooltip = L("Speed for reloading filament into the nozzle when switching extruder."); + def->sidetext = L("mm/s"); // millimeters per second, CIS languages need translation + def->mode = comDevelop; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable { 0. }); + def = this->add("use_firmware_retraction", coBool); def->label = L("Use firmware retraction"); def->tooltip = L("This experimental setting uses G10 and G11 commands to have the firmware " @@ -5952,6 +6176,20 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(tlTraditional)); + // Farthest-point timelapse. Corexy-only refinement layered on top of the existing + // timelapse_type: when enabled the traditional-mode snapshot is + // taken at the extrusion point farthest from the camera (0,0) instead of traveling to a safe/chute + // position. Gated in GCode::process_layer by timelapse_type==tlTraditional && printer_structure!=psI3, + // so it is inert for i3 (A1/A2L) printers and whenever the toggle is off (default false → every + // existing printer's g-code is byte-identical). Only H2C/H2D machine profiles set it =1. + def = this->add("farthest_point_timelapse", coBool); + def->label = L("Farthest point timelapse"); + def->tooltip = L("When enabled, the timelapse snapshot is taken at the farthest point from camera " + "instead of traveling to the wipe tower or excess chute. " + "Only effective in traditional timelapse mode on non-I3 printers."); + def->mode = comSimple; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("standby_temperature_delta", coInt); def->label = L("Temperature variation"); // TRN PrintSettings : "Ooze prevention" > "Temperature variation" @@ -6875,6 +7113,14 @@ void PrintConfigDef::init_fff_params() //def->sidetext = ""; def->set_default_value(new ConfigOptionFloats{0.3}); + // Fast-purge mode: the flush multiplier used when prime_volume_mode==Fast. + // Only consumed on the pvmFast branch (default prime_volume_mode==Default reads flush_multiplier), + // so this key is inert for the shipping fleet. Kept out of the g-code config block (banned_keys). + def = this->add("flush_multiplier_fast", coFloats); + def->label = L("Flush multiplier (Fast mode)"); + def->tooltip = L("The flush multiplier used in fast purge mode."); + def->set_default_value(new ConfigOptionFloats{1.2}); + // BBS def = this->add("prime_volume", coFloat); def->label = L("Prime volume"); @@ -6884,6 +7130,22 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionFloat(45.)); + // Dual-extruder purge control: Default reproduces current behaviour + // (per-extruder flush_multiplier + filament_prime_volume); Saving reduces the prime volume, + // Fast selects flush_multiplier_fast + filament_flush_temp_fast. Default pvmDefault = inert. + def = this->add("prime_volume_mode", coEnum); + def->label = L("Prime volume mode"); + def->tooltip = L("Selects how the wipe-tower prime and flush volumes are computed on multi-extruder printers."); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("Default"); + def->enum_values.push_back("Saving"); + def->enum_values.push_back("Fast"); + def->enum_labels.push_back(L("Default")); + def->enum_labels.push_back(L("Saving")); + def->enum_labels.push_back(L("Fast")); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionEnum(pvmDefault)); + def = this->add("wipe_tower_x", coFloats); //def->label = L("Position X"); //def->tooltip = L("X coordinate of the left front corner of a wipe tower."); @@ -7340,6 +7602,162 @@ void PrintConfigDef::init_fff_params() } } + // ---- Multi-nozzle + pre-heat + nozzle-change (nc) config keys ---- + // These back 6-nozzle cluster grouping, the pre-heat/pre-cool time model and wipe-tower + // nozzle-change handling. Defaults are no-ops for existing single-nozzle printers (all new + // readers gate on extruder_max_nozzle_count > 1). + def = this->add("machine_hotend_change_time", coFloat); + def->label = L("Hotend change time"); + def->tooltip = L("Time to change hotend."); + def->sidetext = L("s"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.0)); + + // Printer-owned toggle selecting the time-aware grouping objective (flush + change/print + // time) over the flush-only objective. Default false == today's flush-only grouping, so + // absent/default is inert. Consumed by the grouping solver (SpeedInfo). + // Orca: pinned to comDevelop (rather than the default comSimple) to match the sibling multi-nozzle + // dev keys and keep it out of user selectors. + def = this->add("group_algo_with_time", coBool); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("machine_prepare_compensation_time", coFloat); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionFloat(260)); + + def = this->add("enable_pre_heating", coBool); + def->set_default_value(new ConfigOptionBool(false)); + + // Pre-heat injector context key. handle_hotend_as_extruder is read defensively by the injector; + // registered here (comDevelop, default off) as a known inert key. + def = this->add("handle_hotend_as_extruder", coBool); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + + // filament_max_temperature_drop_when_ec: inert (default {0}, passed into the injector context but + // never consumed). Registered inert-only (comDevelop); not wired into any estimator read, and not + // added to any per-variant expansion list. + def = this->add("filament_max_temperature_drop_when_ec", coFloats); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionFloats{0}); + + def = this->add("hotend_cooling_rate", coFloats); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{2}); + + def = this->add("hotend_heating_rate", coFloats); + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{2}); + + def = this->add("filament_change_length_nc", coFloats); + def->label = L("Hotend change"); + def->tooltip = L("When changing the hotend, it is recommended to extrude a certain length of filament from the original nozzle. This helps minimize nozzle oozing."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloats{10}); + + def = this->add("filament_ramming_travel_time", coFloats); + def->label = L("Extruder change"); + def->tooltip = L("To prevent oozing, the nozzle will perform a reverse travel movement for a certain period after " + "the ramming is complete. The setting define the travel time."); + def->mode = comAdvanced; + def->sidetext = "s"; + def->min = 0; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0}); + + def = this->add("filament_pre_cooling_temperature", coInts); + def->label = L("Extruder change"); + def->tooltip = L("To prevent oozing, the nozzle temperature will be cooled during ramming. Therefore, the ramming time must be greater than the cooldown time. 0 means disabled."); + def->mode = comAdvanced; + def->sidetext = "°C"; + def->min = 0; + def->nullable = true; + def->set_default_value(new ConfigOptionIntsNullable{0}); + + def = this->add("filament_ramming_volumetric_speed", coFloats); + def->label = L("Extruder change"); + def->tooltip = L("The maximum volumetric speed for ramming before extruder change, where -1 means using the maximum volumetric speed."); + def->sidetext = L("mm³/s"); + def->min = -1; + def->max = 200; + def->mode = comAdvanced; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{-1}); + + def = this->add("filament_ramming_travel_time_nc", coFloats); + def->label = L("Hotend change"); + def->tooltip = L("To prevent oozing, the nozzle will perform a reverse travel movement for a certain period after " + "the ramming is complete. The setting define the travel time."); + def->mode = comAdvanced; + def->sidetext = "s"; + def->min = 0; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0}); + + def = this->add("filament_pre_cooling_temperature_nc", coInts); + def->label = L("Hotend change"); + def->tooltip = L( + "To prevent oozing, the nozzle temperature will be cooled during ramming. Note: only a cooldown command and fan activation are triggered, reaching the target temperature is not guaranteed. 0 means disabled."); + def->mode = comAdvanced; + def->sidetext = "°C"; + def->min = 0; + def->nullable = true; + def->set_default_value(new ConfigOptionIntsNullable{0}); + + def = this->add("filament_ramming_volumetric_speed_nc", coFloats); + def->label = L("Hotend change"); + def->tooltip = L("The maximum volumetric speed for ramming before a hotend change, where -1 means using the maximum volumetric speed."); + def->sidetext = L("mm³/s"); + def->min = -1; + def->max = 200; + def->mode = comAdvanced; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{-1}); + + def = this->add("filament_retract_length_nc", coFloats); + def->label = L("length when change hotend"); + def->tooltip = L("When this retraction value is modified, it will be used as the amount of filament retracted " + "inside the hotend before changing hotends."); + def->sidetext = L("mm"); + def->mode = comDevelop; + def->nullable = true; + def->min = 0; + def->max = 18; + def->set_default_value(new ConfigOptionFloatsNullable { 10. }); + + def = this->add("extruder_max_nozzle_count", coInts); + def->mode = comDevelop; + def->nullable = true; + def->set_default_value(new ConfigOptionIntsNullable{ 1 }); + + // Printer flag gating the fast-purge mode selector in the Multi-Filament + // UI. comDevelop, default false; no shipping profile sets it, so the UI stays hidden. + def = this->add("support_fast_purge_mode", coBool); + def->label = L("Support fast purge mode"); + def->tooltip = L("Whether this printer supports fast purge mode with optimized temperature and multiplier."); + def->mode = comDevelop; + def->set_default_value(new ConfigOptionBool(false)); + + def = this->add("filament_prime_volume_nc", coFloats); + def->label = L("Hotend change"); + def->tooltip = L("The volume of material required to prime the extruder for a hotend change on the tower."); + def->sidetext = L("mm³"); + def->min = 1.0; + def->mode = comSimple; + def->set_default_value(new ConfigOptionFloats{60.}); + + def = this->add("filament_preheat_temperature_delta", coFloats); + def->label = L("Preheat temperature delta"); + def->tooltip = L("Temperature delta applied during pre-heating before tool change."); + def->sidetext = "°C"; + def->mode = comDevelop; + def->nullable = true; + def->set_default_value(new ConfigOptionFloatsNullable{0}); + def = this->add("detect_narrow_internal_solid_infill", coBool); def->label = L("Detect narrow internal solid infills"); def->category = L("Strength"); @@ -7389,13 +7807,14 @@ void PrintConfigDef::init_filament_option_keys() m_filament_option_keys = { "filament_diameter", "min_layer_height", "max_layer_height","volumetric_speed_coefficients", "retraction_length", "z_hop", "z_hop_types", "retract_lift_above", "retract_lift_below", "retract_lift_enforce", "retraction_speed", "deretraction_speed", - "retract_before_wipe", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance", + "retract_before_wipe", "filament_retract_length_nc", "retract_restart_extra", "retraction_minimum_travel", "wipe", "wipe_distance", "retract_when_changing_layer", "retract_length_toolchange", "retract_restart_extra_toolchange", "filament_colour", "default_filament_profile","retraction_distances_when_cut","long_retractions_when_cut"/*,"filament_seam_gap"*/ }; m_filament_retract_keys = { "deretraction_speed", + "filament_retract_length_nc", "long_retractions_when_cut", "retract_before_wipe", "retract_lift_above", @@ -8414,6 +8833,15 @@ std::set print_options_with_variant = { std::set filament_options_with_variant = { "filament_flow_ratio", "filament_max_volumetric_speed", + // Per-variant ramming / pre-cooling / nozzle-change filament overrides + "filament_ramming_volumetric_speed", + "filament_pre_cooling_temperature", + "filament_ramming_travel_time", + "filament_ramming_volumetric_speed_nc", + "filament_pre_cooling_temperature_nc", + "filament_ramming_travel_time_nc", + "filament_retract_length_nc", + "filament_preheat_temperature_delta", //"filament_extruder_id", "filament_extruder_variant", "filament_retraction_length", @@ -8461,7 +8889,8 @@ std::set printer_extruder_options = { "extruder_printable_area", "extruder_printable_height", "min_layer_height", - "max_layer_height" + "max_layer_height", + "extruder_max_nozzle_count" // Per-extruder max (sub-)nozzle count }; std::set printer_options_with_variant_1 = { @@ -8489,6 +8918,9 @@ std::set printer_options_with_variant_1 = { "nozzle_type", "printer_extruder_id", "printer_extruder_variant", + // Per-variant hotend heat-up / cool-down rates (pre-heat time model) + "hotend_cooling_rate", + "hotend_heating_rate", "nozzle_flush_dataset" }; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3b8b809c78..5a2f94bec8 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -46,6 +46,14 @@ enum GCodeFlavor : unsigned char { gcfNoExtrusion }; +// How a filament is used across the model. Part of the multi-nozzle grouping data; not yet +// read by the shipping slicer — the nozzle-centric FilamentGroup engine consumes it. +enum FilamentUsageType { + SupportOnly, + ModelOnly, + Hybrid +}; + enum class FuzzySkinType { None, @@ -418,24 +426,37 @@ enum ExtruderType { enum NozzleVolumeType { nvtStandard = 0, nvtHighFlow, - nvtMaxNozzleVolumeType = nvtHighFlow + nvtHybrid, // match-any / mixed sentinel; hidden from user selectors, kept out of the shipping slicer + nvtTPUHighFlow, // physical variant, used on H2D/H2DP 0.4 nozzles only + // Integer values are serialized as raw ints in 3mf plate metadata and device MQTT, so they MUST stay stable. + nvtMaxNozzleVolumeType = nvtTPUHighFlow }; enum FilamentMapMode { fmmAutoForFlush, fmmAutoForMatch, fmmManual, + fmmNozzleManual, // Fully-manual filament->physical-nozzle mapping (filament_nozzle_map). Kept ordered right after fmmManual so every `< fmmManual` "is-auto" check stays correct. fmmDefault }; +// Dual-extruder purge control. Default reproduces the current +// per-extruder flush_multiplier + filament_prime_volume behaviour, so absent/default is inert. +// Saving -> reduce prime volume to 15 mm3; Fast -> use flush_multiplier_fast + filament_flush_temp_fast. +enum PrimeVolumeMode { + pvmDefault = 0, + pvmSaving, + pvmFast +}; + extern std::string get_extruder_variant_string(ExtruderType extruder_type, NozzleVolumeType nozzle_volume_type); static std::set get_valid_nozzle_volume_type() { std::set type; for (int i = 0; i <= nvtMaxNozzleVolumeType; ++i) { auto t = static_cast(i); - // TODO: Orca: Support hybrid - //if (t == nvtHybrid) continue; + // Hybrid is a "match-any / mixed" sentinel, never a user-selectable physical type. + if (t == nvtHybrid) continue; type.insert(t); } return type; @@ -521,11 +542,17 @@ static std::string get_bed_temp_1st_layer_key(const BedType type) } extern const std::vector filament_extruder_override_keys; +// Full override-key check incl. filament_retract_length_nc (defined outside the generator list). +extern bool is_filament_extruder_override_key(const std::string &opt_key); // for parse extruder_ams_count extern std::vector> get_extruder_ams_count(const std::vector &strs); extern std::vector save_extruder_ams_count_to_string(const std::vector> &extruder_ams_count); +// for parse extruder_nozzle_stats (per-extruder physical nozzle inventory by volume type) +extern std::vector> get_extruder_nozzle_stats(const std::vector &strs); +extern std::vector save_extruder_nozzle_stats_to_string(const std::vector> &extruder_nozzle_stats); + #define CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NAME) \ template<> const t_config_enum_names& ConfigOptionEnum::get_enum_names(); \ template<> const t_config_enum_values& ConfigOptionEnum::get_enum_values(); @@ -1297,6 +1324,12 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloats, machine_min_travel_rate)) // M205 S... [mm/sec] ((ConfigOptionFloats, machine_min_extruding_rate)) + // Bedslinger mass/force model: drive the per-layer Y-axis + // acceleration limit (curr_y_acceleration_limit) and the printed-mass check. + // Default 0 => inactive for every existing printer (mass model reads them as disabled). + ((ConfigOptionFloat, machine_max_force_Y)) + ((ConfigOptionFloat, machine_bed_mass_Y)) + ((ConfigOptionFloat, machine_max_printed_mass)) //resonance avoidance ported from qidi slicer ((ConfigOptionBool, resonance_avoidance)) @@ -1351,6 +1384,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionStrings, filament_vendor)) ((ConfigOptionBools, filament_is_support)) ((ConfigOptionInts, filament_printable)) + ((ConfigOptionInts, filament_extruder_compatibility)) ((ConfigOptionFloats, filament_change_length)) ((ConfigOptionFloats, filament_cost)) ((ConfigOptionStrings, default_filament_colour)) @@ -1367,6 +1401,8 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionIntsNullable, nozzle_flush_dataset)) ((ConfigOptionFloatsNullable, filament_flush_volumetric_speed)) ((ConfigOptionIntsNullable, filament_flush_temp)) + // Fast-purge flush temperature; consumed only when prime_volume_mode==pvmFast. + ((ConfigOptionIntsNullable, filament_flush_temp_fast)) // BBS ((ConfigOptionBool, scan_first_layer)) ((ConfigOptionEnum, enable_power_loss_recovery)) @@ -1428,11 +1464,13 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, nozzle_hrc)) ((ConfigOptionBool, auxiliary_fan)) ((ConfigOptionBool, support_air_filtration)) + ((ConfigOptionBool, cooling_filter_enabled)) ((ConfigOptionEnum,printer_structure)) ((ConfigOptionBool, support_chamber_temp_control)) ((ConfigOptionEnumsGeneric, extruder_type)) ((ConfigOptionEnumsGeneric, nozzle_volume_type)) ((ConfigOptionStrings, extruder_ams_count)) + ((ConfigOptionStrings, extruder_nozzle_stats)) ((ConfigOptionInts, printer_extruder_id)) ((ConfigOptionInt, master_extruder_id)) ((ConfigOptionStrings, printer_extruder_variant)) @@ -1490,6 +1528,26 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionStrings, small_area_infill_flow_compensation_model)) ((ConfigOptionBool, has_scarf_joint_seam)) + + // Multi-nozzle + pre-heating + nozzle-change (nc) keys. Defaults are no-ops for existing + // single-nozzle printers; new slicing paths gate on extruder_max_nozzle_count > 1. + ((ConfigOptionFloat, machine_hotend_change_time)) + ((ConfigOptionFloat, machine_prepare_compensation_time)) + ((ConfigOptionBool, enable_pre_heating)) + ((ConfigOptionFloatsNullable, hotend_cooling_rate)) + ((ConfigOptionFloatsNullable, hotend_heating_rate)) + ((ConfigOptionFloats, filament_change_length_nc)) + ((ConfigOptionFloatsNullable, filament_ramming_travel_time)) + ((ConfigOptionIntsNullable, filament_pre_cooling_temperature)) + ((ConfigOptionFloatsNullable, filament_ramming_volumetric_speed)) + ((ConfigOptionFloatsNullable, filament_ramming_travel_time_nc)) + ((ConfigOptionIntsNullable, filament_pre_cooling_temperature_nc)) + ((ConfigOptionFloatsNullable, filament_ramming_volumetric_speed_nc)) + ((ConfigOptionFloatsNullable, filament_retract_length_nc)) + ((ConfigOptionIntsNullable, extruder_max_nozzle_count)) + // 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)) ) // This object is mapped to Perl as Slic3r::Config::Print. @@ -1636,7 +1694,15 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( // BBS: wipe tower is only used for priming ((ConfigOptionFloat, prime_volume)) + // Nozzle-change (nc) prime volume + pre-heat delta + ((ConfigOptionFloats, filament_prime_volume_nc)) + ((ConfigOptionFloatsNullable, filament_preheat_temperature_delta)) ((ConfigOptionFloats, flush_multiplier)) + // Fast-purge mode. Kept out of the g-code config block (banned_keys in + // GCode::append_full_config) so registering them leaves the shipping fleet's g-code byte-identical; + // consumed only on the prime_volume_mode==pvmFast / pvmSaving branch (default pvmDefault = inert). + ((ConfigOptionEnum, prime_volume_mode)) + ((ConfigOptionFloats, flush_multiplier_fast)) ((ConfigOptionFloat, z_offset)) // BBS: project filaments ((ConfigOptionFloats, filament_colour_new)) @@ -1644,6 +1710,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloatsNullable, nozzle_volume)) ((ConfigOptionPoints, start_end_points)) ((ConfigOptionEnum, timelapse_type)) + // Corexy farthest-point timelapse (default false → inert for existing printers) + ((ConfigOptionBool, farthest_point_timelapse)) ((ConfigOptionString, thumbnails)) // BBS: move from PrintObjectConfig ((ConfigOptionBool, independent_support_layer_height)) diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index a76857dc4b..62b2eeb78e 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -102,6 +102,9 @@ const std::string& var_dir(); // Return a full resource path for a file_name. std::string var(const std::string &file_name); +// Snap a nozzle diameter to the closest supported value and format it as a string (e.g. 0.4 -> "0.4"). +std::string format_diameter_to_str(double diameter, int precision = 1); + // Set a path with various static definition data (for example the initial config bundles). void set_resources_dir(const std::string &path); // Return a full path to the resources directory. diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index f69ad3e1a3..fc8e0cddc0 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -83,6 +83,8 @@ public: NozzleVolumeType nozzle_volume_type; BedType bed_type; float nozzle_diameter; + int nozzle_pos_id{-1}; + std::string nozzle_sn; std::string filament_id; std::string setting_id; std::string name; @@ -93,6 +95,8 @@ public: this->extruder_id = other.extruder_id; this->nozzle_volume_type = other.nozzle_volume_type; this->nozzle_diameter = other.nozzle_diameter; + this->nozzle_pos_id = other.nozzle_pos_id; + this->nozzle_sn = other.nozzle_sn; this->filament_id = other.filament_id; this->setting_id = other.setting_id; this->name = other.name; @@ -123,7 +127,9 @@ public: int ams_id = 0; int slot_id = 0; int cali_idx = -1; + int nozzle_pos_id = -1; //-1 means no nozzle pos float nozzle_diameter; + std::string nozzle_sn; std::string filament_id; std::string setting_id; std::string name; @@ -140,7 +146,9 @@ struct PACalibIndexInfo int ams_id = 0; int slot_id = 0; int cali_idx = -1; // -1 means default + int nozzle_pos_id = -1; //-1 means no nozzle pos float nozzle_diameter; + std::string nozzle_sn; std::string filament_id; }; @@ -148,7 +156,9 @@ struct PACalibExtruderInfo { int extruder_id = 0; NozzleVolumeType nozzle_volume_type; + int nozzle_pos_id = -1; //-1 means no nozzle pos float nozzle_diameter; + std::string nozzle_sn; std::string filament_id = ""; bool use_extruder_id{true}; bool use_nozzle_volume_type{true}; diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 131369d212..5f429f076a 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -8,6 +8,10 @@ #include #include #include +#include +#include +#include +#include #include "format.hpp" #include "Platform.hpp" @@ -1497,6 +1501,15 @@ std::string format_memsize(size_t bytes, unsigned int decimals) } } +std::string format_diameter_to_str(double diameter, int precision) +{ + double candidates[] = {0.2, 0.4, 0.6, 0.8}; + double best = *std::min_element(std::begin(candidates), std::end(candidates), [diameter](double a, double b) { return std::abs(a - diameter) < std::abs(b - diameter); }); + std::ostringstream oss; + oss << std::fixed << std::setprecision(precision) << best; + return oss.str(); +} + // Returns platform-specific string to be used as log output or parsed in SysInfoDialog. // The latter parses the string with (semi)colons as separators, it should look about as // "desc1: value1; desc2: value2" or similar (spaces should not matter). From 15412cd8128157b3383cebd2cf184059a0e9457f Mon Sep 17 00:00:00 2001 From: SoftFever Date: Thu, 9 Jul 2026 00:06:27 +0800 Subject: [PATCH 039/130] feat(profiles): Bambu Lab H2C and A2L profiles and resources Machine models and presets, process and filament presets, plus bed models, covers, previews and device images for the H2C and A2L. --- resources/images/Big_Nozzle_HH_01_04.png | Bin 0 -> 131292 bytes resources/images/Big_Nozzle_HH_01_06.png | Bin 0 -> 130104 bytes resources/images/Big_Nozzle_HH_01_08.png | Bin 0 -> 130235 bytes resources/images/Big_Nozzle_HS_01_02.png | Bin 0 -> 128643 bytes resources/images/Big_Nozzle_HS_01_04.png | Bin 0 -> 129406 bytes resources/images/Big_Nozzle_HS_01_06.png | Bin 0 -> 129118 bytes resources/images/Big_Nozzle_HS_01_08.png | Bin 0 -> 129177 bytes resources/images/Nozzle_HH_01_04.png | Bin 0 -> 1353 bytes resources/images/Nozzle_HH_01_06.png | Bin 0 -> 1349 bytes resources/images/Nozzle_HH_01_08.png | Bin 0 -> 1347 bytes resources/images/Nozzle_HS_01_02.png | Bin 0 -> 1349 bytes resources/images/Nozzle_HS_01_04.png | Bin 0 -> 1353 bytes resources/images/Nozzle_HS_01_06.png | Bin 0 -> 1347 bytes resources/images/Nozzle_HS_01_08.png | Bin 0 -> 1350 bytes resources/images/dev_rack_home.svg | 3 + resources/images/dev_rack_nozzle_empty.svg | 16 + resources/images/dev_rack_nozzle_error.svg | 14 + .../images/dev_rack_nozzle_error_icon.svg | 3 + resources/images/dev_rack_nozzle_normal.svg | 15 + .../images/dev_rack_nozzle_print_job.svg | 11 + resources/images/dev_rack_nozzle_selected.svg | 4 + resources/images/dev_rack_nozzle_unknown.svg | 14 + resources/images/dev_rack_row_up.svg | 3 + resources/images/dev_rack_toolhead_empty.svg | 28 + resources/images/dev_rack_toolhead_normal.svg | 42 + resources/images/error.svg | 3 + .../images/extruder_badge_both_selected.svg | 47 + .../extruder_badge_both_selected_dark.svg | 47 + .../images/extruder_badge_left_selected.svg | 43 + .../extruder_badge_left_selected_dark.svg | 43 + .../extruder_badge_left_selected_single.svg | 45 + ...truder_badge_left_selected_single_dark.svg | 45 + .../images/extruder_badge_none_selected.svg | 39 + .../extruder_badge_none_selected_dark.svg | 39 + .../extruder_badge_none_selected_single.svg | 41 + ...truder_badge_none_selected_single_dark.svg | 41 + .../images/extruder_badge_right_selected.svg | 43 + .../extruder_badge_right_selected_dark.svg | 43 + ...ibration_auto_multi_extruders_o1c_left.png | Bin 0 -> 2532605 bytes ...bration_auto_multi_extruders_o1c_right.png | Bin 0 -> 2530021 bytes .../images/filament_load_o1c_series_ext0.png | Bin 0 -> 80043 bytes .../images/filament_load_o1c_series_ext1.png | Bin 0 -> 80870 bytes resources/images/hotend_thumbnail.svg | 13 + resources/images/nozzle_rack.png | Bin 0 -> 78583 bytes resources/images/printer_preview_N9.png | Bin 0 -> 43121 bytes resources/images/printer_preview_O1C.png | Bin 0 -> 3034 bytes resources/images/printer_preview_O1C2.png | Bin 0 -> 3034 bytes resources/images/printer_thumbnail_o1c.png | Bin 0 -> 52036 bytes .../images/printer_thumbnail_o1c_dark.png | Bin 0 -> 52036 bytes .../images/printer_thumbnail_o1c_png.png | Bin 0 -> 52036 bytes resources/images/refresh_nozzle.svg | 9 + resources/images/refresh_nozzle_1.svg | 9 + resources/images/refresh_nozzle_2.svg | 9 + resources/images/refresh_nozzle_3.svg | 9 + resources/images/refresh_nozzle_4.svg | 9 + resources/printers/N9.json | 86 + resources/printers/O1C.json | 98 ++ resources/printers/O1C2.json | 102 ++ resources/printers/filaments_blacklist.json | 218 +++ resources/printers/version.txt | 2 +- resources/profiles/BBL.json | 1498 ++++++++++++++++- .../profiles/BBL/Bambu Lab A2L_cover.png | Bin 0 -> 43121 bytes .../profiles/BBL/Bambu Lab H2C_cover.png | Bin 0 -> 45395 bytes resources/profiles/BBL/bbl-3dp-H2C.stl | Bin 0 -> 86684 bytes resources/profiles/BBL/cli_config.json | 145 ++ .../Bambu ABS @BBL H2C 0.2 nozzle.json | 210 +++ .../Bambu ABS @BBL H2C 0.6 nozzle.json | 204 +++ .../Bambu ABS @BBL H2C 0.8 nozzle.json | 204 +++ .../BBL/filament/Bambu ABS @BBL H2C.json | 204 +++ .../Bambu ABS-GF @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Bambu ABS-GF @BBL H2C.json | 175 ++ .../Bambu ASA @BBL H2C 0.2 nozzle.json | 201 +++ .../Bambu ASA @BBL H2C 0.6 nozzle.json | 198 +++ .../Bambu ASA @BBL H2C 0.8 nozzle.json | 198 +++ .../BBL/filament/Bambu ASA @BBL H2C.json | 198 +++ .../Bambu ASA-Aero @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Bambu ASA-Aero @BBL H2C.json | 175 ++ .../Bambu ASA-CF @BBL H2C 0.4 nozzle.json | 180 ++ .../BBL/filament/Bambu ASA-CF @BBL H2C.json | 175 ++ .../Bambu PA-CF @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Bambu PA-CF @BBL H2C.json | 172 ++ .../Bambu PA6-CF @BBL H2C 0.4 nozzle.json | 198 +++ .../BBL/filament/Bambu PA6-CF @BBL H2C.json | 199 +++ .../Bambu PA6-GF @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Bambu PA6-GF @BBL H2C.json | 175 ++ .../Bambu PAHT-CF @BBL H2C 0.4 nozzle.json | 198 +++ .../BBL/filament/Bambu PAHT-CF @BBL H2C.json | 199 +++ .../Bambu PC @BBL H2C 0.2 nozzle.json | 204 +++ .../Bambu PC @BBL H2C 0.6 nozzle.json | 204 +++ .../Bambu PC @BBL H2C 0.8 nozzle.json | 204 +++ .../BBL/filament/Bambu PC @BBL H2C.json | 204 +++ .../Bambu PC FR @BBL H2C 0.2 nozzle.json | 180 ++ .../Bambu PC FR @BBL H2C 0.4 nozzle.json | 180 ++ .../BBL/filament/Bambu PC FR @BBL H2C.json | 181 ++ .../Bambu PET-CF @BBL H2C 0.4 nozzle.json | 204 +++ .../BBL/filament/Bambu PET-CF @BBL H2C.json | 208 +++ .../Bambu PETG Basic @BBL A2L 0.2 nozzle.json | 74 + .../Bambu PETG Basic @BBL A2L 0.4 nozzle.json | 74 + .../Bambu PETG Basic @BBL A2L 0.6 nozzle.json | 68 + .../Bambu PETG Basic @BBL A2L 0.8 nozzle.json | 68 + .../Bambu PETG Basic @BBL H2C 0.2 nozzle.json | 183 ++ .../Bambu PETG Basic @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PETG Basic @BBL H2C.json | 181 ++ .../Bambu PETG Basic @BBL H2S 0.6 nozzle.json | 178 ++ .../filament/Bambu PETG Basic @BBL H2S.json | 4 +- .../Bambu PETG HF @BBL A2L 0.2 nozzle.json | 77 + .../Bambu PETG HF @BBL A2L 0.6 nozzle.json | 68 + .../Bambu PETG HF @BBL A2L 0.8 nozzle.json | 68 + .../BBL/filament/Bambu PETG HF @BBL A2L.json | 71 + .../Bambu PETG HF @BBL H2C 0.2 nozzle.json | 216 +++ .../Bambu PETG HF @BBL H2C 0.6 nozzle.json | 216 +++ .../Bambu PETG HF @BBL H2C 0.8 nozzle.json | 216 +++ .../BBL/filament/Bambu PETG HF @BBL H2C.json | 216 +++ ... PETG Translucent @BBL A2L 0.2 nozzle.json | 65 + ... PETG Translucent @BBL A2L 0.6 nozzle.json | 41 + ... PETG Translucent @BBL A2L 0.8 nozzle.json | 41 + .../Bambu PETG Translucent @BBL A2L.json | 35 + ... PETG Translucent @BBL H2C 0.2 nozzle.json | 183 ++ ... PETG Translucent @BBL H2C 0.4 nozzle.json | 183 ++ .../Bambu PETG Translucent @BBL H2C.json | 190 +++ .../Bambu PETG-CF @BBL A2L 0.4 nozzle.json | 44 + .../Bambu PETG-CF @BBL A2L 0.8 nozzle.json | 41 + .../BBL/filament/Bambu PETG-CF @BBL A2L.json | 41 + .../Bambu PETG-CF @BBL H2C 0.4 nozzle.json | 213 +++ .../BBL/filament/Bambu PETG-CF @BBL H2C.json | 214 +++ .../Bambu PLA Aero @BBL A2L 0.6 nozzle.json | 44 + .../Bambu PLA Aero @BBL A2L 0.8 nozzle.json | 44 + .../BBL/filament/Bambu PLA Aero @BBL A2L.json | 44 + .../Bambu PLA Aero @BBL H2C 0.4 nozzle.json | 183 ++ .../BBL/filament/Bambu PLA Aero @BBL H2C.json | 184 ++ .../Bambu PLA Basic @BBL A2L 0.2 nozzle.json | 65 + .../Bambu PLA Basic @BBL A2L 0.4 nozzle.json | 65 + .../Bambu PLA Basic @BBL A2L 0.6 nozzle.json | 62 + .../Bambu PLA Basic @BBL A2L 0.8 nozzle.json | 62 + .../Bambu PLA Basic @BBL H2C 0.2 nozzle.json | 213 +++ .../Bambu PLA Basic @BBL H2C 0.6 nozzle.json | 213 +++ .../Bambu PLA Basic @BBL H2C 0.8 nozzle.json | 213 +++ .../filament/Bambu PLA Basic @BBL H2C.json | 213 +++ ...Bambu PLA Dynamic @BBL A2L 0.2 nozzle.json | 53 + ...Bambu PLA Dynamic @BBL A2L 0.6 nozzle.json | 47 + ...Bambu PLA Dynamic @BBL A2L 0.8 nozzle.json | 47 + .../filament/Bambu PLA Dynamic @BBL A2L.json | 47 + ...Bambu PLA Dynamic @BBL H2C 0.2 nozzle.json | 186 ++ ...Bambu PLA Dynamic @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PLA Dynamic @BBL H2C.json | 187 ++ .../Bambu PLA Galaxy @BBL A2L 0.2 nozzle.json | 71 + .../Bambu PLA Galaxy @BBL A2L 0.6 nozzle.json | 59 + .../Bambu PLA Galaxy @BBL A2L 0.8 nozzle.json | 59 + .../filament/Bambu PLA Galaxy @BBL A2L.json | 59 + .../Bambu PLA Galaxy @BBL H2C 0.2 nozzle.json | 186 ++ .../Bambu PLA Galaxy @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PLA Galaxy @BBL H2C.json | 187 ++ .../Bambu PLA Glow @BBL A2L 0.4 nozzle.json | 56 + .../Bambu PLA Glow @BBL A2L 0.6 nozzle.json | 56 + .../Bambu PLA Glow @BBL A2L 0.8 nozzle.json | 47 + .../Bambu PLA Glow @BBL H2C 0.4 nozzle.json | 186 ++ .../BBL/filament/Bambu PLA Glow @BBL H2C.json | 187 ++ .../Bambu PLA Glow @BBL X2D 0.2 nozzle.json | 2 +- .../Bambu PLA Lite @BBL A2L 0.2 nozzle.json | 77 + .../Bambu PLA Lite @BBL A2L 0.4 nozzle.json | 68 + .../Bambu PLA Lite @BBL A2L 0.6 nozzle.json | 65 + .../Bambu PLA Lite @BBL A2L 0.8 nozzle.json | 68 + .../Bambu PLA Lite @BBL H2C 0.2 nozzle.json | 198 +++ .../Bambu PLA Lite @BBL H2C 0.4 nozzle.json | 213 +++ .../BBL/filament/Bambu PLA Lite @BBL H2C.json | 214 +++ .../Bambu PLA Marble @BBL A2L 0.6 nozzle.json | 50 + .../Bambu PLA Marble @BBL A2L 0.8 nozzle.json | 50 + .../filament/Bambu PLA Marble @BBL A2L.json | 50 + .../Bambu PLA Marble @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PLA Marble @BBL H2C.json | 187 ++ .../Bambu PLA Matte @BBL A2L 0.2 nozzle.json | 71 + .../Bambu PLA Matte @BBL A2L 0.4 nozzle.json | 65 + .../Bambu PLA Matte @BBL A2L 0.6 nozzle.json | 65 + .../Bambu PLA Matte @BBL A2L 0.8 nozzle.json | 62 + .../Bambu PLA Matte @BBL H2C 0.2 nozzle.json | 213 +++ .../Bambu PLA Matte @BBL H2C 0.6 nozzle.json | 213 +++ .../Bambu PLA Matte @BBL H2C 0.8 nozzle.json | 213 +++ .../filament/Bambu PLA Matte @BBL H2C.json | 213 +++ .../Bambu PLA Metal @BBL A2L 0.2 nozzle.json | 65 + .../Bambu PLA Metal @BBL A2L 0.6 nozzle.json | 56 + .../Bambu PLA Metal @BBL A2L 0.8 nozzle.json | 44 + .../filament/Bambu PLA Metal @BBL A2L.json | 44 + .../Bambu PLA Metal @BBL H2C 0.2 nozzle.json | 186 ++ .../Bambu PLA Metal @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PLA Metal @BBL H2C.json | 187 ++ .../Bambu PLA Pure @BBL A2L 0.2 nozzle.json | 56 + .../Bambu PLA Pure @BBL A2L 0.6 nozzle.json | 50 + .../Bambu PLA Pure @BBL A2L 0.8 nozzle.json | 50 + .../BBL/filament/Bambu PLA Pure @BBL A2L.json | 53 + .../Bambu PLA Pure @BBL H2C 0.2 nozzle.json | 183 ++ .../BBL/filament/Bambu PLA Pure @BBL H2C.json | 182 ++ .../Bambu PLA Pure @BBL H2D 0.2 nozzle.json | 171 ++ .../Bambu PLA Pure @BBL H2D 0.8 nozzle.json | 169 ++ .../BBL/filament/Bambu PLA Pure @BBL H2D.json | 168 ++ .../Bambu PLA Pure @BBL H2DP 0.2 nozzle.json | 171 ++ .../Bambu PLA Pure @BBL H2DP 0.8 nozzle.json | 169 ++ .../filament/Bambu PLA Pure @BBL H2DP.json | 168 ++ .../Bambu PLA Pure @BBL H2S 0.2 nozzle.json | 171 ++ .../BBL/filament/Bambu PLA Pure @BBL H2S.json | 171 ++ .../BBL/filament/Bambu PLA Pure @base.json | 29 + .../Bambu PLA Silk @BBL A2L 0.2 nozzle.json | 62 + .../Bambu PLA Silk @BBL A2L 0.4 nozzle.json | 56 + .../Bambu PLA Silk @BBL A2L 0.6 nozzle.json | 53 + .../Bambu PLA Silk @BBL A2L 0.8 nozzle.json | 56 + .../Bambu PLA Silk @BBL H2C 0.2 nozzle.json | 207 +++ .../Bambu PLA Silk @BBL H2C 0.4 nozzle.json | 207 +++ .../BBL/filament/Bambu PLA Silk @BBL H2C.json | 208 +++ .../Bambu PLA Silk+ @BBL A2L 0.2 nozzle.json | 71 + .../Bambu PLA Silk+ @BBL A2L 0.4 nozzle.json | 62 + .../Bambu PLA Silk+ @BBL A2L 0.6 nozzle.json | 62 + .../Bambu PLA Silk+ @BBL A2L 0.8 nozzle.json | 62 + .../Bambu PLA Silk+ @BBL H2C 0.2 nozzle.json | 189 +++ .../Bambu PLA Silk+ @BBL H2C 0.4 nozzle.json | 189 +++ .../filament/Bambu PLA Silk+ @BBL H2C.json | 190 +++ ...Bambu PLA Sparkle @BBL A2L 0.6 nozzle.json | 41 + ...Bambu PLA Sparkle @BBL A2L 0.8 nozzle.json | 41 + .../filament/Bambu PLA Sparkle @BBL A2L.json | 41 + ...Bambu PLA Sparkle @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu PLA Sparkle @BBL H2C.json | 187 ++ .../Bambu PLA Tough @BBL A2L 0.2 nozzle.json | 50 + .../filament/Bambu PLA Tough @BBL A2L.json | 49 + .../Bambu PLA Tough @BBL H2C 0.2 nozzle.json | 186 ++ .../Bambu PLA Tough @BBL H2C 0.4 nozzle.json | 204 +++ .../filament/Bambu PLA Tough @BBL H2C.json | 205 +++ .../Bambu PLA Tough+ @BBL A2L 0.2 nozzle.json | 71 + .../Bambu PLA Tough+ @BBL A2L 0.4 nozzle.json | 47 + .../Bambu PLA Tough+ @BBL A2L 0.6 nozzle.json | 50 + .../Bambu PLA Tough+ @BBL A2L 0.8 nozzle.json | 59 + .../Bambu PLA Tough+ @BBL H2C 0.2 nozzle.json | 180 ++ .../Bambu PLA Tough+ @BBL H2C 0.6 nozzle.json | 192 +++ .../Bambu PLA Tough+ @BBL H2C 0.8 nozzle.json | 192 +++ .../filament/Bambu PLA Tough+ @BBL H2C.json | 192 +++ ...u PLA Translucent @BBL A2L 0.2 nozzle.json | 71 + ...u PLA Translucent @BBL A2L 0.6 nozzle.json | 44 + ...u PLA Translucent @BBL A2L 0.8 nozzle.json | 44 + .../Bambu PLA Translucent @BBL A2L.json | 59 + ...u PLA Translucent @BBL H2C 0.2 nozzle.json | 189 +++ .../Bambu PLA Translucent @BBL H2C.json | 191 +++ .../Bambu PLA Wood @BBL A2L 0.6 nozzle.json | 44 + .../Bambu PLA Wood @BBL A2L 0.8 nozzle.json | 44 + .../BBL/filament/Bambu PLA Wood @BBL A2L.json | 44 + .../Bambu PLA Wood @BBL H2C 0.4 nozzle.json | 186 ++ .../BBL/filament/Bambu PLA Wood @BBL H2C.json | 187 ++ .../Bambu PLA-CF @BBL A2L 0.6 nozzle.json | 56 + .../Bambu PLA-CF @BBL A2L 0.8 nozzle.json | 56 + .../BBL/filament/Bambu PLA-CF @BBL A2L.json | 68 + .../Bambu PLA-CF @BBL H2C 0.4 nozzle.json | 198 +++ .../BBL/filament/Bambu PLA-CF @BBL H2C.json | 199 +++ .../Bambu PPA-CF @BBL H2C 0.4 nozzle.json | 201 +++ .../BBL/filament/Bambu PPA-CF @BBL H2C.json | 202 +++ .../Bambu PPS-CF @BBL H2C 0.4 nozzle.json | 201 +++ .../BBL/filament/Bambu PPS-CF @BBL H2C.json | 202 +++ .../BBL/filament/Bambu PVA @BBL A2L.json | 55 + .../Bambu PVA @BBL H2C 0.4 nozzle.json | 177 ++ .../BBL/filament/Bambu PVA @BBL H2C.json | 178 ++ ...upport For PA PET @BBL H2C 0.4 nozzle.json | 174 ++ .../Bambu Support For PA PET @BBL H2C.json | 175 ++ ...u Support For PLA @BBL A2L 0.2 nozzle.json | 62 + ...u Support For PLA @BBL A2L 0.6 nozzle.json | 47 + ...u Support For PLA @BBL A2L 0.8 nozzle.json | 47 + .../Bambu Support For PLA @BBL A2L.json | 47 + ...u Support For PLA @BBL H2C 0.2 nozzle.json | 186 ++ ...u Support For PLA @BBL H2C 0.4 nozzle.json | 186 ++ .../Bambu Support For PLA @BBL H2C.json | 187 ++ ...port For PLA-PETG @BBL A2L 0.2 nozzle.json | 53 + .../Bambu Support For PLA-PETG @BBL A2L.json | 49 + ...port For PLA-PETG @BBL H2C 0.2 nozzle.json | 180 ++ ...port For PLA-PETG @BBL H2C 0.4 nozzle.json | 180 ++ .../Bambu Support For PLA-PETG @BBL H2C.json | 181 ++ .../Bambu Support G @BBL H2C 0.4 nozzle.json | 174 ++ .../filament/Bambu Support G @BBL H2C.json | 175 ++ .../Bambu Support W @BBL A2L 0.2 nozzle.json | 56 + .../filament/Bambu Support W @BBL A2L.json | 46 + .../Bambu Support W @BBL H2C 0.2 nozzle.json | 180 ++ .../Bambu Support W @BBL H2C 0.4 nozzle.json | 180 ++ .../filament/Bambu Support W @BBL H2C.json | 181 ++ ...u Support for ABS @BBL H2C 0.4 nozzle.json | 174 ++ .../Bambu Support for ABS @BBL H2C.json | 175 ++ .../Bambu TPU 85A @BBL A2L 0.6 nozzle.json | 77 + .../Bambu TPU 85A @BBL A2L 0.8 nozzle.json | 80 + .../BBL/filament/Bambu TPU 85A @BBL H2C.json | 199 +++ .../Bambu TPU 85A @BBL H2D 0.4 nozzle.json | 101 ++ .../BBL/filament/Bambu TPU 85A @BBL H2D.json | 51 +- .../Bambu TPU 85A @BBL H2DP 0.4 nozzle.json | 101 ++ .../BBL/filament/Bambu TPU 85A @BBL H2DP.json | 51 +- .../Bambu TPU 90A @BBL A2L 0.6 nozzle.json | 44 + .../Bambu TPU 90A @BBL A2L 0.8 nozzle.json | 47 + .../BBL/filament/Bambu TPU 90A @BBL A2L.json | 38 + .../Bambu TPU 90A @BBL H2C 0.4 nozzle.json | 195 +++ .../BBL/filament/Bambu TPU 90A @BBL H2C.json | 196 +++ .../Bambu TPU 90A @BBL H2D 0.6 nozzle.json | 205 +++ .../Bambu TPU 90A @BBL H2D 0.8 nozzle.json | 171 ++ .../BBL/filament/Bambu TPU 90A @BBL H2D.json | 51 +- .../Bambu TPU 90A @BBL H2DP 0.6 nozzle.json | 205 +++ .../Bambu TPU 90A @BBL H2DP 0.8 nozzle.json | 171 ++ .../BBL/filament/Bambu TPU 90A @BBL H2DP.json | 51 +- .../BBL/filament/Bambu TPU 95A @BBL A2L.json | 28 + .../Bambu TPU 95A @BBL H2C 0.4 nozzle.json | 180 ++ .../BBL/filament/Bambu TPU 95A @BBL H2C.json | 181 ++ .../BBL/filament/Bambu TPU 95A @BBL H2D.json | 29 +- .../BBL/filament/Bambu TPU 95A @BBL H2DP.json | 29 +- .../Bambu TPU 95A HF @BBL A2L 0.6 nozzle.json | 35 + .../Bambu TPU 95A HF @BBL A2L 0.8 nozzle.json | 35 + .../filament/Bambu TPU 95A HF @BBL A2L.json | 41 + .../Bambu TPU 95A HF @BBL H2C 0.4 nozzle.json | 183 ++ .../filament/Bambu TPU 95A HF @BBL H2C.json | 184 ++ .../Bambu TPU 95A HF @BBL H2D 0.4 nozzle.json | 46 + .../filament/Bambu TPU 95A HF @BBL H2D.json | 50 +- ...Bambu TPU 95A HF @BBL H2DP 0.4 nozzle.json | 51 + .../filament/Bambu TPU 95A HF @BBL H2DP.json | 48 +- ...Bambu TPU for AMS @BBL A2L 0.6 nozzle.json | 38 + ...Bambu TPU for AMS @BBL A2L 0.8 nozzle.json | 38 + .../filament/Bambu TPU for AMS @BBL A2L.json | 47 + ...Bambu TPU for AMS @BBL H2C 0.4 nozzle.json | 186 ++ .../filament/Bambu TPU for AMS @BBL H2C.json | 187 ++ .../Generic ABS @BBL H2C 0.2 nozzle.json | 180 ++ .../Generic ABS @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Generic ABS @BBL H2C.json | 172 ++ .../Generic ASA @BBL H2C 0.2 nozzle.json | 177 ++ .../Generic ASA @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic ASA @BBL H2C.json | 175 ++ .../BBL/filament/Generic BVOH @BBL A2L.json | 19 + .../Generic BVOH @BBL H2C 0.4 nozzle.json | 177 ++ .../BBL/filament/Generic BVOH @BBL H2C.json | 178 ++ .../BBL/filament/Generic EVA @BBL A2L.json | 20 + .../Generic EVA @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic EVA @BBL H2C.json | 179 ++ .../Generic HIPS @BBL A2L 0.2 nozzle.json | 41 + .../BBL/filament/Generic HIPS @BBL A2L.json | 37 + .../Generic HIPS @BBL H2C 0.2 nozzle.json | 171 ++ .../Generic HIPS @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Generic HIPS @BBL H2C.json | 172 ++ .../Generic PA @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Generic PA @BBL H2C.json | 172 ++ .../Generic PA-CF @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PA-CF @BBL H2C.json | 175 ++ .../Generic PC @BBL H2C 0.2 nozzle.json | 174 ++ .../Generic PC @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PC @BBL H2C.json | 175 ++ .../BBL/filament/Generic PCTG @BBL A2L.json | 19 + .../Generic PCTG @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Generic PCTG @BBL H2C.json | 172 ++ .../BBL/filament/Generic PE @BBL A2L.json | 20 + .../Generic PE @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic PE @BBL H2C.json | 179 ++ .../BBL/filament/Generic PE-CF @BBL A2L.json | 20 + .../Generic PE-CF @BBL H2C 0.4 nozzle.json | 177 ++ .../BBL/filament/Generic PE-CF @BBL H2C.json | 178 ++ .../Generic PETG @BBL A2L 0.2 nozzle.json | 26 + .../BBL/filament/Generic PETG @BBL A2L.json | 25 + .../Generic PETG @BBL H2C 0.2 nozzle.json | 174 ++ .../Generic PETG @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PETG @BBL H2C.json | 175 ++ .../Generic PETG HF @BBL A2L 0.2 nozzle.json | 23 + .../filament/Generic PETG HF @BBL A2L.json | 25 + .../Generic PETG HF @BBL H2C 0.2 nozzle.json | 174 ++ .../Generic PETG HF @BBL H2C 0.4 nozzle.json | 174 ++ .../filament/Generic PETG HF @BBL H2C.json | 175 ++ .../filament/Generic PETG-CF @BBL A2L.json | 25 + .../Generic PETG-CF @BBL H2C 0.4 nozzle.json | 183 ++ .../filament/Generic PETG-CF @BBL H2C.json | 184 ++ .../BBL/filament/Generic PHA @BBL A2L.json | 20 + .../Generic PHA @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic PHA @BBL H2C.json | 179 ++ .../Generic PLA @BBL A2L 0.2 nozzle.json | 44 + .../BBL/filament/Generic PLA @BBL A2L.json | 40 + .../Generic PLA @BBL H2C 0.2 nozzle.json | 180 ++ .../Generic PLA @BBL H2C 0.4 nozzle.json | 180 ++ .../BBL/filament/Generic PLA @BBL H2C.json | 181 ++ ...ic PLA High Speed @BBL A2L 0.2 nozzle.json | 47 + .../Generic PLA High Speed @BBL A2L.json | 43 + ...ic PLA High Speed @BBL H2C 0.2 nozzle.json | 180 ++ ...ic PLA High Speed @BBL H2C 0.4 nozzle.json | 183 ++ .../Generic PLA High Speed @BBL H2C.json | 184 ++ .../filament/Generic PLA Silk @BBL A2L.json | 46 + .../Generic PLA Silk @BBL H2C 0.4 nozzle.json | 180 ++ .../filament/Generic PLA Silk @BBL H2C.json | 181 ++ .../BBL/filament/Generic PLA-CF @BBL A2L.json | 43 + .../Generic PLA-CF @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PLA-CF @BBL H2C.json | 175 ++ .../BBL/filament/Generic PP @BBL A2L.json | 20 + .../Generic PP @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic PP @BBL H2C.json | 179 ++ .../Generic PP-CF @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic PP-CF @BBL H2C.json | 179 ++ .../Generic PP-GF @BBL H2C 0.4 nozzle.json | 178 ++ .../BBL/filament/Generic PP-GF @BBL H2C.json | 179 ++ .../Generic PPA-CF @BBL H2C 0.4 nozzle.json | 180 ++ .../BBL/filament/Generic PPA-CF @BBL H2C.json | 184 ++ .../Generic PPA-GF @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PPA-GF @BBL H2C.json | 175 ++ .../Generic PPS @BBL H2C 0.4 nozzle.json | 171 ++ .../BBL/filament/Generic PPS @BBL H2C.json | 172 ++ .../Generic PPS-CF @BBL H2C 0.4 nozzle.json | 168 ++ .../BBL/filament/Generic PPS-CF @BBL H2C.json | 172 ++ .../Generic PVA @BBL A2L 0.2 nozzle.json | 47 + .../BBL/filament/Generic PVA @BBL A2L.json | 43 + .../Generic PVA @BBL H2C 0.2 nozzle.json | 174 ++ .../Generic PVA @BBL H2C 0.4 nozzle.json | 174 ++ .../BBL/filament/Generic PVA @BBL H2C.json | 175 ++ .../BBL/filament/Generic TPU @BBL A2L.json | 31 + .../Generic TPU @BBL H2C 0.4 nozzle.json | 183 ++ .../BBL/filament/Generic TPU @BBL H2C.json | 184 ++ .../BBL/filament/Generic TPU @BBL H2D.json | 29 +- .../BBL/filament/Generic TPU @BBL H2DP.json | 29 +- .../Generic TPU for AMS @BBL A2L.json | 34 + ...neric TPU for AMS @BBL H2C 0.4 nozzle.json | 195 +++ .../Generic TPU for AMS @BBL H2C.json | 196 +++ .../BBL/machine/Bambu Lab A2L 0.2 nozzle.json | 37 + .../BBL/machine/Bambu Lab A2L 0.4 nozzle.json | 99 ++ .../BBL/machine/Bambu Lab A2L 0.6 nozzle.json | 37 + .../BBL/machine/Bambu Lab A2L 0.8 nozzle.json | 37 + .../profiles/BBL/machine/Bambu Lab A2L.json | 17 + .../BBL/machine/Bambu Lab H2C 0.2 nozzle.json | 38 + .../BBL/machine/Bambu Lab H2C 0.4 nozzle.json | 138 ++ .../BBL/machine/Bambu Lab H2C 0.6 nozzle.json | 38 + .../BBL/machine/Bambu Lab H2C 0.8 nozzle.json | 38 + .../profiles/BBL/machine/Bambu Lab H2C.json | 16 + .../BBL/machine/Bambu Lab H2D 0.2 nozzle.json | 298 ++++ .../BBL/machine/Bambu Lab H2D 0.4 nozzle.json | 300 +++- .../BBL/machine/Bambu Lab H2D 0.6 nozzle.json | 1 + .../BBL/machine/Bambu Lab H2D 0.8 nozzle.json | 298 ++++ .../machine/Bambu Lab H2D Pro 0.2 nozzle.json | 292 ++++ .../machine/Bambu Lab H2D Pro 0.4 nozzle.json | 290 +++- .../machine/Bambu Lab H2D Pro 0.6 nozzle.json | 1 + .../machine/Bambu Lab H2D Pro 0.8 nozzle.json | 292 ++++ .../BBL/machine/Bambu Lab H2D Pro.json | 2 +- .../profiles/BBL/machine/Bambu Lab H2D.json | 2 +- .../profiles/BBL/machine/Bambu Lab H2S.json | 2 +- .../process/0.08mm Extra Fine @BBL H2D.json | 132 ++ .../process/0.08mm Extra Fine @BBL H2DP.json | 132 ++ ...08mm High Quality @BBL A2L 0.2 nozzle.json | 44 + .../process/0.08mm High Quality @BBL A2L.json | 65 + ...08mm High Quality @BBL H2C 0.2 nozzle.json | 45 + .../process/0.08mm High Quality @BBL H2C.json | 93 + .../0.10mm Standard @BBL A2L 0.2 nozzle.json | 51 + .../0.10mm Standard @BBL H2C 0.2 nozzle.json | 46 + ... Balanced Quality @BBL A2L 0.2 nozzle.json | 37 + ... Balanced Quality @BBL H2C 0.2 nozzle.json | 44 + .../BBL/process/0.12mm Fine @BBL H2D.json | 132 ++ .../BBL/process/0.12mm Fine @BBL H2DP.json | 132 ++ .../process/0.12mm High Quality @BBL A2L.json | 65 + .../process/0.12mm High Quality @BBL H2C.json | 97 ++ .../0.16mm Balanced Quality @BBL H2D.json | 144 ++ .../0.16mm Balanced Quality @BBL H2DP.json | 144 ++ .../process/0.16mm High Quality @BBL A2L.json | 65 + .../process/0.16mm High Quality @BBL H2C.json | 84 + .../BBL/process/0.16mm Standard @BBL A2L.json | 43 + .../BBL/process/0.16mm Standard @BBL H2C.json | 69 + .../BBL/process/0.16mm Standard @BBL H2D.json | 168 ++ .../process/0.16mm Standard @BBL H2DP.json | 168 ++ ... Balanced Quality @BBL A2L 0.6 nozzle.json | 31 + ... Balanced Quality @BBL H2C 0.6 nozzle.json | 75 + ... Balanced Quality @BBL H2D 0.6 nozzle.json | 138 ++ ...Balanced Quality @BBL H2DP 0.6 nozzle.json | 138 ++ .../0.20mm Balanced Strength @BBL H2D.json | 150 ++ .../0.20mm Balanced Strength @BBL H2DP.json | 150 ++ .../process/0.20mm High Quality @BBL A2L.json | 68 + .../process/0.20mm High Quality @BBL H2C.json | 83 + .../BBL/process/0.20mm Standard @BBL A2L.json | 43 + .../BBL/process/0.20mm Standard @BBL H2C.json | 64 + .../BBL/process/0.20mm Standard @BBL H2D.json | 168 ++ .../process/0.20mm Standard @BBL H2DP.json | 174 ++ .../BBL/process/0.20mm Steady @BBL A2L.json | 180 ++ ... Balanced Quality @BBL A2L 0.6 nozzle.json | 31 + ... Balanced Quality @BBL A2L 0.8 nozzle.json | 31 + ... Balanced Quality @BBL H2C 0.8 nozzle.json | 81 + ...Balanced Strength @BBL H2C 0.6 nozzle.json | 87 + ...Balanced Strength @BBL H2D 0.6 nozzle.json | 138 ++ ...alanced Strength @BBL H2DP 0.6 nozzle.json | 138 ++ .../BBL/process/0.24mm Standard @BBL A2L.json | 43 + .../BBL/process/0.24mm Standard @BBL H2C.json | 50 + .../BBL/process/0.24mm Standard @BBL H2D.json | 174 ++ .../process/0.24mm Standard @BBL H2DP.json | 174 ++ .../0.30mm Standard @BBL A2L 0.6 nozzle.json | 40 + .../0.30mm Standard @BBL H2C 0.6 nozzle.json | 76 + .../0.30mm Standard @BBL H2D 0.6 nozzle.json | 138 ++ .../0.30mm Standard @BBL H2DP 0.6 nozzle.json | 138 ++ ... Balanced Quality @BBL A2L 0.8 nozzle.json | 31 + ...Balanced Strength @BBL H2C 0.8 nozzle.json | 93 + .../0.40mm Standard @BBL A2L 0.8 nozzle.json | 31 + .../0.40mm Standard @BBL H2C 0.8 nozzle.json | 82 + resources/shaders/110/gouraud.fs | 15 + resources/shaders/140/gouraud.fs | 15 + resources/web/flush/NozzleListTable.html | 287 ++++ 485 files changed, 54932 insertions(+), 89 deletions(-) create mode 100644 resources/images/Big_Nozzle_HH_01_04.png create mode 100644 resources/images/Big_Nozzle_HH_01_06.png create mode 100644 resources/images/Big_Nozzle_HH_01_08.png create mode 100644 resources/images/Big_Nozzle_HS_01_02.png create mode 100644 resources/images/Big_Nozzle_HS_01_04.png create mode 100644 resources/images/Big_Nozzle_HS_01_06.png create mode 100644 resources/images/Big_Nozzle_HS_01_08.png create mode 100644 resources/images/Nozzle_HH_01_04.png create mode 100644 resources/images/Nozzle_HH_01_06.png create mode 100644 resources/images/Nozzle_HH_01_08.png create mode 100644 resources/images/Nozzle_HS_01_02.png create mode 100644 resources/images/Nozzle_HS_01_04.png create mode 100644 resources/images/Nozzle_HS_01_06.png create mode 100644 resources/images/Nozzle_HS_01_08.png create mode 100644 resources/images/dev_rack_home.svg create mode 100644 resources/images/dev_rack_nozzle_empty.svg create mode 100644 resources/images/dev_rack_nozzle_error.svg create mode 100644 resources/images/dev_rack_nozzle_error_icon.svg create mode 100644 resources/images/dev_rack_nozzle_normal.svg create mode 100644 resources/images/dev_rack_nozzle_print_job.svg create mode 100644 resources/images/dev_rack_nozzle_selected.svg create mode 100644 resources/images/dev_rack_nozzle_unknown.svg create mode 100644 resources/images/dev_rack_row_up.svg create mode 100644 resources/images/dev_rack_toolhead_empty.svg create mode 100644 resources/images/dev_rack_toolhead_normal.svg create mode 100644 resources/images/error.svg create mode 100644 resources/images/extruder_badge_both_selected.svg create mode 100644 resources/images/extruder_badge_both_selected_dark.svg create mode 100644 resources/images/extruder_badge_left_selected.svg create mode 100644 resources/images/extruder_badge_left_selected_dark.svg create mode 100644 resources/images/extruder_badge_left_selected_single.svg create mode 100644 resources/images/extruder_badge_left_selected_single_dark.svg create mode 100644 resources/images/extruder_badge_none_selected.svg create mode 100644 resources/images/extruder_badge_none_selected_dark.svg create mode 100644 resources/images/extruder_badge_none_selected_single.svg create mode 100644 resources/images/extruder_badge_none_selected_single_dark.svg create mode 100644 resources/images/extruder_badge_right_selected.svg create mode 100644 resources/images/extruder_badge_right_selected_dark.svg create mode 100644 resources/images/fd_calibration_auto_multi_extruders_o1c_left.png create mode 100644 resources/images/fd_calibration_auto_multi_extruders_o1c_right.png create mode 100644 resources/images/filament_load_o1c_series_ext0.png create mode 100644 resources/images/filament_load_o1c_series_ext1.png create mode 100644 resources/images/hotend_thumbnail.svg create mode 100644 resources/images/nozzle_rack.png create mode 100644 resources/images/printer_preview_N9.png create mode 100644 resources/images/printer_preview_O1C.png create mode 100644 resources/images/printer_preview_O1C2.png create mode 100644 resources/images/printer_thumbnail_o1c.png create mode 100644 resources/images/printer_thumbnail_o1c_dark.png create mode 100644 resources/images/printer_thumbnail_o1c_png.png create mode 100644 resources/images/refresh_nozzle.svg create mode 100644 resources/images/refresh_nozzle_1.svg create mode 100644 resources/images/refresh_nozzle_2.svg create mode 100644 resources/images/refresh_nozzle_3.svg create mode 100644 resources/images/refresh_nozzle_4.svg create mode 100644 resources/printers/N9.json create mode 100644 resources/printers/O1C.json create mode 100644 resources/printers/O1C2.json create mode 100644 resources/profiles/BBL/Bambu Lab A2L_cover.png create mode 100644 resources/profiles/BBL/Bambu Lab H2C_cover.png create mode 100644 resources/profiles/BBL/bbl-3dp-H2C.stl create mode 100644 resources/profiles/BBL/filament/Bambu ABS @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ABS @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ABS @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ABS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu ABS-GF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ABS-GF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA-Aero @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA-Aero @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu ASA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PA6-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PA6-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PA6-GF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PA6-GF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PAHT-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PAHT-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PC @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PC @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PC @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PC @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PC FR @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PC FR @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PC FR @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PET-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PET-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Basic @BBL H2S 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG HF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG Translucent @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG-CF @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG-CF @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG-CF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PETG-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Aero @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Aero @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Aero @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Aero @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Aero @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Basic @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Dynamic @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Galaxy @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Glow @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Glow @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Glow @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Glow @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Glow @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Lite @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Marble @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Marble @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Marble @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Marble @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Marble @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Matte @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Metal @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2D 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2D 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2D.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2DP 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2DP 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2DP.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2S 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @BBL H2S.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Pure @base.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Silk+ @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Sparkle @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Tough+ @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Translucent @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Wood @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Wood @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Wood @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Wood @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA Wood @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA-CF @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA-CF @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA-CF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PLA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PPA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PPA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PPS-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PPS-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu PVA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu PVA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu PVA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PA PET @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PA PET @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA-PETG @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA-PETG @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA-PETG @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA-PETG @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support For PLA-PETG @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support G @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support G @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support W @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support W @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu Support W @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support W @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support W @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu Support for ABS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu Support for ABS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 85A @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 85A @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 85A @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 85A @BBL H2D 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 85A @BBL H2DP 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2D 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2D 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2DP 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 90A @BBL H2DP 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL H2D 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU 95A HF @BBL H2DP 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU for AMS @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU for AMS @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU for AMS @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU for AMS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Bambu TPU for AMS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic ABS @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic ABS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic ABS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic ASA @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic ASA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic ASA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic BVOH @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic BVOH @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic BVOH @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic EVA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic EVA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic EVA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic HIPS @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic HIPS @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic HIPS @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic HIPS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic HIPS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PC @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PC @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PC @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PCTG @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PCTG @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PCTG @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PE @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PE @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PE @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PE-CF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PE-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PE-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PETG @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PETG @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PETG HF @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG HF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PETG HF @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG HF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG HF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PETG-CF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PETG-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PETG-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PHA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PHA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PHA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PLA @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PLA @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PLA High Speed @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA High Speed @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PLA High Speed @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA High Speed @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA High Speed @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PLA Silk @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PLA Silk @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA Silk @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PLA-CF @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PLA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PLA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PP @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PP @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PP @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PP-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PP-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PP-GF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PP-GF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PPA-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PPA-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PPA-GF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PPA-GF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PPS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PPS @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PPS-CF @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PPS-CF @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic PVA @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PVA @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic PVA @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PVA @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic PVA @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic TPU @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic TPU @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic TPU @BBL H2C.json create mode 100644 resources/profiles/BBL/filament/Generic TPU for AMS @BBL A2L.json create mode 100644 resources/profiles/BBL/filament/Generic TPU for AMS @BBL H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/filament/Generic TPU for AMS @BBL H2C.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab A2L 0.4 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab A2L.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab H2C 0.4 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/machine/Bambu Lab H2C.json create mode 100644 resources/profiles/BBL/process/0.08mm High Quality @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.08mm High Quality @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.08mm High Quality @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.08mm High Quality @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.10mm Standard @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.10mm Standard @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.12mm Balanced Quality @BBL A2L 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.12mm Balanced Quality @BBL H2C 0.2 nozzle.json create mode 100644 resources/profiles/BBL/process/0.12mm High Quality @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.12mm High Quality @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.16mm High Quality @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.16mm High Quality @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.16mm Standard @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.16mm Standard @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.18mm Balanced Quality @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.18mm Balanced Quality @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.20mm High Quality @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.20mm High Quality @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.20mm Standard @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.20mm Standard @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.20mm Steady @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.24mm Balanced Quality @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.24mm Balanced Quality @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/process/0.24mm Balanced Quality @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/process/0.24mm Balanced Strength @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.24mm Standard @BBL A2L.json create mode 100644 resources/profiles/BBL/process/0.24mm Standard @BBL H2C.json create mode 100644 resources/profiles/BBL/process/0.30mm Standard @BBL A2L 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.30mm Standard @BBL H2C 0.6 nozzle.json create mode 100644 resources/profiles/BBL/process/0.32mm Balanced Quality @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/process/0.32mm Balanced Strength @BBL H2C 0.8 nozzle.json create mode 100644 resources/profiles/BBL/process/0.40mm Standard @BBL A2L 0.8 nozzle.json create mode 100644 resources/profiles/BBL/process/0.40mm Standard @BBL H2C 0.8 nozzle.json create mode 100644 resources/web/flush/NozzleListTable.html diff --git a/resources/images/Big_Nozzle_HH_01_04.png b/resources/images/Big_Nozzle_HH_01_04.png new file mode 100644 index 0000000000000000000000000000000000000000..483d6b9f84b17d4179cb2a21619dff2ea282ee68 GIT binary patch literal 131292 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

?)@P1@bL@TNEV=D6@5UZDas%$AvZ9GZ`Z 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 literal 0 HcmV?d00001 diff --git a/resources/images/Big_Nozzle_HH_01_08.png b/resources/images/Big_Nozzle_HH_01_08.png new file mode 100644 index 0000000000000000000000000000000000000000..caf120fbd2c04a7b0706a2cf0e637c184fb16c62 GIT binary patch literal 130235 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 literal 0 HcmV?d00001 diff --git a/resources/images/Big_Nozzle_HS_01_04.png b/resources/images/Big_Nozzle_HS_01_04.png new file mode 100644 index 0000000000000000000000000000000000000000..49aab4f2b4e5271b02eb26dd847e6dcfddb77236 GIT binary patch literal 129406 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%0DRyz4z+MsUE>W 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�()>|xY(Q(be53di|Da*v1L8O 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 kp!c}@kKDZ-)OG?KNe7!$w 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