Merge branch 'lh_multi_material_segmentation_fix'

This commit is contained in:
Lukáš Hejl 2021-06-16 06:06:07 +02:00
commit ccb53f71b6
13 changed files with 259 additions and 238 deletions

View File

@ -185,7 +185,8 @@ static bool vertex_equal_to_point(const Voronoi::VD::vertex_type &vertex, const
ulp_cmp(vertex.y(), double(ipt.y()), ULPS) == ulp_cmp_type::EQUAL; ulp_cmp(vertex.y(), double(ipt.y()), ULPS) == ulp_cmp_type::EQUAL;
} }
static inline bool vertex_equal_to_point(const Voronoi::VD::vertex_type *vertex, const Point &ipt) { static inline bool vertex_equal_to_point(const Voronoi::VD::vertex_type *vertex, const Point &ipt)
{
return vertex_equal_to_point(*vertex, ipt); return vertex_equal_to_point(*vertex, ipt);
} }
@ -235,6 +236,10 @@ static std::vector<ColoredLine> colorize_line(const Line & line_to_
std::vector<PaintedLine> filtered_lines; std::vector<PaintedLine> filtered_lines;
filtered_lines.emplace_back(internal_painted.front()); filtered_lines.emplace_back(internal_painted.front());
for (size_t line_idx = 1; line_idx < internal_painted.size(); ++line_idx) { for (size_t line_idx = 1; line_idx < internal_painted.size(); ++line_idx) {
// line_to_process is already all colored. Skip another possible duplicate coloring.
if(filtered_lines.back().projected_line.b == line_to_process.b)
break;
PaintedLine &prev = filtered_lines.back(); PaintedLine &prev = filtered_lines.back();
PaintedLine &curr = internal_painted[line_idx]; PaintedLine &curr = internal_painted[line_idx];
@ -525,7 +530,7 @@ struct MMU_Graph
nodes[to_idx].remove_edge(from_idx); nodes[to_idx].remove_edge(from_idx);
} }
size_t get_global_index(const size_t poly_idx, const size_t point_idx) const { return polygon_idx_offset[poly_idx] + point_idx; } [[nodiscard]] size_t get_global_index(const size_t poly_idx, const size_t point_idx) const { return polygon_idx_offset[poly_idx] + point_idx; }
void append_edge(const size_t &from_idx, const size_t &to_idx, int color = -1, ARC_TYPE type = ARC_TYPE::NON_BORDER) void append_edge(const size_t &from_idx, const size_t &to_idx, int color = -1, ARC_TYPE type = ARC_TYPE::NON_BORDER)
{ {
@ -546,7 +551,7 @@ struct MMU_Graph
// Ignoring arcs in the opposite direction // Ignoring arcs in the opposite direction
MMU_Graph::Arc get_arc(size_t idx) { return this->arcs[idx * 2]; } MMU_Graph::Arc get_arc(size_t idx) { return this->arcs[idx * 2]; }
size_t nodes_count() const { return this->nodes.size(); } [[nodiscard]] size_t nodes_count() const { return this->nodes.size(); }
void remove_nodes_with_one_arc() void remove_nodes_with_one_arc()
{ {
@ -602,12 +607,12 @@ struct MMU_Graph
return vertex->color() < this->all_border_points; return vertex->color() < this->all_border_points;
} }
inline bool is_edge_attach_to_contour(const voronoi_diagram<double>::const_edge_iterator &edge_iterator) const [[nodiscard]] inline bool is_edge_attach_to_contour(const voronoi_diagram<double>::const_edge_iterator &edge_iterator) const
{ {
return this->is_vertex_on_contour(edge_iterator->vertex0()) || this->is_vertex_on_contour(edge_iterator->vertex1()); return this->is_vertex_on_contour(edge_iterator->vertex0()) || this->is_vertex_on_contour(edge_iterator->vertex1());
} }
inline bool is_edge_connecting_two_contour_vertices(const voronoi_diagram<double>::const_edge_iterator &edge_iterator) const [[nodiscard]] inline bool is_edge_connecting_two_contour_vertices(const voronoi_diagram<double>::const_edge_iterator &edge_iterator) const
{ {
return this->is_vertex_on_contour(edge_iterator->vertex0()) && this->is_vertex_on_contour(edge_iterator->vertex1()); return this->is_vertex_on_contour(edge_iterator->vertex0()) && this->is_vertex_on_contour(edge_iterator->vertex1());
} }
@ -1130,19 +1135,20 @@ static void cut_segmented_layers(const std::vector<ExPolygons>
const float cut_width, const float cut_width,
const std::function<void()> &throw_on_cancel_callback) const std::function<void()> &throw_on_cancel_callback)
{ {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&](const tbb::blocked_range<size_t>& range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),[&](const tbb::blocked_range<size_t>& range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
std::vector<std::pair<ExPolygon, size_t>> segmented_regions_cuts; std::vector<std::pair<ExPolygon, size_t>> segmented_regions_cuts;
for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) { for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) {
ExPolygons cut_colored_expoly = diff_ex(colored_expoly.first, offset_ex(input_expolygons[layer_idx], cut_width)); ExPolygons cut_colored_expoly = diff_ex(colored_expoly.first, offset_ex(input_expolygons[layer_idx], cut_width));
for (const ExPolygon &expoly : cut_colored_expoly) { for (ExPolygon &expoly : cut_colored_expoly)
segmented_regions_cuts.emplace_back(expoly, colored_expoly.second); segmented_regions_cuts.emplace_back(std::move(expoly), colored_expoly.second);
}
} }
segmented_regions[layer_idx] = segmented_regions_cuts; segmented_regions[layer_idx] = std::move(segmented_regions_cuts);
} }
}); // end of parallel_for }); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - cutting segmented layers in parallel - end";
} }
// Returns MMU segmentation of top and bottom layers based on painting in MMU segmentation gizmo // Returns MMU segmentation of top and bottom layers based on painting in MMU segmentation gizmo
@ -1154,6 +1160,8 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
const ConstLayerPtrsAdaptor layers = print_object.layers(); const ConstLayerPtrsAdaptor layers = print_object.layers();
std::vector<std::vector<ExPolygons>> triangles_by_color(num_extruders); std::vector<std::vector<ExPolygons>> triangles_by_color(num_extruders);
triangles_by_color.assign(num_extruders, std::vector<ExPolygons>(layers.size())); triangles_by_color.assign(num_extruders, std::vector<ExPolygons>(layers.size()));
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - begin";
for (const ModelVolume *mv : print_object.model_object()->volumes) { for (const ModelVolume *mv : print_object.model_object()->volumes) {
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) { for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
@ -1203,6 +1211,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
} }
} }
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - end";
auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float { auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float {
auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(), auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(),
@ -1272,8 +1281,8 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
triangles_by_color_bottom.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size())); triangles_by_color_bottom.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size()));
triangles_by_color_top.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size())); triangles_by_color_top.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size()));
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - begin";
for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) { for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of top layer: " << layer_idx;
float extrusion_width = scale_(get_extrusion_width(layer_idx)); float extrusion_width = scale_(get_extrusion_width(layer_idx));
int top_solid_layers = get_top_solid_layers(layer_idx); int top_solid_layers = get_top_solid_layers(layer_idx);
ExPolygons top_expolygon = top_layers[layer_idx]; ExPolygons top_expolygon = top_layers[layer_idx];
@ -1306,9 +1315,10 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
} }
} }
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - end";
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - begin";
for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) { for (size_t layer_idx = 0; layer_idx < input_expolygons.size(); ++layer_idx) {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of bottom layer: " << layer_idx;
float extrusion_width = scale_(get_extrusion_width(layer_idx)); float extrusion_width = scale_(get_extrusion_width(layer_idx));
int bottom_solid_layers = get_bottom_solid_layers(layer_idx); int bottom_solid_layers = get_bottom_solid_layers(layer_idx);
const ExPolygons &bottom_expolygon = bottom_layers[layer_idx]; const ExPolygons &bottom_expolygon = bottom_layers[layer_idx];
@ -1340,6 +1350,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
} }
} }
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - end";
std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders); std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders);
triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size())); triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(input_expolygons.size()));
@ -1369,23 +1380,27 @@ static std::vector<std::vector<std::pair<ExPolygon, size_t>>> merge_segmented_la
{ {
std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged(segmented_regions.size()); std::vector<std::vector<std::pair<ExPolygon, size_t>>> segmented_regions_merged(segmented_regions.size());
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging region: " << layer_idx;
for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) { for (const std::pair<ExPolygon, size_t> &colored_expoly : segmented_regions[layer_idx]) {
throw_on_cancel_callback(); throw_on_cancel_callback();
// Zero is the default color of the volume.
if(colored_expoly.second == 0)
continue;
ExPolygons cut_colored_expoly = {colored_expoly.first}; ExPolygons cut_colored_expoly = {colored_expoly.first};
for (const std::vector<ExPolygons> &top_and_bottom_layer : top_and_bottom_layers) for (const std::vector<ExPolygons> &top_and_bottom_layer : top_and_bottom_layers)
cut_colored_expoly = diff_ex(cut_colored_expoly, top_and_bottom_layer[layer_idx]); cut_colored_expoly = diff_ex(cut_colored_expoly, top_and_bottom_layer[layer_idx]);
for (ExPolygon &ex_poly : cut_colored_expoly) for (ExPolygon &ex_poly : cut_colored_expoly)
segmented_regions_merged[layer_idx].emplace_back(std::move(ex_poly), colored_expoly.second); segmented_regions_merged[layer_idx].emplace_back(std::move(ex_poly), colored_expoly.second - 1);
} }
for (size_t color_idx = 0; color_idx < top_and_bottom_layers.size(); ++color_idx) for (size_t color_idx = 1; color_idx < top_and_bottom_layers.size(); ++color_idx)
for (ExPolygon &expoly : top_and_bottom_layers[color_idx][layer_idx]) for (ExPolygon &expoly : top_and_bottom_layers[color_idx][layer_idx])
segmented_regions_merged[layer_idx].emplace_back(std::move(expoly), color_idx); segmented_regions_merged[layer_idx].emplace_back(std::move(expoly), color_idx - 1);
} }
}); // end of parallel_for }); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - merging segmented layers in parallel - end";
return segmented_regions_merged; return segmented_regions_merged;
} }
@ -1402,13 +1417,14 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
throw_on_cancel_callback(); throw_on_cancel_callback();
// Merge all regions and remove small holes // Merge all regions and remove small holes
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
ExPolygons ex_polygons; ExPolygons ex_polygons;
for (LayerRegion *region : layers[layer_idx]->regions()) for (LayerRegion *region : layers[layer_idx]->regions())
for (const Surface &surface : region->slices.surfaces) for (const Surface &surface : region->slices.surfaces)
Slic3r::append(ex_polygons, offset_ex(surface.expolygon, float(SCALED_EPSILON))); Slic3r::append(ex_polygons, offset_ex(surface.expolygon, float(10 * SCALED_EPSILON)));
// All expolygons are expanded by SCALED_EPSILON, merged, and then shrunk again by SCALED_EPSILON // All expolygons are expanded by SCALED_EPSILON, merged, and then shrunk again by SCALED_EPSILON
// to ensure that very close polygons will be merged. // to ensure that very close polygons will be merged.
ex_polygons = union_ex(ex_polygons); ex_polygons = union_ex(ex_polygons);
@ -1421,19 +1437,22 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
// Such close points sometimes caused that the Voronoi diagram has self-intersecting edges around these vertices. // Such close points sometimes caused that the Voronoi diagram has self-intersecting edges around these vertices.
// This consequently leads to issues with the extraction of colored segments by function extract_colored_segments. // This consequently leads to issues with the extraction of colored segments by function extract_colored_segments.
// Calling expolygons_simplify fixed these issues. // Calling expolygons_simplify fixed these issues.
input_expolygons[layer_idx] = simplify_polygons_ex(to_polygons(expolygons_simplify(offset_ex(ex_polygons, float(-SCALED_EPSILON)), SCALED_EPSILON))); input_expolygons[layer_idx] = simplify_polygons_ex(to_polygons(expolygons_simplify(offset_ex(ex_polygons, float(-10 * SCALED_EPSILON)), 5 * SCALED_EPSILON)));
input_polygons[layer_idx] = to_polygons(input_expolygons[layer_idx]); input_polygons[layer_idx] = to_polygons(input_expolygons[layer_idx]);
} }
}); // end of parallel_for }); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - end";
for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
BoundingBox bbox(get_extents(input_expolygons[layer_idx])); BoundingBox bbox(get_extents(input_expolygons[layer_idx]));
bbox.offset(SCALED_EPSILON); // Projected triangles may slightly exceed the input polygons.
bbox.offset(20 * SCALED_EPSILON);
edge_grids[layer_idx].set_bbox(bbox); edge_grids[layer_idx].set_bbox(bbox);
edge_grids[layer_idx].create(input_expolygons[layer_idx], coord_t(scale_(10.))); edge_grids[layer_idx].create(input_expolygons[layer_idx], coord_t(scale_(10.)));
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - begin";
for (const ModelVolume *mv : print_object.model_object()->volumes) { for (const ModelVolume *mv : print_object.model_object()->volumes) {
const size_t num_extruders = print_object.print()->config().nozzle_diameter.size(); const size_t num_extruders = print_object.print()->config().nozzle_diameter.size();
for (size_t extruder_idx = 1; extruder_idx < num_extruders; ++extruder_idx) { for (size_t extruder_idx = 1; extruder_idx < num_extruders; ++extruder_idx) {
@ -1500,20 +1519,23 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
} }
} }
} }
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end";
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: "
<< std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector<PaintedLine> &pl) { return !pl.empty(); });
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - begin";
tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layers().size()), [&](const tbb::blocked_range<size_t> &range) { tbb::parallel_for(tbb::blocked_range<size_t>(0, print_object.layers().size()), [&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
throw_on_cancel_callback(); throw_on_cancel_callback();
// for(size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx) { auto comp = [&input_polygons, layer_idx](const PaintedLine &first, const PaintedLine &second) {
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation of layer: " << layer_idx; Point first_start_p = input_polygons[layer_idx][first.contour_idx][first.line_idx];
auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) {
Point first_start_p = *(edge_grids[layer_idx].contours()[first.contour_idx].begin() + first.line_idx);
return first.contour_idx < second.contour_idx || return first.contour_idx < second.contour_idx ||
(first.contour_idx == second.contour_idx && (first.contour_idx == second.contour_idx &&
(first.line_idx < second.line_idx || (first.line_idx < second.line_idx ||
(first.line_idx == second.line_idx && (first.line_idx == second.line_idx &&
Line(first_start_p, first.projected_line.a).length() < Line(first_start_p, second.projected_line.a).length()))); ((first.projected_line.a - first_start_p).cast<double>().squaredNorm() < (second.projected_line.a - first_start_p).cast<double>().squaredNorm() ||
((first.projected_line.a - first_start_p).cast<double>().squaredNorm() == (second.projected_line.a - first_start_p).cast<double>().squaredNorm() &&
(first.projected_line.b - first.projected_line.a).cast<double>().squaredNorm() < (second.projected_line.b - second.projected_line.a).cast<double>().squaredNorm())))));
}; };
std::sort(painted_lines[layer_idx].begin(), painted_lines[layer_idx].end(), comp); std::sort(painted_lines[layer_idx].begin(), painted_lines[layer_idx].end(), comp);
@ -1525,11 +1547,12 @@ std::vector<std::vector<std::pair<ExPolygon, size_t>>> multi_material_segmentati
remove_multiple_edges_in_vertices(graph, color_poly); remove_multiple_edges_in_vertices(graph, color_poly);
graph.remove_nodes_with_one_arc(); graph.remove_nodes_with_one_arc();
std::vector<std::pair<Polygon, size_t>> segmentation = extract_colored_segments(graph); std::vector<std::pair<Polygon, size_t>> segmentation = extract_colored_segments(graph);
for (const std::pair<Polygon, size_t> &region : segmentation) for (std::pair<Polygon, size_t> &region : segmentation)
segmented_regions[layer_idx].emplace_back(region); segmented_regions[layer_idx].emplace_back(std::move(region));
} }
} }
}); // end of parallel_for }); // end of parallel_for
BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - layers segmentation in parallel - end";
throw_on_cancel_callback(); throw_on_cancel_callback();
if (auto w = print_object.config().mmu_segmented_region_max_width; w > 0.f) { if (auto w = print_object.config().mmu_segmented_region_max_width; w > 0.f) {

View File

@ -12,7 +12,7 @@ namespace Slic3r {
#ifndef _NDEBUG #ifndef _NDEBUG
bool TriangleSelector::verify_triangle_midpoints(const Triangle &tr) const bool TriangleSelector::verify_triangle_midpoints(const Triangle &tr) const
{ {
for (int i = 0; i < 3; ++ i) { for (int i = 0; i < 3; ++ i) {
int v1 = tr.verts_idxs[i]; int v1 = tr.verts_idxs[i];
int v2 = tr.verts_idxs[next_idx_modulo(i, 3)]; int v2 = tr.verts_idxs[next_idx_modulo(i, 3)];
int vmid = this->triangle_midpoint(tr, v1, v2); int vmid = this->triangle_midpoint(tr, v1, v2);
@ -168,7 +168,7 @@ bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type,
for (int i = 0; i < 3; ++ i) for (int i = 0; i < 3; ++ i)
neighbors(i) = neighbors_src.neighbor[i]; neighbors(i) = neighbors_src.neighbor[i];
assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors));
if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting)) if (! select_triangle_recursive(facet_idx, neighbors, type, triangle_splitting))
return false; return false;
@ -249,11 +249,11 @@ int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int ver
assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj); assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj);
if (tr.number_of_split_sides() == 1) { if (tr.number_of_split_sides() == 1) {
return edge == next_idx_modulo(tr.special_side(), 3) ? return edge == next_idx_modulo(tr.special_side(), 3) ?
m_triangles[tr.children[0]].verts_idxs[2] : m_triangles[tr.children[0]].verts_idxs[2] :
this->triangle_midpoint(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj); this->triangle_midpoint(m_triangles[tr.children[edge == tr.special_side() ? 0 : 1]], vertexi, vertexj);
} else if (tr.number_of_split_sides() == 2) { } else if (tr.number_of_split_sides() == 2) {
return edge == next_idx_modulo(tr.special_side(), 3) ? return edge == next_idx_modulo(tr.special_side(), 3) ?
this->triangle_midpoint(m_triangles[tr.children[2]], vertexi, vertexj) : this->triangle_midpoint(m_triangles[tr.children[2]], vertexi, vertexj) :
edge == tr.special_side() ? edge == tr.special_side() ?
m_triangles[tr.children[0]].verts_idxs[1] : m_triangles[tr.children[0]].verts_idxs[1] :
@ -261,7 +261,7 @@ int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int ver
} else { } else {
assert(tr.number_of_split_sides() == 3); assert(tr.number_of_split_sides() == 3);
assert(tr.special_side() == 0); assert(tr.special_side() == 0);
return return
(edge == 0) ? m_triangles[tr.children[0]].verts_idxs[1] : (edge == 0) ? m_triangles[tr.children[0]].verts_idxs[1] :
(edge == 1) ? m_triangles[tr.children[1]].verts_idxs[2] : (edge == 1) ? m_triangles[tr.children[1]].verts_idxs[2] :
m_triangles[tr.children[2]].verts_idxs[2]; m_triangles[tr.children[2]].verts_idxs[2];
@ -282,7 +282,7 @@ int TriangleSelector::triangle_midpoint_or_allocate(int itriangle, int vertexi,
Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v); Vec3f c = 0.5f * (m_vertices[vertexi].v + m_vertices[vertexj].v);
#ifdef EXPENSIVE_DEBUG_CHECKS #ifdef EXPENSIVE_DEBUG_CHECKS
// Verify that the vertex is really a new one. // Verify that the vertex is really a new one.
auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [this, c](const Vertex &v) { auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [this, c](const Vertex &v) {
return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; }); return v.ref_cnt > 0 && (v.v - c).norm() < EPSILON; });
assert(it == m_vertices.end()); assert(it == m_vertices.end());
#endif // EXPENSIVE_DEBUG_CHECKS #endif // EXPENSIVE_DEBUG_CHECKS
@ -736,7 +736,7 @@ TriangleSelector::TriangleSelector(const TriangleMesh& mesh)
} }
void TriangleSelector::reset(const EnforcerBlockerType reset_state) void TriangleSelector::reset()
{ {
m_vertices.clear(); m_vertices.clear();
m_triangles.clear(); m_triangles.clear();
@ -749,10 +749,10 @@ void TriangleSelector::reset(const EnforcerBlockerType reset_state)
m_triangles.reserve(m_mesh->its.indices.size()); m_triangles.reserve(m_mesh->its.indices.size());
for (size_t i=0; i<m_mesh->its.indices.size(); ++i) { for (size_t i=0; i<m_mesh->its.indices.size(); ++i) {
const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i]; const stl_triangle_vertex_indices& ind = m_mesh->its.indices[i];
push_triangle(ind[0], ind[1], ind[2], i, reset_state); push_triangle(ind[0], ind[1], ind[2], i);
} }
m_orig_size_vertices = m_vertices.size(); m_orig_size_vertices = m_vertices.size();
m_orig_size_indices = m_triangles.size(); m_orig_size_indices = m_triangles.size();
} }
@ -930,8 +930,8 @@ std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> TriangleSelector:
// In case this is leaf, we better save information about its state. // In case this is leaf, we better save information about its state.
int n = int(tr.get_state()); int n = int(tr.get_state());
if (n >= 3) { if (n >= 3) {
assert(n <= 15); assert(n <= 16);
if (n <= 15) { if (n <= 16) {
// Store "11" plus 4 bits of (n-3). // Store "11" plus 4 bits of (n-3).
data.second.insert(data.second.end(), { true, true }); data.second.insert(data.second.end(), { true, true });
n -= 3; n -= 3;
@ -963,9 +963,9 @@ std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> TriangleSelector:
return out.data; return out.data;
} }
void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, const EnforcerBlockerType init_state) void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data)
{ {
reset(init_state); // dump any current state reset(); // dump any current state
// Vector to store all parents that have offsprings. // Vector to store all parents that have offsprings.
struct ProcessingInfo { struct ProcessingInfo {
@ -1058,7 +1058,7 @@ void TriangleSelector::deserialize(const std::pair<std::vector<std::pair<int, in
} }
} }
void TriangleSelector::seed_fill_unselect_all_triangles() void TriangleSelector::seed_fill_unselect_all_triangles()
{ {
for (Triangle &triangle : m_triangles) for (Triangle &triangle : m_triangles)
if (!triangle.is_split()) if (!triangle.is_split())

View File

@ -50,7 +50,7 @@ public:
void set_facet(int facet_idx, EnforcerBlockerType state); void set_facet(int facet_idx, EnforcerBlockerType state);
// Clear everything and make the tree empty. // Clear everything and make the tree empty.
void reset(const EnforcerBlockerType reset_state = EnforcerBlockerType{0}); void reset();
// Remove all unnecessary data. // Remove all unnecessary data.
void garbage_collect(); void garbage_collect();
@ -60,7 +60,7 @@ public:
std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> serialize() const; std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> serialize() const;
// Load serialized data. Assumes that correct mesh is loaded. // Load serialized data. Assumes that correct mesh is loaded.
void deserialize(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data, const EnforcerBlockerType init_state = EnforcerBlockerType{0}); void deserialize(const std::pair<std::vector<std::pair<int, int>>, std::vector<bool>> &data);
// For all triangles, remove the flag indicating that the triangle was selected by seed fill. // For all triangles, remove the flag indicating that the triangle was selected by seed fill.
void seed_fill_unselect_all_triangles(); void seed_fill_unselect_all_triangles();

View File

@ -1168,10 +1168,11 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
const GLGizmosManager& gm = get_gizmos_manager(); const GLGizmosManager& gm = get_gizmos_manager();
auto gizmo_type = gm.get_current_type(); auto gizmo_type = gm.get_current_type();
if ( (gizmo_type == GLGizmosManager::FdmSupports if ( (gizmo_type == GLGizmosManager::FdmSupports
|| gizmo_type == GLGizmosManager::Seam || gizmo_type == GLGizmosManager::Seam)
|| gizmo_type == GLGizmosManager::MmuSegmentation)
&& ! vol->is_modifier) && ! vol->is_modifier)
vol->force_neutral_color = true; vol->force_neutral_color = true;
else if (gizmo_type == GLGizmosManager::MmuSegmentation)
vol->is_active = false;
else else
vol->force_native_color = true; vol->force_native_color = true;
} }

View File

@ -2201,9 +2201,9 @@ void ObjectList::part_selection_changed()
if (type == itInfo) { if (type == itInfo) {
InfoItemType info_type = m_objects_model->GetInfoItemType(item); InfoItemType info_type = m_objects_model->GetInfoItemType(item);
if (info_type != InfoItemType::VariableLayerHeight) { if (info_type != InfoItemType::VariableLayerHeight) {
GLGizmosManager::EType gizmo_type = GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports :
info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam :
: GLGizmosManager::EType::Seam; GLGizmosManager::EType::MmuSegmentation;
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
if (gizmos_mgr.get_current_type() != gizmo_type) if (gizmos_mgr.get_current_type() != gizmo_type)
gizmos_mgr.open_gizmo(gizmo_type); gizmos_mgr.open_gizmo(gizmo_type);
@ -2333,6 +2333,7 @@ void ObjectList::update_info_items(size_t obj_idx)
for (InfoItemType type : {InfoItemType::CustomSupports, for (InfoItemType type : {InfoItemType::CustomSupports,
InfoItemType::CustomSeam, InfoItemType::CustomSeam,
InfoItemType::MmuSegmentation,
InfoItemType::VariableLayerHeight}) { InfoItemType::VariableLayerHeight}) {
wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type); wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type);
bool shows = item.IsOk(); bool shows = item.IsOk();
@ -2341,12 +2342,13 @@ void ObjectList::update_info_items(size_t obj_idx)
switch (type) { switch (type) {
case InfoItemType::CustomSupports : case InfoItemType::CustomSupports :
case InfoItemType::CustomSeam : case InfoItemType::CustomSeam :
case InfoItemType::MmuSegmentation :
should_show = printer_technology() == ptFFF should_show = printer_technology() == ptFFF
&& std::any_of(model_object->volumes.begin(), model_object->volumes.end(), && std::any_of(model_object->volumes.begin(), model_object->volumes.end(),
[type](const ModelVolume* mv) { [type](const ModelVolume *mv) {
return ! (type == InfoItemType::CustomSupports return !(type == InfoItemType::CustomSupports ? mv->supported_facets.empty() :
? mv->supported_facets.empty() type == InfoItemType::CustomSeam ? mv->seam_facets.empty() :
: mv->seam_facets.empty()); mv->mmu_segmentation_facets.empty());
}); });
break; break;

View File

@ -103,10 +103,10 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f); const float buttons_width = std::max(button_enforce_width, button_cancel_width) + m_imgui->scaled(0.5f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.; float total_text_max = 0.f;
for (const std::string& t : {"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
} }
caption_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
@ -124,7 +124,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
m_imgui->text(text); m_imgui->text(text);
}; };
for (const std::string& t : {"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text(""); m_imgui->text("");

View File

@ -7,6 +7,7 @@
#include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/BitmapCache.hpp" #include "slic3r/GUI/BitmapCache.hpp"
#include "slic3r/GUI/format.hpp" #include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
@ -32,15 +33,15 @@ bool GLGizmoMmuSegmentation::on_is_selectable() const
&& wxGetApp().get_mode() != comSimple && wxGetApp().extruders_edited_cnt() > 1); && wxGetApp().get_mode() != comSimple && wxGetApp().extruders_edited_cnt() > 1);
} }
static std::vector<std::array<uint8_t, 3>> get_extruders_colors() static std::vector<std::array<float, 4>> get_extruders_colors()
{ {
unsigned char rgb_color[3] = {}; unsigned char rgb_color[3] = {};
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::vector<std::array<uint8_t, 3>> colors_out(colors.size()); std::vector<std::array<float, 4>> colors_out(colors.size());
for (const std::string &color : colors) { for (const std::string &color : colors) {
Slic3r::GUI::BitmapCache::parse_color(color, rgb_color); Slic3r::GUI::BitmapCache::parse_color(color, rgb_color);
size_t color_idx = &color - &colors.front(); size_t color_idx = &color - &colors.front();
colors_out[color_idx] = {rgb_color[0], rgb_color[1], rgb_color[2]}; colors_out[color_idx] = {float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f};
} }
return colors_out; return colors_out;
@ -57,6 +58,20 @@ static std::vector<std::string> get_extruders_names()
return extruders_out; return extruders_out;
} }
static std::vector<int> get_extruder_id_for_volumes(const ModelObject &model_object)
{
std::vector<int> extruders_idx;
extruders_idx.reserve(model_object.volumes.size());
for (const ModelVolume *model_volume : model_object.volumes) {
if (!model_volume->is_model_part())
continue;
extruders_idx.emplace_back(model_volume->extruder_id());
}
return extruders_idx;
}
void GLGizmoMmuSegmentation::init_extruders_data() void GLGizmoMmuSegmentation::init_extruders_data()
{ {
m_original_extruders_names = get_extruders_names(); m_original_extruders_names = get_extruders_names();
@ -98,7 +113,7 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() const
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
render_triangles(selection); render_triangles(selection, false);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
render_cursor(); render_cursor();
@ -113,25 +128,31 @@ void GLGizmoMmuSegmentation::set_painter_gizmo_data(const Selection &selection)
if (m_state != On) if (m_state != On)
return; return;
int prev_extruders_count = int(m_original_extruders_colors.size()); ModelObject *model_object = m_c->selection_info()->model_object();
int prev_extruders_count = int(m_original_extruders_colors.size());
if (prev_extruders_count != wxGetApp().extruders_edited_cnt() || get_extruders_colors() != m_original_extruders_colors) { if (prev_extruders_count != wxGetApp().extruders_edited_cnt() || get_extruders_colors() != m_original_extruders_colors) {
this->init_extruders_data(); this->init_extruders_data();
// Reinitialize triangle selectors because of change of extruder count need also change the size of GLIndexedVertexArray // Reinitialize triangle selectors because of change of extruder count need also change the size of GLIndexedVertexArray
if (prev_extruders_count != wxGetApp().extruders_edited_cnt()) if (prev_extruders_count != wxGetApp().extruders_edited_cnt())
this->init_model_triangle_selectors(); this->init_model_triangle_selectors();
} else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_original_volumes_extruder_idxs) {
this->init_model_triangle_selectors();
} }
} }
static void render_extruders_combo(const std::string &label, static void render_extruders_combo(const std::string &label,
const std::vector<std::string> &extruders, const std::vector<std::string> &extruders,
const std::vector<std::array<uint8_t, 3>> &extruders_colors, const std::vector<std::array<float, 4>> &extruders_colors,
size_t &selection_idx) size_t &selection_idx)
{ {
assert(!extruders_colors.empty()); assert(!extruders_colors.empty());
assert(extruders_colors.size() == extruders_colors.size()); assert(extruders_colors.size() == extruders_colors.size());
size_t selection_out = selection_idx; auto convert_to_imu32 = [](const std::array<float, 4> &color) -> ImU32 {
return IM_COL32(uint8_t(color[0] * 255.f), uint8_t(color[1] * 255.f), uint8_t(color[2] * 255.f), uint8_t(color[3] * 255.f));
};
size_t selection_out = selection_idx;
// It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox. // It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox.
ImGui::BeginGroup(); ImGui::BeginGroup();
ImVec2 combo_pos = ImGui::GetCursorScreenPos(); ImVec2 combo_pos = ImGui::GetCursorScreenPos();
@ -146,8 +167,7 @@ static void render_extruders_combo(const std::string &la
ImGui::SameLine(); ImGui::SameLine();
ImGuiStyle &style = ImGui::GetStyle(); ImGuiStyle &style = ImGui::GetStyle();
float height = ImGui::GetTextLineHeight(); float height = ImGui::GetTextLineHeight();
ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), ImGui::GetWindowDrawList()->AddRectFilled(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), convert_to_imu32(extruders_colors[extruder_idx]));
IM_COL32(extruders_colors[extruder_idx][0], extruders_colors[extruder_idx][1], extruders_colors[extruder_idx][2], 255));
ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK); ImGui::GetWindowDrawList()->AddRect(start_position, ImVec2(start_position.x + height + height / 2, start_position.y + height), IM_COL32_BLACK);
ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y)); ImGui::SetCursorScreenPos(ImVec2(start_position.x + height + height / 2 + style.FramePadding.x, start_position.y));
@ -165,9 +185,7 @@ static void render_extruders_combo(const std::string &la
ImVec2 p = ImGui::GetCursorScreenPos(); ImVec2 p = ImGui::GetCursorScreenPos();
float height = ImGui::GetTextLineHeight(); float height = ImGui::GetTextLineHeight();
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + height + height / 2, p.y + height), convert_to_imu32(extruders_colors[selection_idx]));
IM_COL32(extruders_colors[selection_idx][0], extruders_colors[selection_idx][1],
extruders_colors[selection_idx][2], 255));
ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK); ImGui::GetWindowDrawList()->AddRect(p, ImVec2(p.x + height + height / 2, p.y + height), IM_COL32_BLACK);
ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y)); ImGui::SetCursorScreenPos(ImVec2(p.x + height + height / 2 + style.FramePadding.x, p.y));
@ -206,7 +224,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.; float total_text_max = 0.;
for (const std::string &t : {"first_color", "second_color", "remove"}) { for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
} }
@ -225,33 +243,33 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(text); m_imgui->text(text);
}; };
for (const std::string &t : {"first_color", "second_color", "remove"}) for (const auto &t : std::array<std::string, 3>{"first_color", "second_color", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text(""); m_imgui->text("");
ImGui::Separator(); ImGui::Separator();
const std::array<uint8_t, 3> &select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx];
const std::array<uint8_t, 3> &select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx];
m_imgui->text(m_desc.at("first_color")); m_imgui->text(m_desc.at("first_color"));
ImGui::SameLine(combo_label_width); ImGui::SameLine(combo_label_width);
ImGui::PushItemWidth(window_width - combo_label_width - color_button_width); ImGui::PushItemWidth(window_width - combo_label_width - color_button_width);
render_extruders_combo("##first_color_combo", m_original_extruders_names, m_original_extruders_colors, m_first_selected_extruder_idx); render_extruders_combo("##first_color_combo", m_original_extruders_names, m_original_extruders_colors, m_first_selected_extruder_idx);
ImGui::SameLine(); ImGui::SameLine();
ImVec4 first_color = ImVec4(float(select_first_color[0]) / 255.0f, float(select_first_color[1]) / 255.0f, float(select_first_color[2]) / 255.0f, 1.0f); const std::array<float, 4> &select_first_color = m_modified_extruders_colors[m_first_selected_extruder_idx];
ImVec4 second_color = ImVec4(float(select_second_color[0]) / 255.0f, float(select_second_color[1]) / 255.0f, float(select_second_color[2]) / 255.0f, 1.0f); ImVec4 first_color = ImVec4(select_first_color[0], select_first_color[1], select_first_color[2], select_first_color[3]);
if(ImGui::ColorEdit4("First color##color_picker", (float*)&first_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) if(ImGui::ColorEdit4("First color##color_picker", (float*)&first_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
m_modified_extruders_colors[m_first_selected_extruder_idx] = {uint8_t(first_color.x * 255.0f), uint8_t(first_color.y * 255.0f), uint8_t(first_color.z * 255.0f)}; m_modified_extruders_colors[m_first_selected_extruder_idx] = {first_color.x, first_color.y, first_color.z, first_color.w};
m_imgui->text(m_desc.at("second_color")); m_imgui->text(m_desc.at("second_color"));
ImGui::SameLine(combo_label_width); ImGui::SameLine(combo_label_width);
ImGui::PushItemWidth(window_width - combo_label_width - color_button_width); ImGui::PushItemWidth(window_width - combo_label_width - color_button_width);
render_extruders_combo("##second_color_combo", m_original_extruders_names, m_original_extruders_colors, m_second_selected_extruder_idx); render_extruders_combo("##second_color_combo", m_original_extruders_names, m_original_extruders_colors, m_second_selected_extruder_idx);
ImGui::SameLine(); ImGui::SameLine();
const std::array<float, 4> &select_second_color = m_modified_extruders_colors[m_second_selected_extruder_idx];
ImVec4 second_color = ImVec4(select_second_color[0], select_second_color[1], select_second_color[2], select_second_color[3]);
if(ImGui::ColorEdit4("Second color##color_picker", (float*)&second_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) if(ImGui::ColorEdit4("Second color##color_picker", (float*)&second_color, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel))
m_modified_extruders_colors[m_second_selected_extruder_idx] = {uint8_t(second_color.x * 255.0f), uint8_t(second_color.y * 255.0f), uint8_t(second_color.z * 255.0f)}; m_modified_extruders_colors[m_second_selected_extruder_idx] = {second_color.x, second_color.y, second_color.z, second_color.w};
ImGui::Separator(); ImGui::Separator();
@ -279,8 +297,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
for (ModelVolume *mv : mo->volumes) { for (ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) { if (mv->is_model_part()) {
++idx; ++idx;
size_t extruder_id = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->reset(EnforcerBlockerType(extruder_id));
} }
} }
@ -375,8 +392,11 @@ void GLGizmoMmuSegmentation::update_model_object() const
updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get()); updated |= mv->mmu_segmentation_facets.set(*m_triangle_selectors[idx].get());
} }
if (updated) if (updated) {
const ModelObjectPtrs &mos = wxGetApp().model().objects;
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
} }
void GLGizmoMmuSegmentation::init_model_triangle_selectors() void GLGizmoMmuSegmentation::init_model_triangle_selectors()
@ -391,10 +411,11 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors()
// This mesh does not account for the possible Z up SLA offset. // This mesh does not account for the possible Z up SLA offset.
const TriangleMesh *mesh = &mv->mesh(); const TriangleMesh *mesh = &mv->mesh();
size_t extruder_id = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0;
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorMmuGui>(*mesh, m_modified_extruders_colors)); m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorMmuGui>(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)]));
m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), EnforcerBlockerType(extruder_id)); m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data());
} }
m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo);
} }
void GLGizmoMmuSegmentation::update_from_model_object() void GLGizmoMmuSegmentation::update_from_model_object()
@ -410,79 +431,66 @@ PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const
std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_left_button_color() const std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_left_button_color() const
{ {
const std::array<uint8_t, 3> &color = m_modified_extruders_colors[m_first_selected_extruder_idx]; const std::array<float, 4> &color = m_modified_extruders_colors[m_first_selected_extruder_idx];
return {float(color[0]) / 255.0f, float(color[1]) / 255.0f, float(color[2]) / 255.0f, 0.25f}; return {color[0], color[1], color[2], 0.25f};
} }
std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_color() const std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_color() const
{ {
const std::array<uint8_t, 3> &color = m_modified_extruders_colors[m_second_selected_extruder_idx]; const std::array<float, 4> &color = m_modified_extruders_colors[m_second_selected_extruder_idx];
return {float(color[0]) / 255.0f, float(color[1]) / 255.0f, float(color[2]) / 255.0f, 0.25f}; return {color[0], color[1], color[2], 0.25f};
} }
void TriangleSelectorMmuGui::render(ImGuiWrapper *imgui) void TriangleSelectorMmuGui::render(ImGuiWrapper *imgui)
{ {
static constexpr std::array<float, 4> seed_fill_color{0.f, 1.f, 0.44f, 1.f};
std::vector<int> color_cnt(m_iva_colors.size()); std::vector<int> color_cnt(m_iva_colors.size());
int seed_fill_cnt = 0; int seed_fill_cnt = 0;
for (auto &iva_color : m_iva_colors) for (auto &iva_color : m_iva_colors)
iva_color.release_geometry(); iva_color.release_geometry();
m_iva_seed_fill.release_geometry(); m_iva_seed_fill.release_geometry();
auto append_triangle = [this](GLIndexedVertexArray &iva, int &cnt, const Triangle &tr) -> void {
for (int i = 0; i < 3; ++i)
iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
iva.push_triangle(cnt, cnt + 1, cnt + 2);
cnt += 3;
};
for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) { for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) {
for (const Triangle &tr : m_triangles) { for (const Triangle &tr : m_triangles) {
if (!tr.valid() || tr.is_split() || tr.is_selected_by_seed_fill() || tr.get_state() != EnforcerBlockerType(color_idx)) if (!tr.valid() || tr.is_split() || tr.is_selected_by_seed_fill() || tr.get_state() != EnforcerBlockerType(color_idx))
continue; continue;
append_triangle(m_iva_colors[color_idx], color_cnt[color_idx], tr);
for (int i = 0; i < 3; ++i)
m_iva_colors[color_idx].push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
m_iva_colors[color_idx].push_triangle(color_cnt[color_idx], color_cnt[color_idx] + 1, color_cnt[color_idx] + 2);
color_cnt[color_idx] += 3;
} }
} }
for (const Triangle &tr : m_triangles) { for (const Triangle &tr : m_triangles) {
if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill()) continue; if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill())
continue;
for (int i = 0; i < 3; ++i) append_triangle(m_iva_seed_fill, seed_fill_cnt, tr);
m_iva_seed_fill.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
m_iva_seed_fill.push_triangle(seed_fill_cnt, seed_fill_cnt + 1, seed_fill_cnt + 2);
seed_fill_cnt += 3;
} }
for (auto &iva_color : m_iva_colors) for (auto &iva_color : m_iva_colors)
iva_color.finalize_geometry(true); iva_color.finalize_geometry(true);
m_iva_seed_fill.finalize_geometry(true); m_iva_seed_fill.finalize_geometry(true);
std::vector<bool> render_colors(m_iva_colors.size()); auto *shader = wxGetApp().get_current_shader();
for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) if (!shader)
render_colors[color_idx] = m_iva_colors[color_idx].has_VBOs(); return;
bool render_seed_fill = m_iva_seed_fill.has_VBOs(); assert(shader->get_name() == "gouraud");
auto *shader = wxGetApp().get_shader("gouraud"); auto render = [&shader](const GLIndexedVertexArray &iva, const std::array<float, 4> &color) -> void {
if (!shader) return; if (iva.has_VBOs()) {
shader->start_using();
ScopeGuard guard([shader]() {
if (shader)
shader->stop_using();
});
shader->set_uniform("slope.actived", false);
shader->set_uniform("print_box.actived", false);
for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx) {
if (render_colors[color_idx]) {
std::array<float, 4> color = {float(m_colors[color_idx][0]) / 255.0f, float(m_colors[color_idx][1]) / 255.0f,
float(m_colors[color_idx][2]) / 255.0f, 1.f};
shader->set_uniform("uniform_color", color); shader->set_uniform("uniform_color", color);
m_iva_colors[color_idx].render(); iva.render();
} }
} };
if (render_seed_fill) { for (size_t color_idx = 0; color_idx < m_iva_colors.size(); ++color_idx)
std::array<float, 4> color = {0.f, 1.f, 0.44f, 1.f}; render(m_iva_colors[color_idx], (color_idx == 0) ? m_default_volume_color : m_colors[color_idx - 1]);
shader->set_uniform("uniform_color", color); render(m_iva_seed_fill, seed_fill_color);
m_iva_seed_fill.render();
}
} }
wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const

