Cyclic ordering (#13578)

Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
This commit is contained in:
Maksym Pyrozhok
2026-07-28 01:52:29 +03:00
committed by GitHub
parent 47ccca7f72
commit ef7bfeda9c
11 changed files with 897 additions and 11 deletions

View File

@@ -14,6 +14,7 @@
#include "GCode/Thumbnails.hpp"
#include "GCode/WipeTower.hpp"
#include "ShortestPath.hpp"
#include "GCode/OrderingStrategies.hpp"
#include "Print.hpp"
#include "Utils.hpp"
#include "ClipperUtils.hpp"
@@ -2804,6 +2805,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
m_role_based_fan_marker_layer.fill(-1);
m_fan_mover.release();
m_ordering_cache.clear();
m_writer.set_is_bbl_machine(is_bbl_printers);
@@ -3124,11 +3126,19 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
// In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
// Therefore initialize the printing extruders from there.
this->set_extruders(tool_ordering.all_extruders());
print_object_instances_ordering =
print_object_instances_ordering =
// By default, order object instances using a nearest neighbor search.
print.config().print_order == PrintOrder::Default ? chain_print_object_instances(print)
(print.config().print_order == PrintOrder::Default ? chain_print_object_instances(print)
// Snake: serpentine row traversal + 2-opt
: (print.config().print_order == PrintOrder::Snake ? chain_print_object_instances_snake(print)
// Best of all: run every strategy, pick the shortest total path
: (print.config().print_order == PrintOrder::BestOfStrategies ? chain_print_object_instances_best_of(print)
// Otherwise same order as the object list
: sort_object_instances_by_model_order(print);
: sort_object_instances_by_model_order(print))));
}
if (initial_extruder_id == (unsigned int)-1) {
// Nothing to print!
@@ -5977,7 +5987,29 @@ LayerResult GCode::process_layer(
print_objects.push_back(print.get_object(obj_idx));
}
std::vector<const PrintInstance *> new_ordering = chain_print_object_instances(print_objects, &wt_pos);
// Build cache key from sorted object IDs.
std::vector<ObjectID> obj_ids;
for (const PrintObject* po : print_objects)
obj_ids.emplace_back(po->id());
std::sort(obj_ids.begin(), obj_ids.end());
// Check cache: reuse ordering if filament + object set unchanged.
auto &cache_entry = m_ordering_cache[filament_id];
bool cache_hit = (cache_entry.first == obj_ids);
if (!cache_hit) {
// Compute fresh ordering and store in cache.
cache_entry.first = obj_ids;
cache_entry.second =
print.config().print_order == PrintOrder::Snake
? chain_print_object_instances_snake(print_objects, &wt_pos)
: (print.config().print_order == PrintOrder::BestOfStrategies
? chain_print_object_instances_best_of(print_objects, &wt_pos)
: chain_print_object_instances(print_objects, &wt_pos));
}
// Reverse a local copy; keep cached value intact for reuse.
std::vector<const PrintInstance *> new_ordering = cache_entry.second;
std::reverse(new_ordering.begin(), new_ordering.end());
if (print.config().print_sequence == PrintSequence::ByObject) {