diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index bfd70bdff..2c1d8f6b6 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -22,9 +22,74 @@ namespace Slic3r { const static bool g_wipe_into_objects = false; + +// Shortest hamilton path problem +static std::vector solve_extruder_order(const std::vector>& wipe_volumes, std::vector all_extruders, unsigned int start_extruder_id) +{ + auto start_iter = std::find(all_extruders.begin(), all_extruders.end(), start_extruder_id); + bool add_start_extruder_flag = false; + if (start_iter == all_extruders.end()) + all_extruders.insert(all_extruders.begin(), start_extruder_id), add_start_extruder_flag = true; + else + std::swap(*all_extruders.begin(), *start_iter); + + unsigned int iterations = (1 << all_extruders.size()); + unsigned int final_state = iterations - 1; + std::vector>cache(iterations, std::vector(all_extruders.size(),0x7fffffff)); + std::vector>prev(iterations, std::vector(all_extruders.size(), -1)); + cache[1][0] = 0.; + for (unsigned int state = 0; state < iterations; ++state) { + if (state & 1) { + for (unsigned int target = 0; target < all_extruders.size(); ++target) { + if (state >> target & 1) { + for (unsigned int mid_point = 0; mid_point < all_extruders.size(); ++mid_point) { + if(state>>mid_point&1){ + auto tmp = cache[state - (1 << target)][mid_point] + wipe_volumes[all_extruders[mid_point]][all_extruders[target]]; + if (cache[state][target] >tmp) { + cache[state][target] = tmp; + prev[state][target] = mid_point; + } + } + } + } + } + } + } + + //get res + float cost = std::numeric_limits::max(); + int final_dst =0; + for (unsigned int dst = 0; dst < all_extruders.size(); ++dst) { + if (all_extruders[dst] != start_extruder_id && cost > cache[final_state][dst]) { + cost = cache[final_state][dst]; + final_dst = dst; + } + } + + std::vectorpath; + unsigned int curr_state = final_state; + int curr_point = final_dst; + while (curr_point != -1) { + path.emplace_back(all_extruders[curr_point]); + auto mid_point = prev[curr_state][curr_point]; + curr_state -= (1 << curr_point); + curr_point = mid_point; + }; + + if (add_start_extruder_flag) + path.pop_back(); + + std::reverse(path.begin(), path.end()); + return path; +} + std::vector get_extruders_order(const std::vector> &wipe_volumes, std::vector all_extruders, unsigned int start_extruder_id) { - if (all_extruders.size() > 1) { +#define USE_DP_OPTIMIZE +#ifdef USE_DP_OPTIMIZE + return solve_extruder_order(wipe_volumes, all_extruders, start_extruder_id); +#else +if (all_extruders.size() > 1) { int begin_index = 0; auto iter = std::find(all_extruders.begin(), all_extruders.end(), start_extruder_id); if (iter != all_extruders.end()) { @@ -53,6 +118,8 @@ std::vector get_extruders_order(const std::vector(flush_matrix.begin() + i * number_of_extruders, flush_matrix.begin() + (i + 1) * number_of_extruders)); + auto extruders_to_hash_key = [](const std::vector& extruders, unsigned int initial_extruder_id)->uint32_t { + uint32_t hash_key = 0; + // high 16 bit define initial extruder ,low 16 bit define extruder set + hash_key |= (1 << (16 + initial_extruder_id)); + for (auto item : extruders) + hash_key |= (1 << item); + return hash_key; + }; + + unsigned int current_extruder_id = -1; for (int i = 0; i < m_layer_tools.size(); ++i) { LayerTools& lt = m_layer_tools[i]; if (lt.extruders.empty()) continue; - // todo: The algorithm complexity is too high(o(n2)), currently only 8 colors are supported - if (i != 0 && lt.extruders.size() <= 8) { - lt.extruders = get_extruders_order(wipe_volumes, lt.extruders, current_extruder_id); + // The algorithm complexity is O(n2*2^n) + if (i != 0) { + auto hash_key = extruders_to_hash_key(lt.extruders, current_extruder_id); + auto iter = m_tool_order_cache.find(hash_key); + if (iter == m_tool_order_cache.end()) { + lt.extruders = get_extruders_order(wipe_volumes, lt.extruders, current_extruder_id); + std::vector hash_val; + hash_val.reserve(lt.extruders.size()); + for (auto item : lt.extruders) + hash_val.emplace_back(static_cast(item)); + m_tool_order_cache[hash_key] = hash_val; + } + else { + std::vectorextruder_order; + extruder_order.reserve(iter->second.size()); + for (auto item : iter->second) + extruder_order.emplace_back(static_cast(item)); + lt.extruders = std::move(extruder_order); + } } current_extruder_id = lt.extruders.back(); } diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index 728fa4e74..8c0ecdd4c 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -156,7 +156,9 @@ public: // (print->config().print_sequence == PrintSequence::ByObject is false). ToolOrdering(const Print& print, unsigned int first_extruder, bool prime_multi_material = false); - void clear() { m_layer_tools.clear(); } + void clear() { + m_layer_tools.clear(); m_tool_order_cache.clear(); + } // Only valid for non-sequential print: // Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools. @@ -207,7 +209,7 @@ private: unsigned int m_last_printing_extruder = (unsigned int)-1; // All extruders, which extrude some material over m_layer_tools. std::vector m_all_printing_extruders; - + std::unordered_map> m_tool_order_cache; const PrintConfig* m_print_config_ptr = nullptr; const PrintObject* m_print_object_ptr = nullptr; };