View File

@ -7,18 +7,22 @@ namespace Slic3r::GUI {
class TriangleSelectorMmuGui : public TriangleSelectorGUI { class TriangleSelectorMmuGui : public TriangleSelectorGUI {
public: public:
explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector<std::array<uint8_t, 3>> &colors) explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
: TriangleSelectorGUI(mesh), m_colors(colors) { : TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color) {
m_iva_colors = std::vector<GLIndexedVertexArray>(colors.size()); // Plus 1 is because the first position is allocated for non-painted triangles.
m_iva_colors = std::vector<GLIndexedVertexArray>(colors.size() + 1);
} }
~TriangleSelectorMmuGui() override = default;
// Render current selection. Transformation matrices are supposed // Render current selection. Transformation matrices are supposed
// to be already set. // to be already set.
void render(ImGuiWrapper* imgui) override; void render(ImGuiWrapper* imgui) override;
private: private:
const std::vector<std::array<uint8_t, 3>> &m_colors; const std::vector<std::array<float, 4>> &m_colors;
std::vector<GLIndexedVertexArray> m_iva_colors; std::vector<GLIndexedVertexArray> m_iva_colors;
const std::array<float, 4> m_default_volume_color;
GLIndexedVertexArray m_iva_seed_fill;
}; };
class GLGizmoMmuSegmentation : public GLGizmoPainterBase class GLGizmoMmuSegmentation : public GLGizmoPainterBase
@ -26,6 +30,7 @@ class GLGizmoMmuSegmentation : public GLGizmoPainterBase
public: public:
GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoPainterBase(parent, icon_filename, sprite_id) {} : GLGizmoPainterBase(parent, icon_filename, sprite_id) {}
~GLGizmoMmuSegmentation() override = default;
void render_painter_gizmo() const override; void render_painter_gizmo() const override;
@ -35,8 +40,8 @@ protected:
std::array<float, 4> get_cursor_sphere_left_button_color() const override; std::array<float, 4> get_cursor_sphere_left_button_color() const override;
std::array<float, 4> get_cursor_sphere_right_button_color() const override; std::array<float, 4> get_cursor_sphere_right_button_color() const override;
EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_first_selected_extruder_idx); } EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_first_selected_extruder_idx + 1); }
EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(m_second_selected_extruder_idx); } EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(m_second_selected_extruder_idx + 1); }
void on_render_input_window(float x, float y, float bottom_limit) override; void on_render_input_window(float x, float y, float bottom_limit) override;
std::string on_get_name() const override; std::string on_get_name() const override;
@ -45,11 +50,12 @@ protected:
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override; wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
size_t m_first_selected_extruder_idx = 0; size_t m_first_selected_extruder_idx = 0;
size_t m_second_selected_extruder_idx = 1; size_t m_second_selected_extruder_idx = 1;
std::vector<std::string> m_original_extruders_names; std::vector<std::string> m_original_extruders_names;
std::vector<std::array<uint8_t, 3>> m_original_extruders_colors; std::vector<std::array<float, 4>> m_original_extruders_colors;
std::vector<std::array<uint8_t, 3>> m_modified_extruders_colors; std::vector<std::array<float, 4>> m_modified_extruders_colors;
std::vector<int> m_original_volumes_extruder_idxs;
private: private:
bool on_init() override; bool on_init() override;

