mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-06 01:27:40 +00:00
feat(engine): stitch per-object selector plans for sequential prints
Sequential (by-object) prints were incoherent with the per-layer filament selector (enable_filament_dynamic_map): the by-object branch published a static grouping while each per-object ToolOrdering independently ran the dynamic planner from an empty nozzle status and wrote its own map to the config (one write per object, last object wins). The exported toolchange sequences then disagreed with the published result that drives the per-layer maps, placeholders, and selector emission. Now the by-object branch, when the selector is enabled, plans each unique object once — threading the physical nozzle occupancy and the previous object's last filament into the next plan — stitches the per-object per-layer nozzle maps into one print-wide result (gap-filled by the new normalize_nozzle_map_per_layer so any layer index resolves a filament's nozzle consistently), publishes it, and writes the derived extruder map back once. The plans are cached on the Print and g-code export consumes the cache: the ToolOrdering seed changes the plan input (dontcare assignment, first-layer reorder), so a fresh export-time construction could re-plan differently from the published stitch. The per-object dynamic write-back is gated off for sequential prints. Every change is gated behind is_dynamic_group_reorder(); no profile sets the flag, so the static fleet's instruction stream is unchanged (20/20 pinned-slice byte gate identical, incl. the by-object repro sliced twice). Tests: normalize unit coverage (carry-forward, back-fill, ragged input), stitched-blocks selector detection, and an end-to-end by-object selector slice (apply -> process -> export) asserting the published stitched result, one cached plan per object, the config write-back, and a clean export. Suites green (libslic3r 48958/165, fff_print 633/60).
This commit is contained in:
@@ -52,6 +52,54 @@ std::vector<NozzleInfo> build_nozzle_list(double diameter, const std::vector<int
|
||||
return ret;
|
||||
}
|
||||
|
||||
void normalize_nozzle_map_per_layer(std::vector<std::vector<int>> &layer_filament_nozzle_maps,
|
||||
const std::vector<std::vector<unsigned int>> &layer_filaments)
|
||||
{
|
||||
if (layer_filament_nozzle_maps.empty())
|
||||
return;
|
||||
|
||||
const int total_layers = static_cast<int>(layer_filament_nozzle_maps.size());
|
||||
int filament_count = 0;
|
||||
for (const auto &layer_map : layer_filament_nozzle_maps)
|
||||
filament_count = std::max(filament_count, static_cast<int>(layer_map.size()));
|
||||
|
||||
auto layer_uses_filament = [](const std::vector<unsigned int> &filaments, int filament_id) {
|
||||
return std::find(filaments.begin(), filaments.end(), static_cast<unsigned int>(filament_id)) != filaments.end();
|
||||
};
|
||||
|
||||
std::vector<int> last_used_nozzle(filament_count, -1);
|
||||
std::unordered_map<int, int> first_used_nozzle;
|
||||
std::unordered_map<int, int> first_used_layer;
|
||||
|
||||
// Forward pass: layers that extrude a filament define its nozzle; layers that don't inherit
|
||||
// the nozzle it last used (carry-forward), remembering the first-ever nozzle for the back-fill.
|
||||
for (int layer_id = 0; layer_id < total_layers; ++layer_id) {
|
||||
auto &layer_map = layer_filament_nozzle_maps[layer_id];
|
||||
const auto &used = layer_id < static_cast<int>(layer_filaments.size()) ? layer_filaments[layer_id] : std::vector<unsigned int>();
|
||||
|
||||
for (int filament_id = 0; filament_id < static_cast<int>(layer_map.size()); ++filament_id) {
|
||||
if (layer_uses_filament(used, filament_id)) {
|
||||
last_used_nozzle[filament_id] = layer_map[filament_id];
|
||||
if (first_used_nozzle.count(filament_id) == 0) {
|
||||
first_used_nozzle[filament_id] = layer_map[filament_id];
|
||||
first_used_layer[filament_id] = layer_id;
|
||||
}
|
||||
} else if (last_used_nozzle[filament_id] >= 0) {
|
||||
layer_map[filament_id] = last_used_nozzle[filament_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Back-fill pass: layers before a filament's first use inherit the first nozzle it ever uses.
|
||||
for (int layer_id = 0; layer_id < total_layers; ++layer_id) {
|
||||
auto &layer_map = layer_filament_nozzle_maps[layer_id];
|
||||
for (int filament_id = 0; filament_id < static_cast<int>(layer_map.size()); ++filament_id) {
|
||||
if (first_used_layer.count(filament_id) != 0 && layer_id < first_used_layer[filament_id])
|
||||
layer_map[filament_id] = first_used_nozzle[filament_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== LayeredNozzleGroupResult ====================
|
||||
static bool has_filament_mapped_to_multiple_nozzles(const std::vector<std::vector<int>> &layer_filament_nozzle_maps,
|
||||
const std::vector<unsigned int> &used_filaments)
|
||||
|
||||
Reference in New Issue
Block a user