OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GroupMinCostFlowSolver Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/ToolOrderUtils.hpp>

Collaboration diagram for Slic3r::GroupMinCostFlowSolver:

Public Member Functions

 GroupMinCostFlowSolver (const std::vector< FlushMatrix > &matrix_, const std::vector< int > &u_nodes, const std::vector< int > &v_nodes, const std::vector< int > &v_nodes_group, const std::unordered_map< int, std::vector< int > > &uv_link_limits={}, const std::unordered_map< int, std::vector< int > > &uv_unlink_limits={})
std::vector< int > solve ()
 ~GroupMinCostFlowSolver ()

Private Member Functions

void build_graph ()
int get_flush_cost (int l_idx, int r_idx)

Private Attributes

std::unique_ptr< MinCostMaxFlow > m_solver
std::vector< FlushMatrix > flush_matrix
std::vector< int > l_nodes
std::vector< int > r_nodes
std::vector< int > r_nodes_group
std::unordered_map< int, std::vector< int > > m_uv_link_limits
std::unordered_map< int, std::vector< int > > m_uv_unlink_limits
int num_groups = 0

Detailed Description

Constructor & Destructor Documentation

◆ GroupMinCostFlowSolver()

Slic3r::GroupMinCostFlowSolver::GroupMinCostFlowSolver ( const std::vector< FlushMatrix > & matrix_,
const std::vector< int > & u_nodes,
const std::vector< int > & v_nodes,
const std::vector< int > & v_nodes_group,
const std::unordered_map< int, std::vector< int > > & uv_link_limits = {},
const std::unordered_map< int, std::vector< int > > & uv_unlink_limits = {} )
562 {
563 flush_matrix = matrix_;
564 l_nodes = u_nodes;
565 r_nodes = v_nodes;
566 r_nodes_group = v_nodes_group;
567 m_uv_link_limits = uv_link_limits;
568 m_uv_unlink_limits = uv_unlink_limits;
569 num_groups = *std::max_element(r_nodes_group.begin(), r_nodes_group.end()) + 1;
570
571 m_solver = std::make_unique<MinCostMaxFlow>();
572 build_graph();
573 }
std::unordered_map< int, std::vector< int > > m_uv_link_limits
Definition ToolOrderUtils.hpp:149
int num_groups
Definition ToolOrderUtils.hpp:151
void build_graph()
Definition ToolOrderUtils.cpp:583
std::vector< int > l_nodes
Definition ToolOrderUtils.hpp:146
std::unordered_map< int, std::vector< int > > m_uv_unlink_limits
Definition ToolOrderUtils.hpp:150
std::unique_ptr< MinCostMaxFlow > m_solver
Definition ToolOrderUtils.hpp:144
std::vector< int > r_nodes
Definition ToolOrderUtils.hpp:147
std::vector< int > r_nodes_group
Definition ToolOrderUtils.hpp:148
std::vector< FlushMatrix > flush_matrix
Definition ToolOrderUtils.hpp:145

References build_graph(), flush_matrix, l_nodes, m_solver, m_uv_link_limits, m_uv_unlink_limits, num_groups, r_nodes, and r_nodes_group.

Here is the call graph for this function:

◆ ~GroupMinCostFlowSolver()

Slic3r::GroupMinCostFlowSolver::~GroupMinCostFlowSolver ( )
default

Member Function Documentation

◆ build_graph()