View File

@ -13,8 +13,7 @@
namespace Slic3r { namespace Slic3r::GUI {
namespace GUI {
GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
@ -110,13 +109,15 @@ void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection)
void GLGizmoPainterBase::render_triangles(const Selection& selection) const void GLGizmoPainterBase::render_triangles(const Selection& selection, const bool use_polygon_offset_fill) const
{ {
const ModelObject* mo = m_c->selection_info()->model_object(); const ModelObject* mo = m_c->selection_info()->model_object();
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); if (use_polygon_offset_fill) {
ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); } ); glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
glsafe(::glPolygonOffset(-5.0, -5.0)); ScopeGuard offset_fill_guard([]() { glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); });
glsafe(::glPolygonOffset(-5.0, -5.0));
}
// Take care of the clipping plane. The normal of the clipping plane is // Take care of the clipping plane. The normal of the clipping plane is
// saved with opposite sign than we need to pass to OpenGL (FIXME) // saved with opposite sign than we need to pass to OpenGL (FIXME)
@ -125,8 +126,8 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
if (clipping_plane_active) { if (clipping_plane_active) {
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
for (size_t i=0; i<3; ++i) for (size_t i=0; i<3; ++i)
clp_dataf[i] = -1. * clp->get_data()[i]; clp_dataf[i] = -1.f * float(clp->get_data()[i]);
clp_dataf[3] = clp->get_data()[3]; clp_dataf[3] = float(clp->get_data()[3]);
} }
auto *shader = wxGetApp().get_shader("gouraud"); auto *shader = wxGetApp().get_shader("gouraud");
@ -202,13 +203,13 @@ void GLGizmoPainterBase::render_cursor() const
void GLGizmoPainterBase::render_cursor_circle() const void GLGizmoPainterBase::render_cursor_circle() const
{ {
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera &camera = wxGetApp().plater()->get_camera();
float zoom = (float)camera.get_zoom(); auto zoom = (float) camera.get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size(); Size cnv_size = m_parent.get_canvas_size();
float cnv_half_width = 0.5f * (float)cnv_size.get_width(); float cnv_half_width = 0.5f * (float) cnv_size.get_width();
float cnv_half_height = 0.5f * (float)cnv_size.get_height(); float cnv_half_height = 0.5f * (float) cnv_size.get_height();
if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f)) if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f))
return; return;
Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1)); Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1));
@ -216,11 +217,8 @@ void GLGizmoPainterBase::render_cursor_circle() const
center = center * inv_zoom; center = center * inv_zoom;
glsafe(::glLineWidth(1.5f)); glsafe(::glLineWidth(1.5f));
float color[3]; static const std::array<float, 3> color = {0.f, 1.f, 0.3f};
color[0] = 0.f; glsafe(::glColor3fv(color.data()));
color[1] = 1.f;
color[2] = 0.3f;
glsafe(::glColor3fv(color));
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
@ -395,9 +393,10 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>(); Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>();
assert(m_rr.mesh_id < int(m_triangle_selectors.size())); assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
if (m_seed_fill_enabled) if (m_seed_fill_enabled) {
m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state); m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state);
else m_seed_fill_last_mesh_id = -1;
} else
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type, m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type,
new_state, trafo_matrix, m_triangle_splitting_enabled); new_state, trafo_matrix, m_triangle_splitting_enabled);
m_last_mouse_click = mouse_position; m_last_mouse_click = mouse_position;
@ -425,17 +424,27 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
// Now "click" into all the prepared points and spill paint around them. // Now "click" into all the prepared points and spill paint around them.
update_raycast_cache(mouse_position, camera, trafo_matrices); update_raycast_cache(mouse_position, camera, trafo_matrices);
if (m_rr.mesh_id == -1) { auto seed_fill_unselect_all = [this]() {
// Clean selected by seed fill for all triangles
for (auto &triangle_selector : m_triangle_selectors) for (auto &triangle_selector : m_triangle_selectors)
triangle_selector->seed_fill_unselect_all_triangles(); triangle_selector->seed_fill_unselect_all_triangles();
};
if (m_rr.mesh_id == -1) {
// Clean selected by seed fill for all triangles in all meshes when a mouse isn't pointing on any mesh.
seed_fill_unselect_all();
m_seed_fill_last_mesh_id = -1;
// In case we have no valid hit, we can return. // In case we have no valid hit, we can return.
return false; return false;
} }
// The mouse moved from one object's volume to another one. So it is needed to unselect all triangles selected by seed fill.
if(m_rr.mesh_id != m_seed_fill_last_mesh_id)
seed_fill_unselect_all();
assert(m_rr.mesh_id < int(m_triangle_selectors.size())); assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle); m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle);
m_seed_fill_last_mesh_id = m_rr.mesh_id;
return true; return true;
} }
@ -514,11 +523,7 @@ bool GLGizmoPainterBase::on_is_activable() const
// Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside.
const Selection::IndicesList& list = selection.get_volume_idxs(); const Selection::IndicesList& list = selection.get_volume_idxs();
for (const auto& idx : list) return std::all_of(list.cbegin(), list.cend(), [&selection](unsigned int idx) { return !selection.get_volume(idx)->is_outside; });
if (selection.get_volume(idx)->is_outside)
return false;
return true;
} }
bool GLGizmoPainterBase::on_is_selectable() const bool GLGizmoPainterBase::on_is_selectable() const
@ -578,70 +583,42 @@ void GLGizmoPainterBase::on_load(cereal::BinaryInputArchive&)
void TriangleSelectorGUI::render(ImGuiWrapper* imgui) void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
{ {
int enf_cnt = 0; static constexpr std::array<float, 4> enforcers_color{0.47f, 0.47f, 1.f, 1.f};
int blc_cnt = 0; static constexpr std::array<float, 4> blockers_color{1.f, 0.44f, 0.44f, 1.f};
int seed_fill_cnt = 0;
m_iva_enforcers.release_geometry(); int enf_cnt = 0;
m_iva_blockers.release_geometry(); int blc_cnt = 0;
m_iva_seed_fill.release_geometry();
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->release_geometry();
for (const Triangle& tr : m_triangles) { for (const Triangle& tr : m_triangles) {
if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE || tr.is_selected_by_seed_fill()) if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE)
continue; continue;
GLIndexedVertexArray& va = tr.get_state() == EnforcerBlockerType::ENFORCER GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers;
? m_iva_enforcers int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt;
: m_iva_blockers;
int& cnt = tr.get_state() == EnforcerBlockerType::ENFORCER
? enf_cnt
: blc_cnt;
for (int i=0; i<3; ++i) for (int i = 0; i < 3; ++i)
va.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
va.push_triangle(cnt, cnt + 1, cnt + 2); iva.push_triangle(cnt, cnt + 1, cnt + 2);
cnt += 3; cnt += 3;
} }
for (const Triangle &tr : m_triangles) { for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
if (!tr.valid() || tr.is_split() || !tr.is_selected_by_seed_fill()) iva->finalize_geometry(true);
continue;
for (int i = 0; i < 3; ++i)
m_iva_seed_fill.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
m_iva_seed_fill.push_triangle(seed_fill_cnt, seed_fill_cnt + 1, seed_fill_cnt + 2);
seed_fill_cnt += 3;
}
m_iva_enforcers.finalize_geometry(true);
m_iva_blockers.finalize_geometry(true);
m_iva_seed_fill.finalize_geometry(true);
bool render_enf = m_iva_enforcers.has_VBOs();
bool render_blc = m_iva_blockers.has_VBOs();
bool render_seed_fill = m_iva_seed_fill.has_VBOs();
auto* shader = wxGetApp().get_current_shader(); auto* shader = wxGetApp().get_current_shader();
if (! shader) if (! shader)
return; return;
assert(shader->get_name() == "gouraud"); assert(shader->get_name() == "gouraud");
if (render_enf) { for (auto iva : {std::make_pair(&m_iva_enforcers, enforcers_color),
std::array<float, 4> color = { 0.47f, 0.47f, 1.f, 1.f }; std::make_pair(&m_iva_blockers, blockers_color)}) {
shader->set_uniform("uniform_color", color); if (iva.first->has_VBOs()) {
m_iva_enforcers.render(); shader->set_uniform("uniform_color", iva.second);
} iva.first->render();
}
if (render_blc) {
std::array<float, 4> color = { 1.f, 0.44f, 0.44f, 1.f };
shader->set_uniform("uniform_color", color);
m_iva_blockers.render();
}
if (render_seed_fill) {
std::array<float, 4> color = { 0.f, 1.00f, 0.44f, 1.f };
shader->set_uniform("uniform_color", color);
m_iva_seed_fill.render();
} }
@ -746,5 +723,4 @@ void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui)
} // namespace GUI } // namespace Slic3r::GUI
} // namespace Slic3r

View File

@ -31,10 +31,12 @@ class TriangleSelectorGUI : public TriangleSelector {
public: public:
explicit TriangleSelectorGUI(const TriangleMesh& mesh) explicit TriangleSelectorGUI(const TriangleMesh& mesh)
: TriangleSelector(mesh) {} : TriangleSelector(mesh) {}
virtual ~TriangleSelectorGUI() = default;
// Render current selection. Transformation matrices are supposed // Render current selection. Transformation matrices are supposed
// to be already set. // to be already set.
virtual void render(ImGuiWrapper* imgui = nullptr); virtual void render(ImGuiWrapper *imgui);
void render() { this->render(nullptr); }
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
void render_debug(ImGuiWrapper* imgui); void render_debug(ImGuiWrapper* imgui);
@ -43,11 +45,9 @@ public:
#endif #endif
private: private:
GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_enforcers;
GLIndexedVertexArray m_iva_blockers; GLIndexedVertexArray m_iva_blockers;
std::array<GLIndexedVertexArray, 3> m_varrays; std::array<GLIndexedVertexArray, 3> m_varrays;
protected:
GLIndexedVertexArray m_iva_seed_fill;
}; };
@ -59,12 +59,12 @@ class GLGizmoPainterBase : public GLGizmoBase
private: private:
ObjectID m_old_mo_id; ObjectID m_old_mo_id;
size_t m_old_volumes_size = 0; size_t m_old_volumes_size = 0;
virtual void on_render() const override {} void on_render() const override {}
virtual void on_render_for_picking() const override {} void on_render_for_picking() const override {}
public: public:
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoPainterBase() override {} ~GLGizmoPainterBase() override = default;
virtual void set_painter_gizmo_data(const Selection& selection); virtual void set_painter_gizmo_data(const Selection& selection);
virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@ -75,14 +75,13 @@ public:
virtual void render_painter_gizmo() const = 0; virtual void render_painter_gizmo() const = 0;
protected: protected:
void render_triangles(const Selection& selection) const; void render_triangles(const Selection& selection, const bool use_polygon_offset_fill = true) const;
void render_cursor() const; void render_cursor() const;
void render_cursor_circle() const; void render_cursor_circle() const;
void render_cursor_sphere(const Transform3d& trafo) const; void render_cursor_sphere(const Transform3d& trafo) const;
virtual void update_model_object() const = 0; virtual void update_model_object() const = 0;
virtual void update_from_model_object() = 0; virtual void update_from_model_object() = 0;
void activate_internal_undo_redo_stack(bool activate); void activate_internal_undo_redo_stack(bool activate);
void set_cursor_type(TriangleSelector::CursorType);
virtual std::array<float, 4> get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; } virtual std::array<float, 4> get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; }
virtual std::array<float, 4> get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; } virtual std::array<float, 4> get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; }
@ -104,6 +103,10 @@ protected:
bool m_seed_fill_enabled = false; bool m_seed_fill_enabled = false;
float m_seed_fill_angle = 0.f; float m_seed_fill_angle = 0.f;
// It stores the value of the previous mesh_id to which the seed fill was applied.
// It is used to detect when the mouse has moved from one volume to another one.
int m_seed_fill_last_mesh_id = -1;
enum class Button { enum class Button {
None, None,
Left, Left,

View File

@ -86,10 +86,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f); const float button_width = m_imgui->calc_text_size(m_desc.at("remove_all")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
float caption_max = 0.f; float caption_max = 0.f;
float total_text_max = 0.; float total_text_max = 0.f;
for (const std::string& t : {"enforce", "block", "remove"}) { for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"}) {
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t+"_caption")).x); caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc.at(t + "_caption")).x);
total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x); total_text_max = std::max(total_text_max, caption_max + m_imgui->calc_text_size(m_desc.at(t)).x);
} }
caption_max += m_imgui->scaled(1.f); caption_max += m_imgui->scaled(1.f);
@ -107,7 +107,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
m_imgui->text(text); m_imgui->text(text);
}; };
for (const std::string& t : {"enforce", "block", "remove"}) for (const auto &t : std::array<std::string, 3>{"enforce", "block", "remove"})
draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t)); draw_text_with_caption(m_desc.at(t + "_caption"), m_desc.at(t));
m_imgui->text(""); m_imgui->text("");

View File

@ -62,9 +62,10 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_type(itInfo), m_type(itInfo),
m_extruder(wxEmptyString) m_extruder(wxEmptyString)
{ {
m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") :
: info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") :
: _L("Variable layer height"); info_type == InfoItemType::MmuSegmentation ? _L("Paint-on segmentation") :
_L("Variable layer height");
m_info_item_type = info_type; m_info_item_type = info_type;
} }

View File

@ -50,6 +50,7 @@ enum class InfoItemType
Undef, Undef,
CustomSupports, CustomSupports,
CustomSeam, CustomSeam,
MmuSegmentation,
VariableLayerHeight VariableLayerHeight
}; };