void Slic3r::GroupMinCostFlowSolver::build_graph ( )
private
584 {
585 const int L = (int)l_nodes.size();
586 const int R = (int)r_nodes.size();
587 const int G = num_groups;
588
589 m_solver->l_nodes = l_nodes;
590 m_solver->r_nodes = r_nodes;
591 m_solver->total_nodes = L + R + G + 2;
592 m_solver->source_id = L + R + G;
593 m_solver->sink_id = L + R + G + 1;
594 m_solver->adj.resize(m_solver->total_nodes);
595
596 int max_flush = 0;
597 for (const auto &mat : flush_matrix)
598 for (const auto &row : mat)
599 for (float v : row)
600 max_flush = std::max(max_flush, (int)v);
601 int bonus = max_flush * L + 1;
602
603 // source -> l_i
604 for (int i = 0; i < L; ++i)
605 m_solver->add_edge(m_solver->source_id, i, 1, 0);
606
607 // l_i -> r_j (with link/unlink limits)
608 for (int i = 0; i < L; ++i) {
609 if (auto it = m_uv_link_limits.find(i); it != m_uv_link_limits.end()) {
610 for (int j : it->second)
611 m_solver->add_edge(i, L + j, 1, get_flush_cost(i, j));
612 continue;
613 }
614
615 std::optional<std::vector<int>> unlink_limits;
616 if (auto it = m_uv_unlink_limits.find(i); it != m_uv_unlink_limits.end())
617 unlink_limits = it->second;
618
619 for (int j = 0; j < R; ++j) {
620 if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end())
621 continue;
622 m_solver->add_edge(i, L + j, 1, get_flush_cost(i, j));
623 }
624 }
625
626 // r_j -> group_g
627 // Compute per-nozzle incoming edge count as capacity upper bound.
628 // When unlink_limits restrict multiple filaments to the same nozzle,
629 // capacity=1 would block valid assignments. Using the actual in-degree
630 // allows the necessary flow while still preserving nozzle-level balance
631 // (a nozzle with fewer forced filaments keeps a tighter cap).
632 // The first unit carries a small nozzle-bonus to encourage spreading
633 // filaments across distinct nozzles within the same group.
634 int nozzle_bonus = max_flush + 1;
635 std::vector<int> r_in_degree(R, 0);
636 for (int i = 0; i < L; ++i) {
637 if (auto it = m_uv_link_limits.find(i); it != m_uv_link_limits.end()) {
638 for (int j : it->second)
639 r_in_degree[j]++;
640 continue;
641 }
642 std::optional<std::vector<int>> unlink_limits;
643 if (auto it = m_uv_unlink_limits.find(i); it != m_uv_unlink_limits.end())
644 unlink_limits = it->second;
645 for (int j = 0; j < R; ++j) {
646 if (unlink_limits.has_value() && std::find(unlink_limits->begin(), unlink_limits->end(), j) != unlink_limits->end())
647 continue;
648 r_in_degree[j]++;
649 }
650 }
651
652 for (int j = 0; j < R; ++j) {
653 int g = r_nodes_group[j];
654 int cap = std::max(r_in_degree[j], 1);
655 // First unit gets -nozzle_bonus to prefer using distinct nozzles
656 m_solver->add_edge(L + j, L + R + g, 1, -nozzle_bonus);
657 if (cap > 1)
658 m_solver->add_edge(L + j, L + R + g, cap - 1, 0);
659 }
660
661 // group_g -> sink (split: first unit gets -bonus, rest gets 0)
662 // bonus >> nozzle_bonus, so group coverage always takes priority
663 for (int g = 0; g < G; ++g) {
664 m_solver->add_edge(L + R + g, m_solver->sink_id, 1, -bonus);
665 if (L > 1)
666 m_solver->add_edge(L + R + g, m_solver->sink_id, L - 1, 0);
667 }
668 }
#define L(s)
Definition ExtrusionEntity.cpp:25
int get_flush_cost(int l_idx, int r_idx)
Definition ToolOrderUtils.cpp:575

References flush_matrix, get_flush_cost(), L, l_nodes, m_solver, m_uv_link_limits, m_uv_unlink_limits, num_groups, r_nodes, and r_nodes_group.

Referenced by GroupMinCostFlowSolver().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_flush_cost()

int Slic3r::GroupMinCostFlowSolver::get_flush_cost ( int l_idx,
int r_idx )
private
576 {
577 if (r_nodes[r_idx] == -1)
578 return 0;
579 int group_id = r_nodes_group[r_idx];
580 return (int)flush_matrix[group_id][l_nodes[l_idx]][r_nodes[r_idx]];
581 }
uint32_t group_id(std::vector< Bridge > &bridges, uint32_t src_id)
Definition LayerRegion.cpp:214

References flush_matrix, Slic3r::group_id(), l_nodes, r_nodes, and r_nodes_group.

Referenced by build_graph().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ solve()

std::vector< int > Slic3r::GroupMinCostFlowSolver::solve ( )
671 {
672 return m_solver->solve();
673 }

References m_solver.

Referenced by Slic3r::plan_filament_nozzle_mapping_and_order().

Here is the caller graph for this function:

Member Data Documentation

◆ flush_matrix

std::vector<FlushMatrix> Slic3r::GroupMinCostFlowSolver::flush_matrix
private

◆ l_nodes

std::vector<int> Slic3r::GroupMinCostFlowSolver::l_nodes
private

◆ m_solver

std::unique_ptr<MinCostMaxFlow> Slic3r::GroupMinCostFlowSolver::m_solver
private

◆ m_uv_link_limits

std::unordered_map<int, std::vector<int> > Slic3r::GroupMinCostFlowSolver::m_uv_link_limits
private

◆ m_uv_unlink_limits

std::unordered_map<int, std::vector<int> > Slic3r::GroupMinCostFlowSolver::m_uv_unlink_limits
private

◆ num_groups

int Slic3r::GroupMinCostFlowSolver::num_groups = 0
private

◆ r_nodes

std::vector<int> Slic3r::GroupMinCostFlowSolver::r_nodes
private

◆ r_nodes_group

std::vector<int> Slic3r::GroupMinCostFlowSolver::r_nodes_group
private

The documentation for this class was generated from the following files: