2022-07-15 15:37:19 +00:00
|
|
|
#include "BoundingBox.hpp"
|
|
|
|
#include "ClipperUtils.hpp"
|
|
|
|
#include "EdgeGrid.hpp"
|
|
|
|
#include "Layer.hpp"
|
|
|
|
#include "Print.hpp"
|
|
|
|
#include "Geometry/VoronoiVisualUtils.hpp"
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#include "Geometry/VoronoiUtils.hpp"
|
2022-07-15 15:37:19 +00:00
|
|
|
#include "MutablePolygon.hpp"
|
|
|
|
#include "format.hpp"
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
#include <unordered_set>
|
|
|
|
|
|
|
|
#include <boost/log/trivial.hpp>
|
|
|
|
#include <tbb/parallel_for.h>
|
|
|
|
#include <mutex>
|
|
|
|
#include <boost/thread/lock_guard.hpp>
|
|
|
|
|
2024-09-19 06:06:06 +00:00
|
|
|
//#define MM_SEGMENTATION_DEBUG_PAINT_LINE
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
//#define MM_SEGMENTATION_DEBUG_GRAPH
|
|
|
|
//#define MM_SEGMENTATION_DEBUG_REGIONS
|
|
|
|
//#define MM_SEGMENTATION_DEBUG_INPUT
|
|
|
|
//#define MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
|
|
|
//#define MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#if defined(MM_SEGMENTATION_DEBUG_GRAPH) || defined(MM_SEGMENTATION_DEBUG_REGIONS) || \
|
|
|
|
defined(MM_SEGMENTATION_DEBUG_INPUT) || defined(MM_SEGMENTATION_DEBUG_PAINTED_LINES) || \
|
|
|
|
defined(MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS)
|
|
|
|
#define MM_SEGMENTATION_DEBUG
|
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
//#define MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
2024-05-30 12:23:23 +00:00
|
|
|
using boost::polygon::voronoi_diagram;
|
|
|
|
|
|
|
|
static inline Point mk_point(const Voronoi::VD::vertex_type *point) { return {coord_t(point->x()), coord_t(point->y())}; }
|
|
|
|
|
|
|
|
static inline Point mk_point(const Voronoi::Internal::point_type &point) { return {coord_t(point.x()), coord_t(point.y())}; }
|
|
|
|
|
|
|
|
static inline Point mk_point(const voronoi_diagram<double>::vertex_type &point) { return {coord_t(point.x()), coord_t(point.y())}; }
|
|
|
|
|
|
|
|
static inline Point mk_point(const Vec2d &point) { return {coord_t(std::round(point.x())), coord_t(std::round(point.y()))}; }
|
|
|
|
|
|
|
|
static inline Vec2d mk_vec2(const voronoi_diagram<double>::vertex_type *point) { return {point->x(), point->y()}; }
|
|
|
|
|
|
|
|
static bool vertex_equal_to_point(const Voronoi::VD::vertex_type &vertex, const Vec2d &ipt)
|
|
|
|
{
|
|
|
|
// Convert ipt to doubles, force the 80bit FPU temporary to 64bit and then compare.
|
|
|
|
// This should work with any settings of math compiler switches and the C++ compiler
|
|
|
|
// shall understand the memcpies as type punning and it shall optimize them out.
|
|
|
|
using ulp_cmp_type = boost::polygon::detail::ulp_comparison<double>;
|
|
|
|
ulp_cmp_type ulp_cmp;
|
|
|
|
static constexpr int ULPS = boost::polygon::voronoi_diagram_traits<double>::vertex_equality_predicate_type::ULPS;
|
|
|
|
return ulp_cmp(vertex.x(), ipt.x(), ULPS) == ulp_cmp_type::EQUAL && ulp_cmp(vertex.y(), ipt.y(), ULPS) == ulp_cmp_type::EQUAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool vertex_equal_to_point(const Voronoi::VD::vertex_type *vertex, const Vec2d &ipt) { return vertex_equal_to_point(*vertex, ipt); }
|
|
|
|
|
|
|
|
struct MMU_Graph
|
|
|
|
{
|
|
|
|
enum class ARC_TYPE { BORDER, NON_BORDER };
|
|
|
|
|
|
|
|
struct Arc
|
|
|
|
{
|
|
|
|
size_t from_idx;
|
|
|
|
size_t to_idx;
|
|
|
|
int color;
|
|
|
|
ARC_TYPE type;
|
|
|
|
|
|
|
|
bool operator==(const Arc &rhs) const { return (from_idx == rhs.from_idx) && (to_idx == rhs.to_idx) && (color == rhs.color) && (type == rhs.type); }
|
|
|
|
bool operator!=(const Arc &rhs) const { return !operator==(rhs); }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
Vec2d point;
|
|
|
|
std::list<size_t> arc_idxs;
|
|
|
|
|
|
|
|
void remove_edge(const size_t to_idx, MMU_Graph &graph)
|
|
|
|
{
|
|
|
|
for (auto arc_it = this->arc_idxs.begin(); arc_it != this->arc_idxs.end(); ++arc_it) {
|
|
|
|
MMU_Graph::Arc &arc = graph.arcs[*arc_it];
|
|
|
|
if (arc.to_idx == to_idx) {
|
|
|
|
assert(arc.type != ARC_TYPE::BORDER);
|
|
|
|
this->arc_idxs.erase(arc_it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<MMU_Graph::Node> nodes;
|
|
|
|
std::vector<MMU_Graph::Arc> arcs;
|
|
|
|
size_t all_border_points{};
|
|
|
|
|
|
|
|
std::vector<size_t> polygon_idx_offset;
|
|
|
|
std::vector<size_t> polygon_sizes;
|
|
|
|
|
|
|
|
void remove_edge(const size_t from_idx, const size_t to_idx)
|
|
|
|
{
|
|
|
|
nodes[from_idx].remove_edge(to_idx, *this);
|
|
|
|
nodes[to_idx].remove_edge(from_idx, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
[[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)
|
|
|
|
{
|
|
|
|
// Don't append duplicate edges between the same nodes.
|
|
|
|
for (const size_t &arc_idx : this->nodes[from_idx].arc_idxs)
|
|
|
|
if (arcs[arc_idx].to_idx == to_idx) return;
|
|
|
|
for (const size_t &arc_idx : this->nodes[to_idx].arc_idxs)
|
|
|
|
if (arcs[arc_idx].to_idx == from_idx) return;
|
|
|
|
|
|
|
|
this->nodes[from_idx].arc_idxs.push_back(this->arcs.size());
|
|
|
|
this->arcs.push_back({from_idx, to_idx, color, type});
|
|
|
|
|
|
|
|
// Always insert only one directed arc for the input polygons.
|
|
|
|
// Two directed arcs in both directions are inserted if arcs aren't between points of the input polygons.
|
|
|
|
if (type == ARC_TYPE::NON_BORDER) {
|
|
|
|
this->nodes[to_idx].arc_idxs.push_back(this->arcs.size());
|
|
|
|
this->arcs.push_back({to_idx, from_idx, color, type});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// It assumes that between points of the input polygons is always only one directed arc,
|
|
|
|
// with the same direction as lines of the input polygon.
|
|
|
|
[[nodiscard]] MMU_Graph::Arc get_border_arc(size_t idx) const
|
|
|
|
{
|
|
|
|
assert(idx < this->all_border_points);
|
|
|
|
return this->arcs[idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] size_t nodes_count() const { return this->nodes.size(); }
|
|
|
|
|
|
|
|
void remove_nodes_with_one_arc()
|
|
|
|
{
|
|
|
|
std::queue<size_t> update_queue;
|
|
|
|
for (const MMU_Graph::Node &node : this->nodes) {
|
|
|
|
size_t node_idx = &node - &this->nodes.front();
|
|
|
|
// Skip nodes that represent points of input polygons.
|
|
|
|
if (node.arc_idxs.size() == 1 && node_idx >= this->all_border_points) update_queue.emplace(&node - &this->nodes.front());
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!update_queue.empty()) {
|
|
|
|
size_t node_from_idx = update_queue.front();
|
|
|
|
MMU_Graph::Node &node_from = this->nodes[update_queue.front()];
|
|
|
|
update_queue.pop();
|
|
|
|
if (node_from.arc_idxs.empty()) continue;
|
|
|
|
|
|
|
|
assert(node_from.arc_idxs.size() == 1);
|
|
|
|
size_t node_to_idx = arcs[node_from.arc_idxs.front()].to_idx;
|
|
|
|
MMU_Graph::Node &node_to = this->nodes[node_to_idx];
|
|
|
|
this->remove_edge(node_from_idx, node_to_idx);
|
|
|
|
if (node_to.arc_idxs.size() == 1 && node_to_idx >= this->all_border_points) update_queue.emplace(node_to_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_contours(const std::vector<std::vector<ColoredLine>> &color_poly)
|
|
|
|
{
|
|
|
|
this->all_border_points = nodes.size();
|
|
|
|
this->polygon_sizes = std::vector<size_t>(color_poly.size());
|
|
|
|
for (size_t polygon_idx = 0; polygon_idx < color_poly.size(); ++polygon_idx) this->polygon_sizes[polygon_idx] = color_poly[polygon_idx].size();
|
|
|
|
this->polygon_idx_offset = std::vector<size_t>(color_poly.size());
|
|
|
|
this->polygon_idx_offset[0] = 0;
|
|
|
|
for (size_t polygon_idx = 1; polygon_idx < color_poly.size(); ++polygon_idx) {
|
|
|
|
this->polygon_idx_offset[polygon_idx] = this->polygon_idx_offset[polygon_idx - 1] + color_poly[polygon_idx - 1].size();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t poly_idx = 0;
|
|
|
|
for (const std::vector<ColoredLine> &color_lines : color_poly) {
|
|
|
|
size_t line_idx = 0;
|
|
|
|
for (const ColoredLine &color_line : color_lines) {
|
|
|
|
size_t from_idx = this->get_global_index(poly_idx, line_idx);
|
|
|
|
size_t to_idx = this->get_global_index(poly_idx, (line_idx + 1) % color_lines.size());
|
|
|
|
this->append_edge(from_idx, to_idx, color_line.color, ARC_TYPE::BORDER);
|
|
|
|
++line_idx;
|
|
|
|
}
|
|
|
|
++poly_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nodes 0..all_border_points are only one with are on countour. Other vertexis are consider as not on coouter. So we check if base on attach index
|
|
|
|
inline bool is_vertex_on_contour(const Voronoi::VD::vertex_type *vertex) const
|
|
|
|
{
|
|
|
|
assert(vertex != nullptr);
|
|
|
|
return vertex->color() < this->all_border_points;
|
|
|
|
}
|
|
|
|
|
|
|
|
[[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());
|
|
|
|
}
|
|
|
|
|
|
|
|
[[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());
|
|
|
|
}
|
|
|
|
|
|
|
|
// All Voronoi vertices are post-processes to merge very close vertices to single. Witch eliminates issues with intersection edges.
|
|
|
|
// Also, Voronoi vertices outside of the bounding of input polygons are throw away by marking them.
|
|
|
|
void append_voronoi_vertices(const Geometry::VoronoiDiagram &vd, const Polygons &color_poly_tmp, BoundingBox bbox)
|
|
|
|
{
|
|
|
|
bbox.offset(SCALED_EPSILON);
|
|
|
|
|
|
|
|
struct CPoint
|
|
|
|
{
|
|
|
|
CPoint() = delete;
|
|
|
|
CPoint(const Vec2d &point, size_t contour_idx, size_t point_idx) : m_point_double(point), m_point(mk_point(point)), m_point_idx(point_idx), m_contour_idx(contour_idx)
|
|
|
|
{}
|
|
|
|
CPoint(const Vec2d &point, size_t point_idx) : m_point_double(point), m_point(mk_point(point)), m_point_idx(point_idx), m_contour_idx(0) {}
|
|
|
|
const Vec2d m_point_double;
|
|
|
|
const Point m_point;
|
|
|
|
size_t m_point_idx;
|
|
|
|
size_t m_contour_idx;
|
|
|
|
|
|
|
|
[[nodiscard]] const Vec2d &point_double() const { return m_point_double; }
|
|
|
|
[[nodiscard]] const Point &point() const { return m_point; }
|
|
|
|
bool operator==(const CPoint &rhs) const
|
|
|
|
{
|
|
|
|
return this->m_point_double == rhs.m_point_double && this->m_contour_idx == rhs.m_contour_idx && this->m_point_idx == rhs.m_point_idx;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
struct CPointAccessor
|
|
|
|
{
|
|
|
|
const Point *operator()(const CPoint &pt) const { return &pt.point(); }
|
|
|
|
};
|
|
|
|
typedef ClosestPointInRadiusLookup<CPoint, CPointAccessor> CPointLookupType;
|
|
|
|
|
|
|
|
CPointLookupType closest_voronoi_point(coord_t(SCALED_EPSILON));
|
|
|
|
CPointLookupType closest_contour_point(3 * coord_t(SCALED_EPSILON));
|
|
|
|
for (const Polygon &polygon : color_poly_tmp)
|
|
|
|
for (const Point &pt : polygon.points) closest_contour_point.insert(CPoint(Vec2d(pt.x(), pt.y()), &polygon - &color_poly_tmp.front(), &pt - &polygon.points.front()));
|
|
|
|
|
|
|
|
for (const voronoi_diagram<double>::vertex_type &vertex : vd.vertices()) {
|
|
|
|
vertex.color(-1);
|
|
|
|
Vec2d vertex_point_double = Vec2d(vertex.x(), vertex.y());
|
|
|
|
Point vertex_point = mk_point(vertex);
|
|
|
|
|
|
|
|
const Vec2d &first_point_double = this->nodes[this->get_border_arc(vertex.incident_edge()->cell()->source_index()).from_idx].point;
|
|
|
|
const Vec2d &second_point_double = this->nodes[this->get_border_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx].point;
|
|
|
|
|
|
|
|
if (vertex_equal_to_point(&vertex, first_point_double)) {
|
|
|
|
assert(vertex.color() != vertex.incident_edge()->cell()->source_index());
|
|
|
|
assert(vertex.color() != vertex.incident_edge()->twin()->cell()->source_index());
|
|
|
|
vertex.color(this->get_border_arc(vertex.incident_edge()->cell()->source_index()).from_idx);
|
|
|
|
} else if (vertex_equal_to_point(&vertex, second_point_double)) {
|
|
|
|
assert(vertex.color() != vertex.incident_edge()->cell()->source_index());
|
|
|
|
assert(vertex.color() != vertex.incident_edge()->twin()->cell()->source_index());
|
|
|
|
vertex.color(this->get_border_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx);
|
|
|
|
} else if (bbox.contains(vertex_point)) {
|
|
|
|
if (auto [contour_pt, c_dist_sqr] = closest_contour_point.find(vertex_point); contour_pt != nullptr && c_dist_sqr < Slic3r::sqr(3 * SCALED_EPSILON)) {
|
|
|
|
vertex.color(this->get_global_index(contour_pt->m_contour_idx, contour_pt->m_point_idx));
|
|
|
|
} else if (auto [voronoi_pt, v_dist_sqr] = closest_voronoi_point.find(vertex_point); voronoi_pt == nullptr || v_dist_sqr >= Slic3r::sqr(SCALED_EPSILON / 10.0)) {
|
|
|
|
closest_voronoi_point.insert(CPoint(vertex_point_double, this->nodes_count()));
|
|
|
|
vertex.color(this->nodes_count());
|
|
|
|
this->nodes.push_back({vertex_point_double});
|
|
|
|
} else {
|
|
|
|
// Boost Voronoi diagram generator sometimes creates two very closed points instead of one point.
|
|
|
|
// For the example points (146872.99999999997, -146872.99999999997) and (146873, -146873), this example also included in Voronoi generator test cases.
|
|
|
|
std::vector<std::pair<const CPoint *, double>> all_closes_c_points = closest_voronoi_point.find_all(vertex_point);
|
|
|
|
int merge_to_point = -1;
|
|
|
|
for (const std::pair<const CPoint *, double> &c_point : all_closes_c_points)
|
|
|
|
if ((vertex_point_double - c_point.first->point_double()).squaredNorm() <= Slic3r::sqr(EPSILON)) {
|
|
|
|
merge_to_point = int(c_point.first->m_point_idx);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (merge_to_point != -1) {
|
|
|
|
vertex.color(merge_to_point);
|
|
|
|
} else {
|
|
|
|
closest_voronoi_point.insert(CPoint(vertex_point_double, this->nodes_count()));
|
|
|
|
vertex.color(this->nodes_count());
|
|
|
|
this->nodes.push_back({vertex_point_double});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void garbage_collect()
|
|
|
|
{
|
|
|
|
std::vector<int> nodes_map(this->nodes.size(), -1);
|
|
|
|
int nodes_count = 0;
|
|
|
|
size_t arcs_count = 0;
|
|
|
|
for (const MMU_Graph::Node &node : this->nodes)
|
|
|
|
if (size_t node_idx = &node - &this->nodes.front(); !node.arc_idxs.empty()) {
|
|
|
|
nodes_map[node_idx] = nodes_count++;
|
|
|
|
arcs_count += node.arc_idxs.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<MMU_Graph::Node> new_nodes;
|
|
|
|
std::vector<MMU_Graph::Arc> new_arcs;
|
|
|
|
new_nodes.reserve(nodes_count);
|
|
|
|
new_arcs.reserve(arcs_count);
|
|
|
|
for (const MMU_Graph::Node &node : this->nodes)
|
|
|
|
if (size_t node_idx = &node - &this->nodes.front(); nodes_map[node_idx] >= 0) {
|
|
|
|
new_nodes.push_back({node.point});
|
|
|
|
for (const size_t &arc_idx : node.arc_idxs) {
|
|
|
|
const Arc &arc = this->arcs[arc_idx];
|
|
|
|
new_nodes.back().arc_idxs.emplace_back(new_arcs.size());
|
|
|
|
new_arcs.push_back({size_t(nodes_map[arc.from_idx]), size_t(nodes_map[arc.to_idx]), arc.color, arc.type});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this->nodes = std::move(new_nodes);
|
|
|
|
this->arcs = std::move(new_arcs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Polygon colored_points_to_polygon(const std::vector<ColoredLine> &lines)
|
|
|
|
{
|
|
|
|
Polygon out;
|
|
|
|
out.points.reserve(lines.size());
|
|
|
|
for (const ColoredLine &l : lines) out.points.emplace_back(l.line.a);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Polygons colored_points_to_polygon(const std::vector<std::vector<ColoredLine>> &lines)
|
|
|
|
{
|
|
|
|
Polygons out;
|
|
|
|
out.reserve(lines.size());
|
|
|
|
for (const std::vector<ColoredLine> &l : lines) out.emplace_back(colored_points_to_polygon(l));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<std::vector<const MMU_Graph::Arc *>> get_all_next_arcs(
|
|
|
|
const MMU_Graph &graph, std::vector<bool> &used_arcs, const Linef &process_line, const MMU_Graph::Arc &original_arc, const int color)
|
|
|
|
{
|
|
|
|
std::vector<std::vector<const MMU_Graph::Arc *>> all_next_arcs;
|
|
|
|
for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) {
|
|
|
|
std::vector<const MMU_Graph::Arc *> next_continue_arc;
|
|
|
|
|
|
|
|
const MMU_Graph::Arc &arc = graph.arcs[arc_idx];
|
|
|
|
if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) continue;
|
|
|
|
|
|
|
|
if (original_arc.type == MMU_Graph::ARC_TYPE::BORDER && original_arc.color != color) continue;
|
|
|
|
|
|
|
|
if (arc.type == MMU_Graph::ARC_TYPE::BORDER && arc.color != color) continue;
|
|
|
|
|
|
|
|
Vec2d arc_line = graph.nodes[arc.to_idx].point - graph.nodes[arc.from_idx].point;
|
|
|
|
next_continue_arc.emplace_back(&arc);
|
|
|
|
all_next_arcs.emplace_back(next_continue_arc);
|
|
|
|
}
|
|
|
|
return all_next_arcs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<const MMU_Graph::Arc *> get_next_arc(
|
|
|
|
const MMU_Graph &graph, std::vector<bool> &used_arcs, const Linef &process_line, const MMU_Graph::Arc &original_arc, const int color)
|
|
|
|
{
|
|
|
|
std::vector<const MMU_Graph::Arc *> res;
|
|
|
|
|
|
|
|
std::vector<std::vector<const MMU_Graph::Arc *>> all_next_arcs = get_all_next_arcs(graph, used_arcs, process_line, original_arc, color);
|
|
|
|
if (all_next_arcs.empty()) {
|
|
|
|
res.emplace_back(&original_arc);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::pair<std::vector<const MMU_Graph::Arc *>, double>> sorted_arcs;
|
|
|
|
for (auto next_arc : all_next_arcs) {
|
|
|
|
if (next_arc.empty()) continue;
|
|
|
|
|
|
|
|
Vec2d process_line_vec_n = (process_line.a - process_line.b).normalized();
|
|
|
|
Vec2d neighbour_line_vec_n = (graph.nodes[next_arc.back()->to_idx].point - graph.nodes[next_arc.back()->from_idx].point).normalized();
|
|
|
|
|
|
|
|
double angle = ::acos(std::clamp(neighbour_line_vec_n.dot(process_line_vec_n), -1.0, 1.0));
|
|
|
|
if (Slic3r::cross2(neighbour_line_vec_n, process_line_vec_n) < 0.0) angle = 2.0 * (double) PI - angle;
|
|
|
|
|
|
|
|
sorted_arcs.emplace_back(next_arc, angle);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(sorted_arcs.begin(), sorted_arcs.end(),
|
|
|
|
[](std::pair<std::vector<const MMU_Graph::Arc *>, double> &l, std::pair<std::vector<const MMU_Graph::Arc *>, double> &r) -> bool { return l.second < r.second; });
|
|
|
|
|
|
|
|
// Try to return left most edge witch is unused
|
|
|
|
for (auto &sorted_arc : sorted_arcs) {
|
|
|
|
if (size_t arc_idx = sorted_arc.first.back() - &graph.arcs.front(); !used_arcs[arc_idx]) return sorted_arc.first;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sorted_arcs.empty()) {
|
|
|
|
res.emplace_back(&original_arc);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sorted_arcs.front().first;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_profile_self_interaction(Polygon poly)
|
|
|
|
{
|
|
|
|
auto lines = poly.lines();
|
|
|
|
Point intersection;
|
|
|
|
for (int i = 0; i < lines.size(); ++i) {
|
|
|
|
for (int j = i + 2; j < std::min(lines.size(), lines.size() + i - 1); ++j) {
|
|
|
|
if (lines[i].intersection(lines[j], &intersection)) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Polygon to_polygon(const std::vector<std::pair<size_t, Linef>> &id_to_lines)
|
|
|
|
{
|
|
|
|
std::vector<Linef> lines;
|
|
|
|
for (auto id_to_line : id_to_lines) lines.emplace_back(id_to_line.second);
|
|
|
|
|
|
|
|
Polygon poly_out;
|
|
|
|
poly_out.points.reserve(lines.size());
|
|
|
|
for (const Linef &line : lines) poly_out.points.emplace_back(mk_point(line.a));
|
|
|
|
return poly_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<ExPolygons> extract_colored_segments(const MMU_Graph &graph, const size_t num_extruders)
|
|
|
|
{
|
|
|
|
std::vector<bool> used_arcs(graph.arcs.size(), false);
|
|
|
|
|
|
|
|
auto all_arc_used = [&used_arcs](const MMU_Graph::Node &node) -> bool {
|
|
|
|
return std::all_of(node.arc_idxs.cbegin(), node.arc_idxs.cend(), [&used_arcs](const size_t &arc_idx) -> bool { return used_arcs[arc_idx]; });
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<ExPolygons> expolygons_segments(num_extruders + 1);
|
|
|
|
for (size_t node_idx = 0; node_idx < graph.all_border_points; ++node_idx) {
|
|
|
|
const MMU_Graph::Node &node = graph.nodes[node_idx];
|
|
|
|
|
|
|
|
for (const size_t &arc_idx : node.arc_idxs) {
|
|
|
|
const MMU_Graph::Arc &arc = graph.arcs[arc_idx];
|
|
|
|
if (arc.type == MMU_Graph::ARC_TYPE::NON_BORDER || used_arcs[arc_idx]) continue;
|
|
|
|
|
|
|
|
Linef process_line(graph.nodes[arc.from_idx].point, graph.nodes[arc.to_idx].point);
|
|
|
|
used_arcs[arc_idx] = true;
|
|
|
|
|
|
|
|
std::vector<std::pair<size_t, Linef>> arc_id_to_face_lines;
|
|
|
|
arc_id_to_face_lines.emplace_back(std::make_pair(arc_idx, process_line));
|
|
|
|
Vec2d start_p = process_line.a;
|
|
|
|
|
|
|
|
Linef p_vec = process_line;
|
|
|
|
const MMU_Graph::Arc *p_arc = &arc;
|
|
|
|
bool flag = false;
|
|
|
|
do {
|
|
|
|
std::vector<const MMU_Graph::Arc *> nexts = get_next_arc(graph, used_arcs, p_vec, *p_arc, arc.color);
|
|
|
|
for (auto next : nexts) {
|
|
|
|
size_t next_arc_idx = next - &graph.arcs.front();
|
|
|
|
if (used_arcs[next_arc_idx]) {
|
|
|
|
flag = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flag) break;
|
|
|
|
|
|
|
|
for (auto next : nexts) {
|
|
|
|
size_t next_arc_idx = next - &graph.arcs.front();
|
|
|
|
arc_id_to_face_lines.emplace_back(std::make_pair(next_arc_idx, Linef(graph.nodes[next->from_idx].point, graph.nodes[next->to_idx].point)));
|
|
|
|
used_arcs[next_arc_idx] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_vec = Linef(graph.nodes[nexts.back()->from_idx].point, graph.nodes[nexts.back()->to_idx].point);
|
|
|
|
p_arc = nexts.back();
|
|
|
|
|
|
|
|
} while (graph.nodes[p_arc->to_idx].point != start_p || !all_arc_used(graph.nodes[p_arc->to_idx]));
|
|
|
|
|
|
|
|
if (Polygon poly = to_polygon(arc_id_to_face_lines); poly.is_counter_clockwise() && poly.is_valid()) {
|
|
|
|
expolygons_segments[arc.color].emplace_back(std::move(poly));
|
|
|
|
} else {
|
|
|
|
while (arc_id_to_face_lines.size() > 1) {
|
|
|
|
auto id_to_line = arc_id_to_face_lines.back();
|
|
|
|
used_arcs[id_to_line.first] = false;
|
|
|
|
arc_id_to_face_lines.pop_back();
|
|
|
|
Linef add_line(arc_id_to_face_lines.back().second.b, arc_id_to_face_lines.front().second.a);
|
|
|
|
arc_id_to_face_lines.emplace_back(std::make_pair(-1, add_line));
|
|
|
|
Polygon poly = to_polygon(arc_id_to_face_lines);
|
|
|
|
if (!is_profile_self_interaction(poly) && poly.is_counter_clockwise() && poly.is_valid()) {
|
|
|
|
expolygons_segments[arc.color].emplace_back(std::move(poly));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
arc_id_to_face_lines.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return expolygons_segments;
|
|
|
|
}
|
|
|
|
|
2023-03-29 07:22:21 +00:00
|
|
|
bool is_equal(float left, float right, float eps = 1e-3) {
|
|
|
|
return abs(left - right) <= eps;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_less(float left, float right, float eps = 1e-3) {
|
|
|
|
return left + eps < right;
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
// Assumes that is at most same projected_l length or below than projection_l
|
|
|
|
static bool project_line_on_line(const Line &projection_l, const Line &projected_l, Line *new_projected)
|
|
|
|
{
|
|
|
|
const Vec2d v1 = (projection_l.b - projection_l.a).cast<double>();
|
|
|
|
const Vec2d va = (projected_l.a - projection_l.a).cast<double>();
|
|
|
|
const Vec2d vb = (projected_l.b - projection_l.a).cast<double>();
|
|
|
|
const double l2 = v1.squaredNorm(); // avoid a sqrt
|
|
|
|
if (l2 == 0.0)
|
|
|
|
return false;
|
|
|
|
double t1 = va.dot(v1) / l2;
|
|
|
|
double t2 = vb.dot(v1) / l2;
|
|
|
|
t1 = std::clamp(t1, 0., 1.);
|
|
|
|
t2 = std::clamp(t2, 0., 1.);
|
|
|
|
assert(t1 >= 0.);
|
|
|
|
assert(t2 >= 0.);
|
|
|
|
assert(t1 <= 1.);
|
|
|
|
assert(t2 <= 1.);
|
|
|
|
|
|
|
|
Point p1 = projection_l.a + (t1 * v1).cast<coord_t>();
|
|
|
|
Point p2 = projection_l.a + (t2 * v1).cast<coord_t>();
|
|
|
|
*new_projected = Line(p1, p2);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PaintedLine
|
|
|
|
{
|
|
|
|
size_t contour_idx;
|
|
|
|
size_t line_idx;
|
|
|
|
Line projected_line;
|
|
|
|
int color;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PaintedLineVisitor
|
|
|
|
{
|
|
|
|
PaintedLineVisitor(const EdgeGrid::Grid &grid, std::vector<PaintedLine> &painted_lines, std::mutex &painted_lines_mutex, size_t reserve) : grid(grid), painted_lines(painted_lines), painted_lines_mutex(painted_lines_mutex)
|
|
|
|
{
|
|
|
|
painted_lines_set.reserve(reserve);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset() { painted_lines_set.clear(); }
|
|
|
|
|
|
|
|
bool operator()(coord_t iy, coord_t ix)
|
|
|
|
{
|
|
|
|
// Called with a row and column of the grid cell, which is intersected by a line.
|
|
|
|
auto cell_data_range = grid.cell_data_range(iy, ix);
|
|
|
|
const Vec2d v1 = line_to_test.vector().cast<double>();
|
|
|
|
const double v1_sqr_norm = v1.squaredNorm();
|
|
|
|
const double heuristic_thr_part = line_to_test.length() + append_threshold;
|
|
|
|
for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) {
|
|
|
|
Line grid_line = grid.line(*it_contour_and_segment);
|
|
|
|
const Vec2d v2 = grid_line.vector().cast<double>();
|
|
|
|
double heuristic_thr_sqr = Slic3r::sqr(heuristic_thr_part + grid_line.length());
|
|
|
|
|
|
|
|
// An inexpensive heuristic to test whether line_to_test and grid_line can be somewhere close enough to each other.
|
|
|
|
// This helps filter out cases when the following expensive calculations are useless.
|
|
|
|
if ((grid_line.a - line_to_test.a).cast<double>().squaredNorm() > heuristic_thr_sqr ||
|
|
|
|
(grid_line.b - line_to_test.a).cast<double>().squaredNorm() > heuristic_thr_sqr ||
|
|
|
|
(grid_line.a - line_to_test.b).cast<double>().squaredNorm() > heuristic_thr_sqr ||
|
|
|
|
(grid_line.b - line_to_test.b).cast<double>().squaredNorm() > heuristic_thr_sqr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// When lines have too different length, it is necessary to normalize them
|
|
|
|
if (Slic3r::sqr(v1.dot(v2)) > cos_threshold2 * v1_sqr_norm * v2.squaredNorm()) {
|
|
|
|
// The two vectors are nearly collinear (their mutual angle is lower than 30 degrees)
|
|
|
|
if (painted_lines_set.find(*it_contour_and_segment) == painted_lines_set.end()) {
|
|
|
|
if (grid_line.distance_to_squared(line_to_test.a) < append_threshold2 ||
|
|
|
|
grid_line.distance_to_squared(line_to_test.b) < append_threshold2 ||
|
|
|
|
line_to_test.distance_to_squared(grid_line.a) < append_threshold2 ||
|
|
|
|
line_to_test.distance_to_squared(grid_line.b) < append_threshold2) {
|
|
|
|
Line line_to_test_projected;
|
|
|
|
project_line_on_line(grid_line, line_to_test, &line_to_test_projected);
|
|
|
|
|
|
|
|
if ((line_to_test_projected.a - grid_line.a).cast<double>().squaredNorm() > (line_to_test_projected.b - grid_line.a).cast<double>().squaredNorm())
|
|
|
|
line_to_test_projected.reverse();
|
|
|
|
|
|
|
|
painted_lines_set.insert(*it_contour_and_segment);
|
|
|
|
{
|
|
|
|
boost::lock_guard<std::mutex> lock(painted_lines_mutex);
|
|
|
|
painted_lines.push_back({it_contour_and_segment->first, it_contour_and_segment->second, line_to_test_projected, this->color});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Continue traversing the grid along the edge.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const EdgeGrid::Grid &grid;
|
|
|
|
std::vector<PaintedLine> &painted_lines;
|
|
|
|
std::mutex &painted_lines_mutex;
|
|
|
|
Line line_to_test;
|
|
|
|
std::unordered_set<std::pair<size_t, size_t>, boost::hash<std::pair<size_t, size_t>>> painted_lines_set;
|
|
|
|
int color = -1;
|
|
|
|
|
|
|
|
static inline const double cos_threshold2 = Slic3r::sqr(cos(M_PI * 30. / 180.));
|
|
|
|
static inline const double append_threshold = 50 * SCALED_EPSILON;
|
|
|
|
static inline const double append_threshold2 = Slic3r::sqr(append_threshold);
|
|
|
|
};
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BoundingBox get_extents(const std::vector<ColoredLines> &colored_polygons) {
|
|
|
|
BoundingBox bbox;
|
|
|
|
for (const ColoredLines &colored_lines : colored_polygons) {
|
|
|
|
for (const ColoredLine &colored_line : colored_lines) {
|
|
|
|
bbox.merge(colored_line.line.a);
|
|
|
|
bbox.merge(colored_line.line.b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bbox;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flatten the vector of vectors into a vector.
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static inline ColoredLines to_lines(const std::vector<ColoredLines> &c_lines)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
size_t n_lines = 0;
|
|
|
|
for (const auto &c_line : c_lines)
|
|
|
|
n_lines += c_line.size();
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
ColoredLines lines;
|
2022-07-15 15:37:19 +00:00
|
|
|
lines.reserve(n_lines);
|
|
|
|
for (const auto &c_line : c_lines)
|
|
|
|
lines.insert(lines.end(), c_line.begin(), c_line.end());
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static std::vector<std::pair<size_t, size_t>> get_segments(const ColoredLines &polygon)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
std::vector<std::pair<size_t, size_t>> segments;
|
|
|
|
|
|
|
|
size_t segment_end = 0;
|
|
|
|
while (segment_end + 1 < polygon.size() && polygon[segment_end].color == polygon[segment_end + 1].color)
|
|
|
|
segment_end++;
|
|
|
|
|
|
|
|
if (segment_end == polygon.size() - 1)
|
|
|
|
return {std::make_pair(0, polygon.size() - 1)};
|
|
|
|
|
|
|
|
size_t first_different_color = (segment_end + 1) % polygon.size();
|
|
|
|
for (size_t line_offset_idx = 0; line_offset_idx < polygon.size(); ++line_offset_idx) {
|
|
|
|
size_t start_s = (first_different_color + line_offset_idx) % polygon.size();
|
|
|
|
size_t end_s = start_s;
|
|
|
|
|
|
|
|
while (line_offset_idx + 1 < polygon.size() && polygon[start_s].color == polygon[(first_different_color + line_offset_idx + 1) % polygon.size()].color) {
|
|
|
|
end_s = (first_different_color + line_offset_idx + 1) % polygon.size();
|
|
|
|
line_offset_idx++;
|
|
|
|
}
|
|
|
|
segments.emplace_back(start_s, end_s);
|
|
|
|
}
|
|
|
|
return segments;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<PaintedLine> filter_painted_lines(const Line &line_to_process, const size_t start_idx, const size_t end_idx, const std::vector<PaintedLine> &painted_lines)
|
|
|
|
{
|
|
|
|
const int filter_eps_value = scale_(0.1f);
|
|
|
|
std::vector<PaintedLine> filtered_lines;
|
|
|
|
filtered_lines.emplace_back(painted_lines[start_idx]);
|
|
|
|
for (size_t line_idx = start_idx + 1; line_idx <= end_idx; ++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();
|
|
|
|
const PaintedLine &curr = painted_lines[line_idx];
|
|
|
|
|
|
|
|
double prev_length = prev.projected_line.length();
|
|
|
|
double curr_dist_start = (curr.projected_line.a - prev.projected_line.a).cast<double>().norm();
|
|
|
|
double dist_between_lines = curr_dist_start - prev_length;
|
|
|
|
|
|
|
|
if (dist_between_lines >= 0) {
|
|
|
|
if (prev.color == curr.color) {
|
|
|
|
if (dist_between_lines <= filter_eps_value) {
|
|
|
|
prev.projected_line.b = curr.projected_line.b;
|
|
|
|
} else {
|
|
|
|
filtered_lines.emplace_back(curr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
filtered_lines.emplace_back(curr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
double curr_dist_end = (curr.projected_line.b - prev.projected_line.a).cast<double>().norm();
|
|
|
|
if (curr_dist_end > prev_length) {
|
|
|
|
if (prev.color == curr.color)
|
|
|
|
prev.projected_line.b = curr.projected_line.b;
|
|
|
|
else
|
|
|
|
filtered_lines.push_back({curr.contour_idx, curr.line_idx, Line{prev.projected_line.b, curr.projected_line.b}, curr.color});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (double dist_to_start = (filtered_lines.front().projected_line.a - line_to_process.a).cast<double>().norm(); dist_to_start <= filter_eps_value)
|
|
|
|
filtered_lines.front().projected_line.a = line_to_process.a;
|
|
|
|
|
|
|
|
if (double dist_to_end = (filtered_lines.back().projected_line.b - line_to_process.b).cast<double>().norm(); dist_to_end <= filter_eps_value)
|
|
|
|
filtered_lines.back().projected_line.b = line_to_process.b;
|
|
|
|
|
|
|
|
return filtered_lines;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<std::vector<PaintedLine>> post_process_painted_lines(const std::vector<EdgeGrid::Contour> &contours, std::vector<PaintedLine> &&painted_lines)
|
|
|
|
{
|
|
|
|
if (painted_lines.empty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto comp = [&contours](const PaintedLine &first, const PaintedLine &second) {
|
|
|
|
Point first_start_p = contours[first.contour_idx].segment_start(first.line_idx);
|
|
|
|
return 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.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.begin(), painted_lines.end(), comp);
|
|
|
|
|
|
|
|
std::vector<std::vector<PaintedLine>> filtered_painted_lines(contours.size());
|
|
|
|
size_t prev_painted_line_idx = 0;
|
|
|
|
for (size_t curr_painted_line_idx = 0; curr_painted_line_idx < painted_lines.size(); ++curr_painted_line_idx) {
|
|
|
|
size_t next_painted_line_idx = curr_painted_line_idx + 1;
|
|
|
|
if (next_painted_line_idx >= painted_lines.size() || painted_lines[curr_painted_line_idx].contour_idx != painted_lines[next_painted_line_idx].contour_idx || painted_lines[curr_painted_line_idx].line_idx != painted_lines[next_painted_line_idx].line_idx) {
|
|
|
|
const PaintedLine &start_line = painted_lines[prev_painted_line_idx];
|
|
|
|
const Line &line_to_process = contours[start_line.contour_idx].get_segment(start_line.line_idx);
|
|
|
|
Slic3r::append(filtered_painted_lines[painted_lines[curr_painted_line_idx].contour_idx], filter_painted_lines(line_to_process, prev_painted_line_idx, curr_painted_line_idx, painted_lines));
|
|
|
|
prev_painted_line_idx = next_painted_line_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return filtered_painted_lines;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static bool are_lines_connected(const ColoredLines &colored_lines)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
for (size_t line_idx = 1; line_idx < colored_lines.size(); ++line_idx)
|
|
|
|
if (colored_lines[line_idx - 1].line.b != colored_lines[line_idx].line.a)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static ColoredLines colorize_line(const Line &line_to_process,
|
2022-07-15 15:37:19 +00:00
|
|
|
const size_t start_idx,
|
|
|
|
const size_t end_idx,
|
|
|
|
const std::vector<PaintedLine> &painted_contour)
|
|
|
|
{
|
|
|
|
assert(start_idx < painted_contour.size() && end_idx < painted_contour.size() && start_idx <= end_idx);
|
|
|
|
assert(std::all_of(painted_contour.begin() + start_idx, painted_contour.begin() + end_idx + 1, [&painted_contour, &start_idx](const auto &p_line) { return painted_contour[start_idx].line_idx == p_line.line_idx; }));
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
const int filter_eps_value = scale_(0.1f);
|
|
|
|
ColoredLines final_lines;
|
|
|
|
const PaintedLine &first_line = painted_contour[start_idx];
|
2022-07-15 15:37:19 +00:00
|
|
|
if (double dist_to_start = (first_line.projected_line.a - line_to_process.a).cast<double>().norm(); dist_to_start > filter_eps_value)
|
|
|
|
final_lines.push_back({Line(line_to_process.a, first_line.projected_line.a), 0});
|
|
|
|
final_lines.push_back({first_line.projected_line, first_line.color});
|
|
|
|
|
|
|
|
for (size_t line_idx = start_idx + 1; line_idx <= end_idx; ++line_idx) {
|
|
|
|
ColoredLine &prev = final_lines.back();
|
|
|
|
const PaintedLine &curr = painted_contour[line_idx];
|
|
|
|
|
|
|
|
double line_dist = (curr.projected_line.a - prev.line.b).cast<double>().norm();
|
|
|
|
if (line_dist <= filter_eps_value) {
|
|
|
|
if (prev.color == curr.color) {
|
|
|
|
prev.line.b = curr.projected_line.b;
|
|
|
|
} else {
|
|
|
|
prev.line.b = curr.projected_line.a;
|
|
|
|
final_lines.push_back({curr.projected_line, curr.color});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
final_lines.push_back({Line(prev.line.b, curr.projected_line.a), 0});
|
|
|
|
final_lines.push_back({curr.projected_line, curr.color});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is non-painted space, then inserts line painted by a default color.
|
|
|
|
if (double dist_to_end = (final_lines.back().line.b - line_to_process.b).cast<double>().norm(); dist_to_end > filter_eps_value)
|
|
|
|
final_lines.push_back({Line(final_lines.back().line.b, line_to_process.b), 0});
|
|
|
|
|
|
|
|
// Make sure all the lines are connected.
|
|
|
|
assert(are_lines_connected(final_lines));
|
|
|
|
|
|
|
|
for (size_t line_idx = 2; line_idx < final_lines.size(); ++line_idx) {
|
|
|
|
const ColoredLine &line_0 = final_lines[line_idx - 2];
|
|
|
|
ColoredLine &line_1 = final_lines[line_idx - 1];
|
|
|
|
const ColoredLine &line_2 = final_lines[line_idx - 0];
|
|
|
|
|
|
|
|
if (line_0.color == line_2.color && line_0.color != line_1.color)
|
|
|
|
if (line_1.line.length() <= scale_(0.2)) line_1.color = line_0.color;
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
ColoredLines colored_lines_simple;
|
2022-07-15 15:37:19 +00:00
|
|
|
colored_lines_simple.emplace_back(final_lines.front());
|
|
|
|
for (size_t line_idx = 1; line_idx < final_lines.size(); ++line_idx) {
|
|
|
|
const ColoredLine &line_0 = final_lines[line_idx];
|
|
|
|
|
|
|
|
if (colored_lines_simple.back().color == line_0.color)
|
|
|
|
colored_lines_simple.back().line.b = line_0.line.b;
|
|
|
|
else
|
|
|
|
colored_lines_simple.emplace_back(line_0);
|
|
|
|
}
|
|
|
|
|
|
|
|
final_lines = colored_lines_simple;
|
|
|
|
|
|
|
|
if (final_lines.size() > 1)
|
|
|
|
if (final_lines.front().color != final_lines[1].color && final_lines.front().line.length() <= scale_(0.2)) {
|
|
|
|
final_lines[1].line.a = final_lines.front().line.a;
|
|
|
|
final_lines.erase(final_lines.begin());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (final_lines.size() > 1)
|
|
|
|
if (final_lines.back().color != final_lines[final_lines.size() - 2].color && final_lines.back().line.length() <= scale_(0.2)) {
|
|
|
|
final_lines[final_lines.size() - 2].line.b = final_lines.back().line.b;
|
|
|
|
final_lines.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
return final_lines;
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static ColoredLines filter_colorized_polygon(ColoredLines &&new_lines) {
|
2022-07-15 15:37:19 +00:00
|
|
|
for (size_t line_idx = 2; line_idx < new_lines.size(); ++line_idx) {
|
|
|
|
const ColoredLine &line_0 = new_lines[line_idx - 2];
|
|
|
|
ColoredLine &line_1 = new_lines[line_idx - 1];
|
|
|
|
const ColoredLine &line_2 = new_lines[line_idx - 0];
|
|
|
|
|
|
|
|
if (line_0.color == line_2.color && line_0.color != line_1.color && line_0.color >= 1) {
|
|
|
|
if (line_1.line.length() <= scale_(0.5)) line_1.color = line_0.color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t line_idx = 3; line_idx < new_lines.size(); ++line_idx) {
|
|
|
|
const ColoredLine &line_0 = new_lines[line_idx - 3];
|
|
|
|
ColoredLine &line_1 = new_lines[line_idx - 2];
|
|
|
|
ColoredLine &line_2 = new_lines[line_idx - 1];
|
|
|
|
const ColoredLine &line_3 = new_lines[line_idx - 0];
|
|
|
|
|
|
|
|
if (line_0.color == line_3.color && (line_0.color != line_1.color || line_0.color != line_2.color) && line_0.color >= 1 && line_3.color >= 1) {
|
|
|
|
if ((line_1.line.length() + line_2.line.length()) <= scale_(0.5)) {
|
|
|
|
line_1.color = line_0.color;
|
|
|
|
line_2.color = line_0.color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::pair<size_t, size_t>> segments = get_segments(new_lines);
|
|
|
|
auto segment_length = [&new_lines](const std::pair<size_t, size_t> &segment) {
|
|
|
|
double total_length = 0;
|
|
|
|
for (size_t seg_start_idx = segment.first; seg_start_idx != segment.second; seg_start_idx = (seg_start_idx + 1 < new_lines.size()) ? seg_start_idx + 1 : 0)
|
|
|
|
total_length += new_lines[seg_start_idx].line.length();
|
|
|
|
total_length += new_lines[segment.second].line.length();
|
|
|
|
return total_length;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (segments.size() >= 2)
|
|
|
|
for (size_t curr_idx = 0; curr_idx < segments.size(); ++curr_idx) {
|
|
|
|
size_t next_idx = next_idx_modulo(curr_idx, segments.size());
|
|
|
|
assert(curr_idx != next_idx);
|
|
|
|
|
|
|
|
int color0 = new_lines[segments[curr_idx].first].color;
|
|
|
|
int color1 = new_lines[segments[next_idx].first].color;
|
|
|
|
|
|
|
|
double seg0l = segment_length(segments[curr_idx]);
|
|
|
|
double seg1l = segment_length(segments[next_idx]);
|
|
|
|
|
|
|
|
if (color0 != color1 && seg0l >= scale_(0.1) && seg1l <= scale_(0.2)) {
|
|
|
|
for (size_t seg_start_idx = segments[next_idx].first; seg_start_idx != segments[next_idx].second; seg_start_idx = (seg_start_idx + 1 < new_lines.size()) ? seg_start_idx + 1 : 0)
|
|
|
|
new_lines[seg_start_idx].color = color0;
|
|
|
|
new_lines[segments[next_idx].second].color = color0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
segments = get_segments(new_lines);
|
|
|
|
if (segments.size() >= 2)
|
|
|
|
for (size_t curr_idx = 0; curr_idx < segments.size(); ++curr_idx) {
|
|
|
|
size_t next_idx = next_idx_modulo(curr_idx, segments.size());
|
|
|
|
assert(curr_idx != next_idx);
|
|
|
|
|
|
|
|
int color0 = new_lines[segments[curr_idx].first].color;
|
|
|
|
int color1 = new_lines[segments[next_idx].first].color;
|
|
|
|
double seg1l = segment_length(segments[next_idx]);
|
|
|
|
|
|
|
|
if (color0 >= 1 && color0 != color1 && seg1l <= scale_(0.2)) {
|
|
|
|
for (size_t seg_start_idx = segments[next_idx].first; seg_start_idx != segments[next_idx].second; seg_start_idx = (seg_start_idx + 1 < new_lines.size()) ? seg_start_idx + 1 : 0)
|
|
|
|
new_lines[seg_start_idx].color = color0;
|
|
|
|
new_lines[segments[next_idx].second].color = color0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
segments = get_segments(new_lines);
|
|
|
|
if (segments.size() >= 3)
|
|
|
|
for (size_t curr_idx = 0; curr_idx < segments.size(); ++curr_idx) {
|
|
|
|
size_t next_idx = next_idx_modulo(curr_idx, segments.size());
|
|
|
|
size_t next_next_idx = next_idx_modulo(next_idx, segments.size());
|
|
|
|
|
|
|
|
int color0 = new_lines[segments[curr_idx].first].color;
|
|
|
|
int color1 = new_lines[segments[next_idx].first].color;
|
|
|
|
int color2 = new_lines[segments[next_next_idx].first].color;
|
|
|
|
|
|
|
|
if (color0 > 0 && color0 == color2 && color0 != color1 && segment_length(segments[next_idx]) <= scale_(0.5)) {
|
|
|
|
for (size_t seg_start_idx = segments[next_next_idx].first; seg_start_idx != segments[next_next_idx].second; seg_start_idx = (seg_start_idx + 1 < new_lines.size()) ? seg_start_idx + 1 : 0)
|
|
|
|
new_lines[seg_start_idx].color = color0;
|
|
|
|
new_lines[segments[next_next_idx].second].color = color0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::move(new_lines);
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static ColoredLines colorize_contour(const EdgeGrid::Contour &contour, const std::vector<PaintedLine> &painted_contour) {
|
2022-07-15 15:37:19 +00:00
|
|
|
assert(painted_contour.empty() || std::all_of(painted_contour.begin(), painted_contour.end(), [&painted_contour](const auto &p_line) { return painted_contour.front().contour_idx == p_line.contour_idx; }));
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
ColoredLines colorized_contour;
|
2022-07-15 15:37:19 +00:00
|
|
|
if (painted_contour.empty()) {
|
|
|
|
// Appends contour with default color for lines before the first PaintedLine.
|
|
|
|
colorized_contour.reserve(contour.num_segments());
|
|
|
|
for (const Line &line : contour.get_segments())
|
|
|
|
colorized_contour.emplace_back(ColoredLine{line, 0});
|
|
|
|
return colorized_contour;
|
|
|
|
}
|
|
|
|
|
|
|
|
colorized_contour.reserve(contour.num_segments() + painted_contour.size());
|
|
|
|
for (size_t idx = 0; idx < painted_contour.front().line_idx; ++idx)
|
|
|
|
colorized_contour.emplace_back(ColoredLine{contour.get_segment(idx), 0});
|
|
|
|
|
|
|
|
size_t prev_painted_line_idx = 0;
|
|
|
|
for (size_t curr_painted_line_idx = 0; curr_painted_line_idx < painted_contour.size(); ++curr_painted_line_idx) {
|
|
|
|
size_t next_painted_line_idx = curr_painted_line_idx + 1;
|
|
|
|
if (next_painted_line_idx >= painted_contour.size() || painted_contour[curr_painted_line_idx].line_idx != painted_contour[next_painted_line_idx].line_idx) {
|
|
|
|
const std::vector<PaintedLine> &painted_contour_copy = painted_contour;
|
|
|
|
Slic3r::append(colorized_contour, colorize_line(contour.get_segment(painted_contour[prev_painted_line_idx].line_idx), prev_painted_line_idx, curr_painted_line_idx, painted_contour_copy));
|
|
|
|
|
|
|
|
// Appends contour with default color for lines between the current and the next PaintedLine.
|
|
|
|
if (next_painted_line_idx < painted_contour.size())
|
|
|
|
for (size_t idx = painted_contour[curr_painted_line_idx].line_idx + 1; idx < painted_contour[next_painted_line_idx].line_idx; ++idx)
|
|
|
|
colorized_contour.emplace_back(ColoredLine{contour.get_segment(idx), 0});
|
|
|
|
|
|
|
|
prev_painted_line_idx = next_painted_line_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Appends contour with default color for lines after the last PaintedLine.
|
|
|
|
for (size_t idx = painted_contour.back().line_idx + 1; idx < contour.num_segments(); ++idx)
|
|
|
|
colorized_contour.emplace_back(ColoredLine{contour.get_segment(idx), 0});
|
|
|
|
|
|
|
|
assert(!colorized_contour.empty());
|
|
|
|
return filter_colorized_polygon(std::move(colorized_contour));
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static std::vector<ColoredLines> colorize_contours(const std::vector<EdgeGrid::Contour> &contours, const std::vector<std::vector<PaintedLine>> &painted_contours)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
assert(contours.size() == painted_contours.size());
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
std::vector<ColoredLines> colorized_contours(contours.size());
|
2022-07-15 15:37:19 +00:00
|
|
|
for (const std::vector<PaintedLine> &painted_contour : painted_contours) {
|
|
|
|
size_t contour_idx = &painted_contour - &painted_contours.front();
|
|
|
|
colorized_contours[contour_idx] = colorize_contour(contours[contour_idx], painted_contours[contour_idx]);
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
size_t poly_idx = 0;
|
|
|
|
for (ColoredLines &color_lines : colorized_contours) {
|
|
|
|
size_t line_idx = 0;
|
|
|
|
for (size_t color_line_idx = 0; color_line_idx < color_lines.size(); ++color_line_idx) {
|
|
|
|
color_lines[color_line_idx].poly_idx = int(poly_idx);
|
|
|
|
color_lines[color_line_idx].local_line_idx = int(line_idx);
|
|
|
|
++line_idx;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
++poly_idx;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
return colorized_contours;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determines if the line points from the point between two contour lines is pointing inside polygon or outside.
|
|
|
|
static inline bool points_inside(const Line &contour_first, const Line &contour_second, const Point &new_point)
|
|
|
|
{
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// TODO: Used in points_inside for decision if line leading thought the common point of two lines is pointing inside polygon or outside
|
2022-07-15 15:37:19 +00:00
|
|
|
auto three_points_inward_normal = [](const Point &left, const Point &middle, const Point &right) -> Vec2d {
|
|
|
|
assert(left != middle);
|
|
|
|
assert(middle != right);
|
|
|
|
return (perp(Point(middle - left)).cast<double>().normalized() + perp(Point(right - middle)).cast<double>().normalized()).normalized();
|
|
|
|
};
|
|
|
|
|
|
|
|
assert(contour_first.b == contour_second.a);
|
|
|
|
Vec2d inward_normal = three_points_inward_normal(contour_first.a, contour_first.b, contour_second.b);
|
|
|
|
Vec2d edge_norm = (new_point - contour_first.b).cast<double>().normalized();
|
|
|
|
double side = inward_normal.dot(edge_norm);
|
|
|
|
// assert(side != 0.);
|
|
|
|
return side > 0.;
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
enum VD_ANNOTATION : Voronoi::VD::cell_type::color_type {
|
|
|
|
VERTEX_ON_CONTOUR = 1,
|
|
|
|
DELETED = 2
|
|
|
|
};
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_GRAPH
|
|
|
|
static void export_graph_to_svg(const std::string &path, const Voronoi::VD& vd, const std::vector<ColoredLines>& colored_polygons) {
|
|
|
|
const coordf_t stroke_width = scaled<coordf_t>(0.05f);
|
|
|
|
const BoundingBox bbox = get_extents(colored_polygons);
|
|
|
|
|
|
|
|
SVG svg(path.c_str(), bbox);
|
|
|
|
for (const ColoredLines &colored_lines : colored_polygons)
|
|
|
|
for (const ColoredLine &colored_line : colored_lines)
|
|
|
|
svg.draw(colored_line.line, "black", stroke_width);
|
|
|
|
|
|
|
|
for (const Voronoi::VD::vertex_type &vertex : vd.vertices()) {
|
|
|
|
if (Geometry::VoronoiUtils::is_in_range<coord_t>(vertex)) {
|
|
|
|
if (const Point pt = Geometry::VoronoiUtils::to_point(&vertex).cast<coord_t>(); vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR) {
|
|
|
|
svg.draw(pt, "blue", coord_t(stroke_width));
|
|
|
|
} else if (vertex.color() != VD_ANNOTATION::DELETED) {
|
|
|
|
svg.draw(pt, "green", coord_t(stroke_width));
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const Voronoi::VD::edge_type &edge : vd.edges()) {
|
|
|
|
if (edge.is_infinite() || !Geometry::VoronoiUtils::is_in_range<coord_t>(edge))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const Point from = Geometry::VoronoiUtils::to_point(edge.vertex0()).cast<coord_t>();
|
|
|
|
const Point to = Geometry::VoronoiUtils::to_point(edge.vertex1()).cast<coord_t>();
|
|
|
|
|
|
|
|
if (edge.color() != VD_ANNOTATION::DELETED)
|
|
|
|
svg.draw(Line(from, to), "red", stroke_width);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_GRAPH
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static size_t non_deleted_edge_count(const VD::vertex_type &vertex) {
|
|
|
|
size_t non_deleted_edge_cnt = 0;
|
|
|
|
const VD::edge_type *edge = vertex.incident_edge();
|
|
|
|
do {
|
|
|
|
if (edge->color() != VD_ANNOTATION::DELETED)
|
|
|
|
++non_deleted_edge_cnt;
|
|
|
|
} while (edge = edge->prev()->twin(), edge != vertex.incident_edge());
|
|
|
|
|
|
|
|
return non_deleted_edge_cnt;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static bool can_vertex_be_deleted(const VD::vertex_type &vertex) {
|
|
|
|
if (vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR || vertex.color() == VD_ANNOTATION::DELETED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return non_deleted_edge_count(vertex) <= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void delete_vertex_deep(const VD::vertex_type &vertex) {
|
|
|
|
std::queue<const VD::vertex_type *> vertices_to_delete;
|
|
|
|
vertices_to_delete.emplace(&vertex);
|
|
|
|
|
|
|
|
while (!vertices_to_delete.empty()) {
|
|
|
|
const VD::vertex_type &vertex_to_delete = *vertices_to_delete.front();
|
|
|
|
vertices_to_delete.pop();
|
|
|
|
vertex_to_delete.color(VD_ANNOTATION::DELETED);
|
|
|
|
|
|
|
|
const VD::edge_type *edge = vertex_to_delete.incident_edge();
|
|
|
|
do {
|
|
|
|
edge->color(VD_ANNOTATION::DELETED);
|
|
|
|
edge->twin()->color(VD_ANNOTATION::DELETED);
|
|
|
|
|
|
|
|
if (edge->is_finite() && can_vertex_be_deleted(*edge->vertex1()))
|
|
|
|
vertices_to_delete.emplace(edge->vertex1());
|
|
|
|
} while (edge = edge->prev()->twin(), edge != vertex_to_delete.incident_edge());
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static inline Vec2d mk_point_vec2d(const VD::vertex_type *point) {
|
|
|
|
assert(point != nullptr);
|
|
|
|
return {point->x(), point->y()};
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static inline Vec2d mk_vector_vec2d(const VD::edge_type *edge) {
|
|
|
|
assert(edge != nullptr);
|
|
|
|
return mk_point_vec2d(edge->vertex1()) - mk_point_vec2d(edge->vertex0());
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static inline Vec2d mk_flipped_vector_vec2d(const VD::edge_type *edge) {
|
|
|
|
assert(edge != nullptr);
|
|
|
|
return mk_point_vec2d(edge->vertex0()) - mk_point_vec2d(edge->vertex1());
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static double edge_length(const VD::edge_type &edge) {
|
|
|
|
assert(edge.is_finite());
|
|
|
|
return mk_vector_vec2d(&edge).norm();
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Used in remove_multiple_edges_in_vertices()
|
|
|
|
// Returns length of edge with is connected to contour. To this length is include other edges with follows it if they are almost straight (with the
|
|
|
|
// tolerance of 15) And also if node between two subsequent edges is connected only to these two edges.
|
|
|
|
static inline double calc_total_edge_length(const VD::edge_type &starting_edge)
|
|
|
|
{
|
|
|
|
double total_edge_length = edge_length(starting_edge);
|
|
|
|
const VD::edge_type *prev = &starting_edge;
|
|
|
|
do {
|
|
|
|
if (prev->is_finite() && non_deleted_edge_count(*prev->vertex1()) > 2)
|
|
|
|
break;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
bool found_next_edge = false;
|
|
|
|
const VD::edge_type *current = prev->next();
|
|
|
|
do {
|
|
|
|
if (current->color() == VD_ANNOTATION::DELETED)
|
2022-07-15 15:37:19 +00:00
|
|
|
continue;
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
Vec2d first_line_vec_n = mk_flipped_vector_vec2d(prev).normalized();
|
|
|
|
Vec2d second_line_vec_n = mk_vector_vec2d(current).normalized();
|
|
|
|
double angle = ::acos(std::clamp(first_line_vec_n.dot(second_line_vec_n), -1.0, 1.0));
|
|
|
|
if (Slic3r::cross2(first_line_vec_n, second_line_vec_n) < 0.0)
|
|
|
|
angle = 2.0 * (double) PI - angle;
|
|
|
|
|
|
|
|
if (std::abs(angle - PI) >= (PI / 12))
|
2022-07-15 15:37:19 +00:00
|
|
|
continue;
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
prev = current;
|
|
|
|
found_next_edge = true;
|
|
|
|
total_edge_length += edge_length(*current);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
break;
|
|
|
|
} while (current = current->prev()->twin(), current != prev->next());
|
2022-09-28 04:24:43 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (!found_next_edge)
|
|
|
|
break;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
} while (prev != &starting_edge);
|
2022-09-28 04:24:43 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
return total_edge_length;
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// When a Voronoi vertex has more than one Voronoi edge (for example, in concave parts of a polygon),
|
|
|
|
// we leave just one Voronoi edge in the Voronoi vertex.
|
|
|
|
// This Voronoi edge is selected based on a heuristic.
|
|
|
|
static void remove_multiple_edges_in_vertex(const VD::vertex_type &vertex) {
|
|
|
|
if (non_deleted_edge_count(vertex) <= 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::vector<std::pair<const VD::edge_type *, double>> edges_to_check;
|
|
|
|
const VD::edge_type *edge = vertex.incident_edge();
|
|
|
|
do {
|
|
|
|
if (edge->color() == VD_ANNOTATION::DELETED)
|
2022-07-15 15:37:19 +00:00
|
|
|
continue;
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
edges_to_check.emplace_back(edge, calc_total_edge_length(*edge));
|
|
|
|
} while (edge = edge->prev()->twin(), edge != vertex.incident_edge());
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
std::sort(edges_to_check.begin(), edges_to_check.end(), [](const auto &l, const auto &r) -> bool {
|
|
|
|
return l.second > r.second;
|
|
|
|
});
|
|
|
|
|
|
|
|
while (edges_to_check.size() > 1) {
|
|
|
|
const VD::edge_type &edge_to_check = *edges_to_check.back().first;
|
|
|
|
edge_to_check.color(VD_ANNOTATION::DELETED);
|
|
|
|
edge_to_check.twin()->color(VD_ANNOTATION::DELETED);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (const VD::vertex_type &vertex_to_delete = *edge_to_check.vertex1(); can_vertex_be_deleted(vertex_to_delete))
|
|
|
|
delete_vertex_deep(vertex_to_delete);
|
|
|
|
|
|
|
|
edges_to_check.pop_back();
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
2024-05-30 12:23:23 +00:00
|
|
|
#if (0)
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Returns list of ExPolygons for each extruder + 1 for default unpainted regions.
|
|
|
|
// It iterates through all nodes on the border between two different colors, and from this point,
|
|
|
|
// start selection always left most edges for every node to construct CCW polygons.
|
|
|
|
static std::vector<ExPolygons> extract_colored_segments(const std::vector<ColoredLines> &colored_polygons,
|
|
|
|
const size_t num_extruders,
|
|
|
|
const size_t layer_idx)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
const ColoredLines colored_lines = to_lines(colored_polygons);
|
|
|
|
const BoundingBox bbox = get_extents(colored_polygons);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
auto get_next_contour_line = [&colored_polygons](const ColoredLine &line) -> const ColoredLine & {
|
|
|
|
size_t contour_line_size = colored_polygons[line.poly_idx].size();
|
|
|
|
size_t contour_next_idx = (line.local_line_idx + 1) % contour_line_size;
|
|
|
|
return colored_polygons[line.poly_idx][contour_next_idx];
|
|
|
|
};
|
2022-11-22 04:23:37 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
Voronoi::VD vd;
|
|
|
|
vd.construct_voronoi(colored_lines.begin(), colored_lines.end());
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// First, mark each Voronoi vertex on the input polygon to prevent it from being deleted later.
|
|
|
|
for (const Voronoi::VD::cell_type &cell : vd.cells()) {
|
|
|
|
if (cell.is_degenerate() || !cell.contains_segment())
|
2022-11-22 04:23:37 +00:00
|
|
|
continue;
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (const Geometry::SegmentCellRange<Point> cell_range = Geometry::VoronoiUtils::compute_segment_cell_range(cell, colored_lines.begin(), colored_lines.end()); cell_range.is_valid())
|
|
|
|
cell_range.edge_begin->vertex0()->color(VD_ANNOTATION::VERTEX_ON_CONTOUR);
|
|
|
|
}
|
2022-09-28 04:24:43 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Second, remove all Voronoi vertices that are outside the bounding box of input polygons.
|
|
|
|
// Such Voronoi vertices are definitely not inside of input polygons, so we don't care about them.
|
|
|
|
for (const Voronoi::VD::vertex_type &vertex : vd.vertices()) {
|
|
|
|
if (vertex.color() == VD_ANNOTATION::DELETED || vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR)
|
2022-11-22 04:23:37 +00:00
|
|
|
continue;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (!Geometry::VoronoiUtils::is_in_range<coord_t>(vertex) || !bbox.contains(Geometry::VoronoiUtils::to_point(vertex).cast<coord_t>()))
|
|
|
|
delete_vertex_deep(vertex);
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Third, remove all Voronoi edges that are infinite.
|
|
|
|
for (const Voronoi::VD::edge_type &edge : vd.edges()) {
|
|
|
|
if (edge.color() != VD_ANNOTATION::DELETED && edge.is_infinite()) {
|
|
|
|
edge.color(VD_ANNOTATION::DELETED);
|
|
|
|
edge.twin()->color(VD_ANNOTATION::DELETED);
|
|
|
|
|
|
|
|
if (edge.vertex0() != nullptr && can_vertex_be_deleted(*edge.vertex0()))
|
|
|
|
delete_vertex_deep(*edge.vertex0());
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (edge.vertex1() != nullptr && can_vertex_be_deleted(*edge.vertex1()))
|
|
|
|
delete_vertex_deep(*edge.vertex1());
|
|
|
|
}
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Fourth, remove all edges that point outward from the input polygon.
|
|
|
|
for (Voronoi::VD::cell_type cell : vd.cells()) {
|
|
|
|
if (cell.is_degenerate() || !cell.contains_segment())
|
2022-11-22 04:23:37 +00:00
|
|
|
continue;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (const Geometry::SegmentCellRange<Point> cell_range = Geometry::VoronoiUtils::compute_segment_cell_range(cell, colored_lines.begin(), colored_lines.end()); cell_range.is_valid()) {
|
|
|
|
const ColoredLine ¤t_line = Geometry::VoronoiUtils::get_source_segment(cell, colored_lines.begin(), colored_lines.end());
|
|
|
|
const ColoredLine &next_line = get_next_contour_line(current_line);
|
2022-11-22 04:23:37 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
const VD::edge_type *edge = cell_range.edge_begin;
|
|
|
|
do {
|
|
|
|
if (edge->color() == VD_ANNOTATION::DELETED)
|
|
|
|
continue;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (!points_inside(current_line.line, next_line.line, Geometry::VoronoiUtils::to_point(edge->vertex1()).cast<coord_t>())) {
|
|
|
|
edge->color(VD_ANNOTATION::DELETED);
|
|
|
|
edge->twin()->color(VD_ANNOTATION::DELETED);
|
|
|
|
delete_vertex_deep(*edge->vertex1());
|
|
|
|
}
|
|
|
|
} while (edge = edge->prev()->twin(), edge != cell_range.edge_begin);
|
|
|
|
}
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Fifth, if a Voronoi vertex has more than one Voronoi edge, remove all but one of them based on heuristics.
|
|
|
|
for (const Voronoi::VD::vertex_type &vertex : vd.vertices()) {
|
|
|
|
if (vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR)
|
|
|
|
remove_multiple_edges_in_vertex(vertex);
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_GRAPH
|
|
|
|
{
|
|
|
|
static int iRun = 0;
|
|
|
|
export_graph_to_svg(debug_out_path("mm-graph-%d-%d.svg", layer_idx, iRun++), vd, colored_polygons);
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_GRAPH
|
2022-11-22 04:23:37 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Sixth, extract the colored segments from the annotated Voronoi diagram.
|
|
|
|
std::vector<ExPolygons> segmented_expolygons_per_extruder(num_extruders + 1);
|
|
|
|
for (const Voronoi::VD::cell_type &cell : vd.cells()) {
|
|
|
|
if (cell.is_degenerate() || !cell.contains_segment())
|
|
|
|
continue;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (const Geometry::SegmentCellRange<Point> cell_range = Geometry::VoronoiUtils::compute_segment_cell_range(cell, colored_lines.begin(), colored_lines.end()); cell_range.is_valid()) {
|
|
|
|
if (cell_range.edge_begin->vertex0()->color() != VD_ANNOTATION::VERTEX_ON_CONTOUR)
|
2022-07-15 15:37:19 +00:00
|
|
|
continue;
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
const ColoredLine source_segment = Geometry::VoronoiUtils::get_source_segment(cell, colored_lines.begin(), colored_lines.end());
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
Polygon segmented_polygon;
|
|
|
|
segmented_polygon.points.emplace_back(source_segment.line.b);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// We have ensured that each segmented_polygon have to start at edge_begin->vertex0() and end at edge_end->vertex1().
|
|
|
|
const VD::edge_type *edge = cell_range.edge_begin;
|
2022-07-15 15:37:19 +00:00
|
|
|
do {
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (edge->color() == VD_ANNOTATION::DELETED)
|
|
|
|
continue;
|
2022-11-22 04:23:37 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
const VD::vertex_type &next_vertex = *edge->vertex1();
|
|
|
|
segmented_polygon.points.emplace_back(Geometry::VoronoiUtils::to_point(next_vertex).cast<coord_t>());
|
|
|
|
edge->color(VD_ANNOTATION::DELETED);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (next_vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR || next_vertex.color() == VD_ANNOTATION::DELETED) {
|
|
|
|
assert(next_vertex.color() == VD_ANNOTATION::VERTEX_ON_CONTOUR);
|
|
|
|
break;
|
2022-11-22 04:23:37 +00:00
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
edge = edge->twin();
|
|
|
|
} while (edge = edge->twin()->next(), edge != cell_range.edge_begin);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (edge->vertex1() != cell_range.edge_end->vertex1())
|
|
|
|
continue;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
cell_range.edge_begin->vertex0()->color(VD_ANNOTATION::DELETED);
|
|
|
|
segmented_expolygons_per_extruder[source_segment.color].emplace_back(std::move(segmented_polygon));
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
// Merge all polygons together for each extruder
|
|
|
|
for (auto &segmented_expolygons : segmented_expolygons_per_extruder)
|
|
|
|
segmented_expolygons = union_ex(segmented_expolygons);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
return segmented_expolygons_per_extruder;
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
2024-05-30 12:23:23 +00:00
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
static void cut_segmented_layers(const std::vector<ExPolygons> &input_expolygons,
|
|
|
|
std::vector<std::vector<ExPolygons>> &segmented_regions,
|
|
|
|
const float cut_width,
|
2023-09-01 03:27:35 +00:00
|
|
|
const float interlocking_depth,
|
2022-07-15 15:37:19 +00:00
|
|
|
const std::function<void()> &throw_on_cancel_callback)
|
|
|
|
{
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - cutting segmented layers in parallel - begin";
|
|
|
|
const float interlocking_cut_width = interlocking_depth > 0.f ? std::max(cut_width - interlocking_depth, 0.f) : 0.f;
|
2024-05-21 06:49:14 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, segmented_regions.size()),
|
|
|
|
[&segmented_regions, &input_expolygons, &cut_width, &interlocking_depth, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
2022-07-15 15:37:19 +00:00
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
2024-05-21 06:49:14 +00:00
|
|
|
const float region_cut_width = ((layer_idx % 2 == 0) && (interlocking_depth != 0.f)) ? interlocking_depth : cut_width;
|
2023-09-01 03:27:35 +00:00
|
|
|
const size_t num_extruders_plus_one = segmented_regions[layer_idx].size();
|
|
|
|
if (region_cut_width > 0.f) {
|
|
|
|
std::vector<ExPolygons> segmented_regions_cuts(num_extruders_plus_one); // Indexed by extruder_id
|
|
|
|
for (size_t extruder_idx = 0; extruder_idx < num_extruders_plus_one; ++extruder_idx)
|
|
|
|
if (const ExPolygons &ex_polygons = segmented_regions[layer_idx][extruder_idx]; !ex_polygons.empty())
|
|
|
|
segmented_regions_cuts[extruder_idx] = diff_ex(ex_polygons, offset_ex(input_expolygons[layer_idx], -region_cut_width));
|
|
|
|
segmented_regions[layer_idx] = std::move(segmented_regions_cuts);
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}); // end of parallel_for
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - cutting segmented layers in parallel - end";
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_volume_sinking(const indexed_triangle_set &its, const Transform3d &trafo)
|
|
|
|
{
|
|
|
|
const Transform3f trafo_f = trafo.cast<float>();
|
|
|
|
for (const stl_vertex &vertex : its.vertices)
|
|
|
|
if ((trafo_f * vertex).z() < SINKING_Z_THRESHOLD) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//#define MMU_SEGMENTATION_DEBUG_TOP_BOTTOM
|
|
|
|
|
|
|
|
// Returns MMU segmentation of top and bottom layers based on painting in MMU segmentation gizmo
|
|
|
|
static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bottom_layers(const PrintObject &print_object,
|
|
|
|
const std::vector<ExPolygons> &input_expolygons,
|
|
|
|
const std::function<void()> &throw_on_cancel_callback)
|
|
|
|
{
|
|
|
|
// BBS
|
|
|
|
const size_t num_extruders = print_object.print()->config().filament_colour.size() + 1;
|
|
|
|
const size_t num_layers = input_expolygons.size();
|
|
|
|
const ConstLayerPtrsAdaptor layers = print_object.layers();
|
|
|
|
|
|
|
|
// Maximum number of top / bottom layers accounts for maximum overlap of one thread group into a neighbor thread group.
|
|
|
|
int max_top_layers = 0;
|
|
|
|
int max_bottom_layers = 0;
|
|
|
|
int granularity = 1;
|
|
|
|
for (size_t i = 0; i < print_object.num_printing_regions(); ++ i) {
|
|
|
|
const PrintRegionConfig &config = print_object.printing_region(i).config();
|
2025-02-26 06:19:24 +00:00
|
|
|
max_top_layers = std::max(max_top_layers, config.top_color_penetration_layers.value);
|
|
|
|
max_bottom_layers = std::max(max_bottom_layers, config.bottom_color_penetration_layers.value);
|
|
|
|
granularity = std::max(granularity, std::max(config.top_color_penetration_layers.value, config.bottom_color_penetration_layers.value) - 1);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Project upwards pointing painted triangles over top surfaces,
|
|
|
|
// project downards pointing painted triangles over bottom surfaces.
|
|
|
|
std::vector<std::vector<Polygons>> top_raw(num_extruders), bottom_raw(num_extruders);
|
|
|
|
std::vector<float> zs = zs_from_layers(layers);
|
|
|
|
Transform3d object_trafo = print_object.trafo_centered();
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
static int iRun = 0;
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
if (max_top_layers > 0 || max_bottom_layers > 0) {
|
|
|
|
for (const ModelVolume *mv : print_object.model_object()->volumes)
|
|
|
|
if (mv->is_model_part()) {
|
|
|
|
const Transform3d volume_trafo = object_trafo * mv->get_matrix();
|
|
|
|
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++ extruder_idx) {
|
|
|
|
const indexed_triangle_set painted = mv->mmu_segmentation_facets.get_facets_strict(*mv, EnforcerBlockerType(extruder_idx));
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
static int iRun = 0;
|
|
|
|
its_write_obj(painted, debug_out_path("mm-painted-patch-%d-%d.obj", iRun ++, extruder_idx).c_str());
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
if (! painted.indices.empty()) {
|
|
|
|
std::vector<Polygons> top, bottom;
|
|
|
|
if (!zs.empty() && is_volume_sinking(painted, volume_trafo)) {
|
|
|
|
std::vector<float> zs_sinking = {0.f};
|
|
|
|
Slic3r::append(zs_sinking, zs);
|
2024-03-21 08:43:45 +00:00
|
|
|
slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2024-08-27 03:28:36 +00:00
|
|
|
if (top.size() > 0)
|
|
|
|
top.erase(top.begin());
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2024-08-27 03:28:36 +00:00
|
|
|
if (bottom.size() > 1) {
|
|
|
|
MeshSlicingParams slicing_params;
|
|
|
|
slicing_params.trafo = volume_trafo;
|
|
|
|
Polygons bottom_slice = slice_mesh(painted, zs[0], slicing_params);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2024-08-27 03:28:36 +00:00
|
|
|
bottom.erase(bottom.begin());
|
|
|
|
bottom[0] = union_(bottom[0], bottom_slice);
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
} else
|
2024-03-21 08:43:45 +00:00
|
|
|
slice_mesh_slabs(painted, zs, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback);
|
2022-07-15 15:37:19 +00:00
|
|
|
auto merge = [](std::vector<Polygons> &&src, std::vector<Polygons> &dst) {
|
|
|
|
auto it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); });
|
|
|
|
if (it_src != src.end()) {
|
|
|
|
if (dst.empty()) {
|
|
|
|
dst = std::move(src);
|
|
|
|
} else {
|
|
|
|
assert(src.size() == dst.size());
|
|
|
|
auto it_dst = dst.begin() + (it_src - src.begin());
|
|
|
|
for (; it_src != src.end(); ++ it_src, ++ it_dst)
|
|
|
|
if (! it_src->empty()) {
|
|
|
|
if (it_dst->empty())
|
|
|
|
*it_dst = std::move(*it_src);
|
|
|
|
else
|
|
|
|
append(*it_dst, std::move(*it_src));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
merge(std::move(top), top_raw[extruder_idx]);
|
|
|
|
merge(std::move(bottom), bottom_raw[extruder_idx]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto filter_out_small_polygons = [&num_extruders, &num_layers](std::vector<std::vector<Polygons>> &raw_surfaces, double min_area) -> void {
|
|
|
|
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx)
|
|
|
|
if (!raw_surfaces[extruder_idx].empty())
|
|
|
|
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx)
|
|
|
|
if (!raw_surfaces[extruder_idx][layer_idx].empty())
|
|
|
|
remove_small(raw_surfaces[extruder_idx][layer_idx], min_area);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Filter out polygons less than 0.1mm^2, because they are unprintable and causing dimples on outer primers (#7104)
|
|
|
|
filter_out_small_polygons(top_raw, Slic3r::sqr(scale_(0.1f)));
|
|
|
|
filter_out_small_polygons(bottom_raw, Slic3r::sqr(scale_(0.1f)));
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
const char* colors[] = { "aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "purple", "red", "silver", "teal", "yellow" };
|
|
|
|
static int iRun = 0;
|
|
|
|
for (size_t layer_id = 0; layer_id < zs.size(); ++layer_id) {
|
|
|
|
std::vector<std::pair<Slic3r::ExPolygons, SVG::ExPolygonAttributes>> svg;
|
|
|
|
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++ extruder_idx) {
|
|
|
|
if (! top_raw[extruder_idx].empty() && ! top_raw[extruder_idx][layer_id].empty())
|
|
|
|
if (ExPolygons expoly = union_ex(top_raw[extruder_idx][layer_id]); ! expoly.empty()) {
|
|
|
|
const char *color = colors[extruder_idx];
|
|
|
|
svg.emplace_back(expoly, SVG::ExPolygonAttributes{ format("top%d", extruder_idx), color, color, color });
|
|
|
|
}
|
|
|
|
if (! bottom_raw[extruder_idx].empty() && ! bottom_raw[extruder_idx][layer_id].empty())
|
|
|
|
if (ExPolygons expoly = union_ex(bottom_raw[extruder_idx][layer_id]); ! expoly.empty()) {
|
|
|
|
const char *color = colors[extruder_idx + 8];
|
|
|
|
svg.emplace_back(expoly, SVG::ExPolygonAttributes{ format("bottom%d", extruder_idx), color, color, color });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SVG::export_expolygons(debug_out_path("mm-segmentation-top-bottom-%d-%d-%lf.svg", iRun, layer_id, zs[layer_id]), svg);
|
|
|
|
}
|
|
|
|
++ iRun;
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_TOP_BOTTOM
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2024-02-19 04:08:46 +00:00
|
|
|
// When the upper surface of an object is occluded, it should no longer be considered the upper surface
|
|
|
|
{
|
|
|
|
for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) {
|
|
|
|
for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) {
|
|
|
|
if (!top_raw[extruder_idx].empty() && !top_raw[extruder_idx][layer_idx].empty() && layer_idx + 1 < layers.size()) {
|
|
|
|
top_raw[extruder_idx][layer_idx] = diff(top_raw[extruder_idx][layer_idx], input_expolygons[layer_idx + 1]);
|
|
|
|
}
|
|
|
|
if (!bottom_raw[extruder_idx].empty() && !bottom_raw[extruder_idx][layer_idx].empty() && layer_idx > 0) {
|
|
|
|
bottom_raw[extruder_idx][layer_idx] = diff(bottom_raw[extruder_idx][layer_idx], input_expolygons[layer_idx - 1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
std::vector<std::vector<ExPolygons>> triangles_by_color_bottom(num_extruders);
|
|
|
|
std::vector<std::vector<ExPolygons>> triangles_by_color_top(num_extruders);
|
|
|
|
triangles_by_color_bottom.assign(num_extruders, std::vector<ExPolygons>(num_layers * 2));
|
|
|
|
triangles_by_color_top.assign(num_extruders, std::vector<ExPolygons>(num_layers * 2));
|
|
|
|
|
2023-03-29 02:59:31 +00:00
|
|
|
// BBS: use shell_triangles_by_color_bottom & shell_triangles_by_color_top to save the top and bottom embedded layers's color information
|
|
|
|
std::vector<std::vector<ExPolygons>> shell_triangles_by_color_bottom(num_extruders);
|
|
|
|
std::vector<std::vector<ExPolygons>> shell_triangles_by_color_top(num_extruders);
|
|
|
|
shell_triangles_by_color_bottom.assign(num_extruders, std::vector<ExPolygons>(num_layers * 2));
|
|
|
|
shell_triangles_by_color_top.assign(num_extruders, std::vector<ExPolygons>(num_layers * 2));
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
struct LayerColorStat {
|
|
|
|
// Number of regions for a queried color.
|
|
|
|
int num_regions { 0 };
|
|
|
|
// Maximum perimeter extrusion width for a queried color.
|
|
|
|
float extrusion_width { 0.f };
|
|
|
|
// Minimum radius of a region to be printable. Used to filter regions by morphological opening.
|
|
|
|
float small_region_threshold { 0.f };
|
|
|
|
// Maximum number of top layers for a queried color.
|
2025-02-26 06:19:24 +00:00
|
|
|
int top_color_penetration_layers { 0 };
|
2022-07-15 15:37:19 +00:00
|
|
|
// Maximum number of bottom layers for a queried color.
|
2025-02-26 06:19:24 +00:00
|
|
|
int bottom_color_penetration_layers { 0 };
|
2022-07-15 15:37:19 +00:00
|
|
|
//BBS: spacing according to width and layer height
|
|
|
|
float extrusion_spacing{ 0.f };
|
|
|
|
};
|
2023-09-13 09:45:29 +00:00
|
|
|
PrintConfig print_config = print_object.print()->config();
|
|
|
|
float default_line_width = float(print_object.config().line_width.value);
|
2024-07-02 11:26:52 +00:00
|
|
|
auto layer_color_stat = [&layers = std::as_const(layers), print_config, default_line_width, &print_object](const size_t layer_idx, const size_t color_idx) -> LayerColorStat {
|
2022-07-15 15:37:19 +00:00
|
|
|
LayerColorStat out;
|
|
|
|
const Layer &layer = *layers[layer_idx];
|
|
|
|
for (const LayerRegion *region : layer.regions())
|
|
|
|
if (const PrintRegionConfig &config = region->region().config();
|
|
|
|
// color_idx == 0 means "don't know" extruder aka the underlying extruder.
|
|
|
|
// As this region may split existing regions, we collect statistics over all regions for color_idx == 0.
|
|
|
|
color_idx == 0 || config.wall_filament == int(color_idx)) {
|
|
|
|
//BBS: the extrusion line width is outer wall rather than inner wall
|
2023-09-13 09:45:29 +00:00
|
|
|
float nozzle_diamter = float(print_config.nozzle_diameter.get_at(config.wall_filament - 1));
|
|
|
|
float outer_wall_line_width = float(config.outer_wall_line_width) == 0.0 ? (default_line_width == 0.0 ? nozzle_diamter : default_line_width) : float(config.outer_wall_line_width.value);
|
|
|
|
out.extrusion_width = std::max<float>(out.extrusion_width, outer_wall_line_width);
|
2025-02-26 06:19:24 +00:00
|
|
|
out.top_color_penetration_layers = std::max<int>(out.top_color_penetration_layers, config.top_color_penetration_layers);
|
|
|
|
out.bottom_color_penetration_layers = std::max<int>(out.bottom_color_penetration_layers, config.bottom_color_penetration_layers);
|
2024-07-02 11:26:52 +00:00
|
|
|
out.small_region_threshold = config.gap_infill_speed.get_at(print_object.print()->get_extruder_id(config.wall_filament - 1)) > 0 ?
|
2022-07-15 15:37:19 +00:00
|
|
|
// Gap fill enabled. Enable a single line of 1/2 extrusion width.
|
2023-09-13 09:45:29 +00:00
|
|
|
0.5f * outer_wall_line_width :
|
2022-07-15 15:37:19 +00:00
|
|
|
// Gap fill disabled. Enable two lines slightly overlapping.
|
2023-09-13 09:45:29 +00:00
|
|
|
outer_wall_line_width + 0.7f * Flow::rounded_rectangle_extrusion_spacing(outer_wall_line_width, float(layer.height));
|
2022-07-15 15:37:19 +00:00
|
|
|
out.small_region_threshold = scaled<float>(out.small_region_threshold * 0.5f);
|
2023-09-13 09:45:29 +00:00
|
|
|
out.extrusion_spacing = Flow::rounded_rectangle_extrusion_spacing(outer_wall_line_width, float(layer.height));
|
2022-07-15 15:37:19 +00:00
|
|
|
++ out.num_regions;
|
|
|
|
}
|
|
|
|
assert(out.num_regions > 0);
|
|
|
|
out.extrusion_width = scaled<float>(out.extrusion_width);
|
|
|
|
out.extrusion_spacing = scaled<float>(out.extrusion_spacing);
|
|
|
|
return out;
|
|
|
|
};
|
|
|
|
|
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers, granularity), [&granularity, &num_layers, &num_extruders, &layer_color_stat, &top_raw, &triangles_by_color_top,
|
2023-03-29 02:59:31 +00:00
|
|
|
&throw_on_cancel_callback, &input_expolygons, &bottom_raw, &triangles_by_color_bottom,
|
|
|
|
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
|
2022-07-15 15:37:19 +00:00
|
|
|
size_t group_idx = range.begin() / granularity;
|
|
|
|
size_t layer_idx_offset = (group_idx & 1) * num_layers;
|
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
|
|
|
for (size_t color_idx = 0; color_idx < num_extruders; ++ color_idx) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
LayerColorStat stat = layer_color_stat(layer_idx, color_idx);
|
|
|
|
if (std::vector<Polygons> &top = top_raw[color_idx]; ! top.empty() && ! top[layer_idx].empty())
|
|
|
|
if (ExPolygons top_ex = union_ex(top[layer_idx]); ! top_ex.empty()) {
|
|
|
|
// Clean up thin projections. They are not printable anyways.
|
|
|
|
top_ex = opening_ex(top_ex, stat.small_region_threshold);
|
|
|
|
if (! top_ex.empty()) {
|
|
|
|
append(triangles_by_color_top[color_idx][layer_idx + layer_idx_offset], top_ex);
|
|
|
|
float offset = 0.f;
|
|
|
|
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
|
2025-02-26 06:19:24 +00:00
|
|
|
for (int last_idx = int(layer_idx) - 1; last_idx > std::max(int(layer_idx - stat.top_color_penetration_layers), int(0)); --last_idx) {
|
2022-07-15 15:37:19 +00:00
|
|
|
//BBS: offset width should be 2*spacing to avoid too narrow area which has overlap of wall line
|
|
|
|
//offset -= stat.extrusion_width ;
|
|
|
|
offset -= (stat.extrusion_spacing + stat.extrusion_width);
|
|
|
|
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx]);
|
|
|
|
ExPolygons last = opening_ex(intersection_ex(top_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
|
|
|
if (last.empty())
|
|
|
|
break;
|
2023-03-29 02:59:31 +00:00
|
|
|
append(shell_triangles_by_color_top[color_idx][last_idx + layer_idx_offset], std::move(last));
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (std::vector<Polygons> &bottom = bottom_raw[color_idx]; ! bottom.empty() && ! bottom[layer_idx].empty())
|
|
|
|
if (ExPolygons bottom_ex = union_ex(bottom[layer_idx]); ! bottom_ex.empty()) {
|
|
|
|
// Clean up thin projections. They are not printable anyways.
|
|
|
|
bottom_ex = opening_ex(bottom_ex, stat.small_region_threshold);
|
|
|
|
if (! bottom_ex.empty()) {
|
|
|
|
append(triangles_by_color_bottom[color_idx][layer_idx + layer_idx_offset], bottom_ex);
|
|
|
|
float offset = 0.f;
|
|
|
|
ExPolygons layer_slices_trimmed = input_expolygons[layer_idx];
|
2025-02-26 06:19:24 +00:00
|
|
|
for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + stat.bottom_color_penetration_layers, num_layers); ++last_idx) {
|
2022-07-15 15:37:19 +00:00
|
|
|
//BBS: offset width should be 2*spacing to avoid too narrow area which has overlap of wall line
|
|
|
|
//offset -= stat.extrusion_width;
|
|
|
|
offset -= (stat.extrusion_spacing + stat.extrusion_width);
|
|
|
|
layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx]);
|
|
|
|
ExPolygons last = opening_ex(intersection_ex(bottom_ex, offset_ex(layer_slices_trimmed, offset)), stat.small_region_threshold);
|
|
|
|
if (last.empty())
|
|
|
|
break;
|
2023-03-29 02:59:31 +00:00
|
|
|
append(shell_triangles_by_color_bottom[color_idx][last_idx + layer_idx_offset], std::move(last));
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
std::vector<std::vector<ExPolygons>> triangles_by_color_merged(num_extruders);
|
|
|
|
triangles_by_color_merged.assign(num_extruders, std::vector<ExPolygons>(num_layers));
|
2023-03-29 02:59:31 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&triangles_by_color_merged, &triangles_by_color_bottom, &triangles_by_color_top, &num_layers, &throw_on_cancel_callback,
|
|
|
|
&shell_triangles_by_color_top, &shell_triangles_by_color_bottom](const tbb::blocked_range<size_t> &range) {
|
2022-07-15 15:37:19 +00:00
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
2023-03-29 02:59:31 +00:00
|
|
|
ExPolygons painted_exploys;
|
2022-07-15 15:37:19 +00:00
|
|
|
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
|
|
|
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
|
|
|
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx]));
|
|
|
|
append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx + num_layers]));
|
|
|
|
append(self, std::move(triangles_by_color_top[color_idx][layer_idx]));
|
|
|
|
append(self, std::move(triangles_by_color_top[color_idx][layer_idx + num_layers]));
|
|
|
|
self = union_ex(self);
|
2023-03-29 02:59:31 +00:00
|
|
|
|
|
|
|
append(painted_exploys, self);
|
|
|
|
}
|
|
|
|
|
|
|
|
painted_exploys = union_ex(painted_exploys);
|
|
|
|
|
|
|
|
//BBS: merge the top and bottom shell layers
|
|
|
|
for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
|
|
|
auto &self = triangles_by_color_merged[color_idx][layer_idx];
|
|
|
|
|
|
|
|
auto top_area = diff_ex(union_ex(shell_triangles_by_color_top[color_idx][layer_idx],
|
|
|
|
shell_triangles_by_color_top[color_idx][layer_idx + num_layers]),
|
|
|
|
painted_exploys);
|
|
|
|
|
|
|
|
auto bottom_area = diff_ex(union_ex(shell_triangles_by_color_bottom[color_idx][layer_idx],
|
|
|
|
shell_triangles_by_color_bottom[color_idx][layer_idx + num_layers]),
|
|
|
|
painted_exploys);
|
|
|
|
|
|
|
|
append(self, top_area);
|
|
|
|
append(self, bottom_area);
|
|
|
|
self = union_ex(self);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
// Trim one region by the other if some of the regions overlap.
|
2023-07-21 10:19:05 +00:00
|
|
|
ExPolygons painted_regions;
|
|
|
|
for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) {
|
|
|
|
triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx], painted_regions);
|
|
|
|
append(painted_regions, triangles_by_color_merged[color_idx][layer_idx]);
|
|
|
|
}
|
|
|
|
triangles_by_color_merged[0][layer_idx] = diff_ex(triangles_by_color_merged[0][layer_idx], painted_regions);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return triangles_by_color_merged;
|
|
|
|
}
|
|
|
|
|
2024-05-30 12:23:23 +00:00
|
|
|
// For every ColoredLine in lines_colored_out, assign the index of the polygon to which belongs and also the index of this line inside of the polygon.
|
|
|
|
static inline void init_polygon_indices(const MMU_Graph &graph, const std::vector<std::vector<ColoredLine>> &color_poly, std::vector<ColoredLine> &lines_colored_out)
|
|
|
|
{
|
|
|
|
size_t poly_idx = 0;
|
|
|
|
for (const std::vector<ColoredLine> &color_lines : color_poly) {
|
|
|
|
size_t line_idx = 0;
|
|
|
|
for (size_t color_line_idx = 0; color_line_idx < color_lines.size(); ++color_line_idx) {
|
|
|
|
size_t from_idx = graph.get_global_index(poly_idx, line_idx);
|
|
|
|
lines_colored_out[from_idx].poly_idx = int(poly_idx);
|
|
|
|
lines_colored_out[from_idx].local_line_idx = int(line_idx);
|
|
|
|
++line_idx;
|
|
|
|
}
|
|
|
|
++poly_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool line_intersection_with_epsilon(const Line &line_to_extend, const Line &other, Point *intersection)
|
|
|
|
{
|
|
|
|
Line extended_line = line_to_extend;
|
|
|
|
extended_line.extend(15 * SCALED_EPSILON);
|
|
|
|
return extended_line.intersection(other, intersection);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mark_processed(const voronoi_diagram<double>::const_edge_iterator &edge_iterator)
|
|
|
|
{
|
|
|
|
edge_iterator->color(true);
|
|
|
|
edge_iterator->twin()->color(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool is_point_closer_to_beginning_of_line(const Line &line, const Point &p)
|
|
|
|
{
|
|
|
|
return (p - line.a).cast<double>().squaredNorm() < (p - line.b).cast<double>().squaredNorm();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Line clip_finite_voronoi_edge(const Voronoi::VD::edge_type &edge, const BoundingBoxf &bbox)
|
|
|
|
{
|
|
|
|
assert(edge.is_finite());
|
|
|
|
Vec2d v0 = mk_vec2(edge.vertex0());
|
|
|
|
Vec2d v1 = mk_vec2(edge.vertex1());
|
|
|
|
bool contains_v0 = bbox.contains(v0);
|
|
|
|
bool contains_v1 = bbox.contains(v1);
|
|
|
|
if ((contains_v0 && contains_v1) || (!contains_v0 && !contains_v1)) return {mk_point(edge.vertex0()), mk_point(edge.vertex1())};
|
|
|
|
|
|
|
|
Vec2d vector = (v1 - v0).normalized() * bbox.size().norm();
|
|
|
|
if (!contains_v0)
|
|
|
|
v0 = (v1 - vector);
|
|
|
|
else
|
|
|
|
v1 = (v0 + vector);
|
|
|
|
|
|
|
|
return {v0.cast<coord_t>(), v1.cast<coord_t>()};
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool has_same_color(const ColoredLine &cl1, const ColoredLine &cl2) { return cl1.color == cl2.color; }
|
|
|
|
|
|
|
|
static MMU_Graph build_graph(size_t layer_idx, const std::vector<std::vector<ColoredLine>> &color_poly)
|
|
|
|
{
|
|
|
|
const Polygons color_poly_tmp = colored_points_to_polygon(color_poly);
|
|
|
|
const Points points = to_points(color_poly_tmp);
|
|
|
|
const Lines lines = to_lines(color_poly_tmp);
|
|
|
|
|
|
|
|
// The algorithm adds edges to the graph that are between two different colors.
|
|
|
|
// If a polygon is colored entirely with one color, we need to add at least one edge from that polygon artificially.
|
|
|
|
// Adding this edge is necessary for cases where the expolygon has an outer contour colored whole with one color
|
|
|
|
// and a hole colored with a different color. If an edge wasn't added to the graph,
|
|
|
|
// the entire expolygon would be colored with single random color instead of two different.
|
|
|
|
std::vector<bool> force_edge_adding(color_poly.size());
|
|
|
|
|
|
|
|
// For each polygon, check if it is all colored with the same color. If it is, we need to force adding one edge to it.
|
|
|
|
for (const std::vector<ColoredLine> &c_poly : color_poly) {
|
|
|
|
bool force_edge = true;
|
|
|
|
for (const ColoredLine &c_line : c_poly)
|
|
|
|
if (c_line.color != c_poly.front().color) {
|
|
|
|
force_edge = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
force_edge_adding[&c_poly - &color_poly.front()] = force_edge;
|
|
|
|
}
|
|
|
|
|
|
|
|
ColoredLines lines_colored = to_lines(color_poly);
|
|
|
|
const ColoredLines colored_lines = lines_colored;
|
|
|
|
|
|
|
|
Voronoi::VD vd;
|
|
|
|
vd.construct_voronoi(colored_lines.begin(), colored_lines.end());
|
|
|
|
// boost::polygon::construct_voronoi(lines_colored.begin(), lines_colored.end(), &vd);
|
|
|
|
MMU_Graph graph;
|
|
|
|
graph.nodes.reserve(points.size() + vd.vertices().size());
|
|
|
|
for (const Point &point : points) graph.nodes.push_back({Vec2d(double(point.x()), double(point.y()))});
|
|
|
|
|
|
|
|
graph.add_contours(color_poly);
|
|
|
|
init_polygon_indices(graph, color_poly, lines_colored);
|
|
|
|
|
|
|
|
assert(graph.nodes.size() == lines_colored.size());
|
|
|
|
BoundingBox bbox = get_extents(color_poly_tmp);
|
|
|
|
graph.append_voronoi_vertices(vd, color_poly_tmp, bbox);
|
|
|
|
|
|
|
|
auto get_prev_contour_line = [&lines_colored, &color_poly, &graph](const voronoi_diagram<double>::const_edge_iterator &edge_it) -> ColoredLine {
|
|
|
|
size_t contour_line_local_idx = lines_colored[edge_it->cell()->source_index()].local_line_idx;
|
|
|
|
size_t contour_line_size = color_poly[lines_colored[edge_it->cell()->source_index()].poly_idx].size();
|
|
|
|
size_t contour_prev_idx = graph.get_global_index(lines_colored[edge_it->cell()->source_index()].poly_idx,
|
|
|
|
(contour_line_local_idx > 0) ? contour_line_local_idx - 1 : contour_line_size - 1);
|
|
|
|
return lines_colored[contour_prev_idx];
|
|
|
|
};
|
|
|
|
|
|
|
|
auto get_next_contour_line = [&lines_colored, &color_poly, &graph](const voronoi_diagram<double>::const_edge_iterator &edge_it) -> ColoredLine {
|
|
|
|
size_t contour_line_local_idx = lines_colored[edge_it->cell()->source_index()].local_line_idx;
|
|
|
|
size_t contour_line_size = color_poly[lines_colored[edge_it->cell()->source_index()].poly_idx].size();
|
|
|
|
size_t contour_next_idx = graph.get_global_index(lines_colored[edge_it->cell()->source_index()].poly_idx, (contour_line_local_idx + 1) % contour_line_size);
|
|
|
|
return lines_colored[contour_next_idx];
|
|
|
|
};
|
|
|
|
|
|
|
|
bbox.offset(scale_(10.));
|
|
|
|
const BoundingBoxf bbox_clip(bbox.min.cast<double>(), bbox.max.cast<double>());
|
|
|
|
const double bbox_dim_max = double(std::max(bbox.size().x(), bbox.size().y()));
|
|
|
|
|
|
|
|
// Make a copy of the input segments with the double type.
|
|
|
|
std::vector<Voronoi::Internal::segment_type> segments;
|
|
|
|
for (const Line &line : lines)
|
|
|
|
segments.emplace_back(Voronoi::Internal::point_type(double(line.a(0)), double(line.a(1))), Voronoi::Internal::point_type(double(line.b(0)), double(line.b(1))));
|
|
|
|
|
|
|
|
for (auto edge_it = vd.edges().begin(); edge_it != vd.edges().end(); ++edge_it) {
|
|
|
|
// Skip second half-edge
|
|
|
|
if (edge_it->cell()->source_index() > edge_it->twin()->cell()->source_index() || edge_it->color()) continue;
|
|
|
|
|
|
|
|
if (edge_it->is_infinite() && (edge_it->vertex0() != nullptr || edge_it->vertex1() != nullptr)) {
|
|
|
|
// Infinite edge is leading through a point on the counter, but there are no Voronoi vertices.
|
|
|
|
// So we could fix this case by computing the intersection between the contour line and infinity edge.
|
|
|
|
std::vector<Voronoi::Internal::point_type> samples;
|
|
|
|
Voronoi::Internal::clip_infinite_edge(points, segments, *edge_it, bbox_dim_max, &samples);
|
|
|
|
if (samples.empty()) continue;
|
|
|
|
|
|
|
|
const Line edge_line(mk_point(samples[0]), mk_point(samples[1]));
|
|
|
|
const ColoredLine &contour_line = lines_colored[edge_it->cell()->source_index()];
|
|
|
|
Point contour_intersection;
|
|
|
|
|
|
|
|
if (line_intersection_with_epsilon(contour_line.line, edge_line, &contour_intersection)) {
|
|
|
|
const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_it->cell()->source_index());
|
|
|
|
const size_t from_idx = (edge_it->vertex1() != nullptr) ? edge_it->vertex1()->color() : edge_it->vertex0()->color();
|
|
|
|
size_t to_idx = ((contour_line.line.a - contour_intersection).cast<double>().squaredNorm() <
|
|
|
|
(contour_line.line.b - contour_intersection).cast<double>().squaredNorm()) ?
|
|
|
|
graph_arc.from_idx :
|
|
|
|
graph_arc.to_idx;
|
|
|
|
if (from_idx != to_idx && from_idx < graph.nodes_count() && to_idx < graph.nodes_count()) {
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
mark_processed(edge_it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (edge_it->is_finite()) {
|
|
|
|
// Both points are on contour, so skip them. In cases of duplicate Voronoi vertices, skip edges between the same two points.
|
|
|
|
if (graph.is_edge_connecting_two_contour_vertices(edge_it) || (edge_it->vertex0()->color() == edge_it->vertex1()->color())) continue;
|
|
|
|
|
|
|
|
const Line edge_line = clip_finite_voronoi_edge(*edge_it, bbox_clip);
|
|
|
|
const Line contour_line = lines_colored[edge_it->cell()->source_index()].line;
|
|
|
|
const ColoredLine colored_line = lines_colored[edge_it->cell()->source_index()];
|
|
|
|
const ColoredLine contour_line_prev = get_prev_contour_line(edge_it);
|
|
|
|
const ColoredLine contour_line_next = get_next_contour_line(edge_it);
|
|
|
|
|
|
|
|
if (edge_it->vertex0()->color() >= graph.nodes_count() || edge_it->vertex1()->color() >= graph.nodes_count()) {
|
|
|
|
enum class Vertex { VERTEX0, VERTEX1 };
|
|
|
|
auto append_edge_if_intersects_with_contour = [&graph, &lines_colored, &edge_line,
|
|
|
|
&contour_line](const voronoi_diagram<double>::const_edge_iterator &edge_iterator, const Vertex vertex) {
|
|
|
|
Point intersection;
|
|
|
|
Line contour_line_twin = lines_colored[edge_iterator->twin()->cell()->source_index()].line;
|
|
|
|
if (line_intersection_with_epsilon(contour_line_twin, edge_line, &intersection)) {
|
|
|
|
const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_iterator->twin()->cell()->source_index());
|
|
|
|
const size_t to_idx_l = is_point_closer_to_beginning_of_line(contour_line_twin, intersection) ? graph_arc.from_idx : graph_arc.to_idx;
|
|
|
|
graph.append_edge(vertex == Vertex::VERTEX0 ? edge_iterator->vertex0()->color() : edge_iterator->vertex1()->color(), to_idx_l);
|
|
|
|
} else if (line_intersection_with_epsilon(contour_line, edge_line, &intersection)) {
|
|
|
|
const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_iterator->cell()->source_index());
|
|
|
|
const size_t to_idx_l = is_point_closer_to_beginning_of_line(contour_line, intersection) ? graph_arc.from_idx : graph_arc.to_idx;
|
|
|
|
graph.append_edge(vertex == Vertex::VERTEX0 ? edge_iterator->vertex0()->color() : edge_iterator->vertex1()->color(), to_idx_l);
|
|
|
|
}
|
|
|
|
mark_processed(edge_iterator);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (edge_it->vertex0()->color() < graph.nodes_count() && !graph.is_vertex_on_contour(edge_it->vertex0()))
|
|
|
|
append_edge_if_intersects_with_contour(edge_it, Vertex::VERTEX0);
|
|
|
|
|
|
|
|
if (edge_it->vertex1()->color() < graph.nodes_count() && !graph.is_vertex_on_contour(edge_it->vertex1()))
|
|
|
|
append_edge_if_intersects_with_contour(edge_it, Vertex::VERTEX1);
|
|
|
|
} else if (graph.is_edge_attach_to_contour(edge_it)) {
|
|
|
|
mark_processed(edge_it);
|
|
|
|
// Skip edges witch connection two points on a contour
|
|
|
|
if (graph.is_edge_connecting_two_contour_vertices(edge_it)) continue;
|
|
|
|
|
|
|
|
const size_t from_idx = edge_it->vertex0()->color();
|
|
|
|
const size_t to_idx = edge_it->vertex1()->color();
|
|
|
|
if (graph.is_vertex_on_contour(edge_it->vertex0())) {
|
|
|
|
if (is_point_closer_to_beginning_of_line(contour_line, edge_line.a)) {
|
|
|
|
if ((!has_same_color(contour_line_prev, colored_line) || force_edge_adding[colored_line.poly_idx]) &&
|
|
|
|
points_inside(contour_line_prev.line, contour_line, edge_line.b)) {
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
force_edge_adding[colored_line.poly_idx] = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((!has_same_color(contour_line_next, colored_line) || force_edge_adding[colored_line.poly_idx]) &&
|
|
|
|
points_inside(contour_line, contour_line_next.line, edge_line.b)) {
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
force_edge_adding[colored_line.poly_idx] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(graph.is_vertex_on_contour(edge_it->vertex1()));
|
|
|
|
if (is_point_closer_to_beginning_of_line(contour_line, edge_line.b)) {
|
|
|
|
if ((!has_same_color(contour_line_prev, colored_line) || force_edge_adding[colored_line.poly_idx]) &&
|
|
|
|
points_inside(contour_line_prev.line, contour_line, edge_line.a)) {
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
force_edge_adding[colored_line.poly_idx] = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((!has_same_color(contour_line_next, colored_line) || force_edge_adding[colored_line.poly_idx]) &&
|
|
|
|
points_inside(contour_line, contour_line_next.line, edge_line.a)) {
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
force_edge_adding[colored_line.poly_idx] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (Point intersection; line_intersection_with_epsilon(contour_line, edge_line, &intersection)) {
|
|
|
|
mark_processed(edge_it);
|
|
|
|
Vec2d real_v0_double = graph.nodes[edge_it->vertex0()->color()].point;
|
|
|
|
Vec2d real_v1_double = graph.nodes[edge_it->vertex1()->color()].point;
|
|
|
|
Point real_v0 = Point(coord_t(real_v0_double.x()), coord_t(real_v0_double.y()));
|
|
|
|
Point real_v1 = Point(coord_t(real_v1_double.x()), coord_t(real_v1_double.y()));
|
|
|
|
|
|
|
|
if (is_point_closer_to_beginning_of_line(contour_line, intersection)) {
|
|
|
|
Line first_part(intersection, real_v0);
|
|
|
|
Line second_part(intersection, real_v1);
|
|
|
|
|
|
|
|
if (!has_same_color(contour_line_prev, colored_line)) {
|
|
|
|
if (points_inside(contour_line_prev.line, contour_line, first_part.b))
|
|
|
|
graph.append_edge(edge_it->vertex0()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx);
|
|
|
|
|
|
|
|
if (points_inside(contour_line_prev.line, contour_line, second_part.b))
|
|
|
|
graph.append_edge(edge_it->vertex1()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const size_t int_point_idx = graph.get_border_arc(edge_it->cell()->source_index()).to_idx;
|
|
|
|
const Vec2d int_point_double = graph.nodes[int_point_idx].point;
|
|
|
|
const Point int_point = Point(coord_t(int_point_double.x()), coord_t(int_point_double.y()));
|
|
|
|
|
|
|
|
const Line first_part(int_point, real_v0);
|
|
|
|
const Line second_part(int_point, real_v1);
|
|
|
|
|
|
|
|
if (!has_same_color(contour_line_next, colored_line)) {
|
|
|
|
if (points_inside(contour_line, contour_line_next.line, first_part.b)) graph.append_edge(edge_it->vertex0()->color(), int_point_idx);
|
|
|
|
|
|
|
|
if (points_inside(contour_line, contour_line_next.line, second_part.b)) graph.append_edge(edge_it->vertex1()->color(), int_point_idx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto edge_it = vd.edges().begin(); edge_it != vd.edges().end(); ++edge_it) {
|
|
|
|
// Skip second half-edge and processed edges
|
|
|
|
if (edge_it->cell()->source_index() > edge_it->twin()->cell()->source_index() || edge_it->color()) continue;
|
|
|
|
|
|
|
|
if (edge_it->is_finite() && !bool(edge_it->color()) && edge_it->vertex0()->color() < graph.nodes_count() && edge_it->vertex1()->color() < graph.nodes_count()) {
|
|
|
|
// Skip cases, when the edge is between two same vertices, which is in cases two near vertices were merged together.
|
|
|
|
if (edge_it->vertex0()->color() == edge_it->vertex1()->color()) continue;
|
|
|
|
|
|
|
|
size_t from_idx = edge_it->vertex0()->color();
|
|
|
|
size_t to_idx = edge_it->vertex1()->color();
|
|
|
|
graph.append_edge(from_idx, to_idx);
|
|
|
|
}
|
|
|
|
mark_processed(edge_it);
|
|
|
|
}
|
|
|
|
|
|
|
|
graph.remove_nodes_with_one_arc();
|
|
|
|
return graph;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<std::vector<std::pair<size_t, size_t>>> get_all_segments(const std::vector<std::vector<ColoredLine>> &color_poly)
|
|
|
|
{
|
|
|
|
std::vector<std::vector<std::pair<size_t, size_t>>> all_segments(color_poly.size());
|
|
|
|
for (size_t poly_idx = 0; poly_idx < color_poly.size(); ++poly_idx) {
|
|
|
|
const std::vector<ColoredLine> &c_polygon = color_poly[poly_idx];
|
|
|
|
all_segments[poly_idx] = get_segments(c_polygon);
|
|
|
|
}
|
|
|
|
return all_segments;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline double compute_edge_length(const MMU_Graph &graph, const size_t start_idx, const size_t &start_arc_idx)
|
|
|
|
{
|
|
|
|
assert(start_arc_idx < graph.arcs.size());
|
|
|
|
std::vector<bool> used_arcs(graph.arcs.size(), false);
|
|
|
|
|
|
|
|
used_arcs[start_arc_idx] = true;
|
|
|
|
const MMU_Graph::Arc *arc = &graph.arcs[start_arc_idx];
|
|
|
|
size_t idx = start_idx;
|
|
|
|
double line_total_length = (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).norm();
|
|
|
|
while (graph.nodes[arc->to_idx].arc_idxs.size() == 2) {
|
|
|
|
bool found = false;
|
|
|
|
for (const size_t &arc_idx : graph.nodes[arc->to_idx].arc_idxs) {
|
|
|
|
if (const MMU_Graph::Arc &arc_n = graph.arcs[arc_idx]; arc_n.type == MMU_Graph::ARC_TYPE::NON_BORDER && !used_arcs[arc_idx] && arc_n.to_idx != idx) {
|
|
|
|
Linef first_line(graph.nodes[idx].point, graph.nodes[arc->to_idx].point);
|
|
|
|
Linef second_line(graph.nodes[arc->to_idx].point, graph.nodes[arc_n.to_idx].point);
|
|
|
|
|
|
|
|
Vec2d first_line_vec = (first_line.a - first_line.b);
|
|
|
|
Vec2d second_line_vec = (second_line.b - second_line.a);
|
|
|
|
Vec2d first_line_vec_n = first_line_vec.normalized();
|
|
|
|
Vec2d second_line_vec_n = second_line_vec.normalized();
|
|
|
|
double angle = ::acos(std::clamp(first_line_vec_n.dot(second_line_vec_n), -1.0, 1.0));
|
|
|
|
if (Slic3r::cross2(first_line_vec_n, second_line_vec_n) < 0.0) angle = 2.0 * (double) PI - angle;
|
|
|
|
|
|
|
|
if (std::abs(angle - PI) >= (PI / 12)) continue;
|
|
|
|
|
|
|
|
idx = arc->to_idx;
|
|
|
|
arc = &arc_n;
|
|
|
|
|
|
|
|
line_total_length += (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).norm();
|
|
|
|
used_arcs[arc_idx] = true;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return line_total_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_multiple_edges_in_vertices(MMU_Graph &graph, const std::vector<std::vector<ColoredLine>> &color_poly)
|
|
|
|
{
|
|
|
|
std::vector<std::vector<std::pair<size_t, size_t>>> colored_segments = get_all_segments(color_poly);
|
|
|
|
for (const std::vector<std::pair<size_t, size_t>> &colored_segment_p : colored_segments) {
|
|
|
|
size_t poly_idx = &colored_segment_p - &colored_segments.front();
|
|
|
|
for (const std::pair<size_t, size_t> &colored_segment : colored_segment_p) {
|
|
|
|
size_t first_idx = graph.get_global_index(poly_idx, colored_segment.first);
|
|
|
|
size_t second_idx = graph.get_global_index(poly_idx, (colored_segment.second + 1) % graph.polygon_sizes[poly_idx]);
|
|
|
|
Linef seg_line(graph.nodes[first_idx].point, graph.nodes[second_idx].point);
|
|
|
|
|
|
|
|
if (graph.nodes[first_idx].arc_idxs.size() >= 3) {
|
|
|
|
std::vector<std::pair<MMU_Graph::Arc *, double>> arc_to_check;
|
|
|
|
for (const size_t &arc_idx : graph.nodes[first_idx].arc_idxs) {
|
|
|
|
MMU_Graph::Arc &n_arc = graph.arcs[arc_idx];
|
|
|
|
if (n_arc.type == MMU_Graph::ARC_TYPE::NON_BORDER) {
|
|
|
|
double total_len = compute_edge_length(graph, first_idx, arc_idx);
|
|
|
|
arc_to_check.emplace_back(&n_arc, total_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::sort(arc_to_check.begin(), arc_to_check.end(),
|
|
|
|
[](std::pair<MMU_Graph::Arc *, double> &l, std::pair<MMU_Graph::Arc *, double> &r) -> bool { return l.second > r.second; });
|
|
|
|
|
|
|
|
while (arc_to_check.size() > 1) {
|
|
|
|
graph.remove_edge(first_idx, arc_to_check.back().first->to_idx);
|
|
|
|
arc_to_check.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
static std::vector<std::vector<ExPolygons>> merge_segmented_layers(
|
|
|
|
const std::vector<std::vector<ExPolygons>> &segmented_regions,
|
|
|
|
std::vector<std::vector<ExPolygons>> &&top_and_bottom_layers,
|
|
|
|
const size_t num_extruders,
|
|
|
|
const std::function<void()> &throw_on_cancel_callback)
|
|
|
|
{
|
|
|
|
const size_t num_layers = segmented_regions.size();
|
|
|
|
std::vector<std::vector<ExPolygons>> segmented_regions_merged(num_layers);
|
|
|
|
segmented_regions_merged.assign(num_layers, std::vector<ExPolygons>(num_extruders));
|
|
|
|
assert(num_extruders + 1 == top_and_bottom_layers.size());
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - merging segmented layers in parallel - begin";
|
2022-07-15 15:37:19 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&segmented_regions, &top_and_bottom_layers, &segmented_regions_merged, &num_extruders, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
|
|
|
assert(segmented_regions[layer_idx].size() == num_extruders + 1);
|
|
|
|
// Zero is skipped because it is the default color of the volume
|
|
|
|
for (size_t extruder_id = 1; extruder_id < num_extruders + 1; ++extruder_id) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
if (!segmented_regions[layer_idx][extruder_id].empty()) {
|
|
|
|
ExPolygons segmented_regions_trimmed = segmented_regions[layer_idx][extruder_id];
|
|
|
|
for (const std::vector<ExPolygons> &top_and_bottom_by_extruder : top_and_bottom_layers)
|
|
|
|
if (!top_and_bottom_by_extruder[layer_idx].empty() && !segmented_regions_trimmed.empty())
|
|
|
|
segmented_regions_trimmed = diff_ex(segmented_regions_trimmed, top_and_bottom_by_extruder[layer_idx]);
|
|
|
|
|
|
|
|
segmented_regions_merged[layer_idx][extruder_id - 1] = std::move(segmented_regions_trimmed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!top_and_bottom_layers[extruder_id][layer_idx].empty()) {
|
|
|
|
bool was_top_and_bottom_empty = segmented_regions_merged[layer_idx][extruder_id - 1].empty();
|
|
|
|
append(segmented_regions_merged[layer_idx][extruder_id - 1], top_and_bottom_layers[extruder_id][layer_idx]);
|
|
|
|
|
|
|
|
// Remove dimples (#7235) appearing after merging side segmentation of the model with tops and bottoms painted layers.
|
|
|
|
if (!was_top_and_bottom_empty)
|
|
|
|
segmented_regions_merged[layer_idx][extruder_id - 1] = offset2_ex(union_ex(segmented_regions_merged[layer_idx][extruder_id - 1]), float(SCALED_EPSILON), -float(SCALED_EPSILON));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}); // end of parallel_for
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - merging segmented layers in parallel - end";
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
return segmented_regions_merged;
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_REGIONS
|
2022-07-15 15:37:19 +00:00
|
|
|
static void export_regions_to_svg(const std::string &path, const std::vector<ExPolygons> ®ions, const ExPolygons &lslices)
|
|
|
|
{
|
|
|
|
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "yellow"};
|
|
|
|
coordf_t stroke_width = scale_(0.05);
|
|
|
|
BoundingBox bbox = get_extents(lslices);
|
|
|
|
bbox.offset(scale_(1.));
|
|
|
|
::Slic3r::SVG svg(path.c_str(), bbox);
|
|
|
|
|
|
|
|
svg.draw_outline(lslices, "green", "lime", stroke_width);
|
|
|
|
for (const ExPolygons &by_extruder : regions) {
|
|
|
|
size_t extrude_idx = &by_extruder - ®ions.front();
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
if (extrude_idx < int(colors.size()))
|
|
|
|
svg.draw(by_extruder, colors[extrude_idx]);
|
2022-07-15 15:37:19 +00:00
|
|
|
else
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
svg.draw(by_extruder, "black");
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_REGIONS
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_INPUT
|
2022-07-15 15:37:19 +00:00
|
|
|
void export_processed_input_expolygons_to_svg(const std::string &path, const LayerRegionPtrs ®ions, const ExPolygons &processed_input_expolygons)
|
|
|
|
{
|
|
|
|
coordf_t stroke_width = scale_(0.05);
|
|
|
|
BoundingBox bbox = get_extents(regions);
|
|
|
|
bbox.merge(get_extents(processed_input_expolygons));
|
|
|
|
bbox.offset(scale_(1.));
|
|
|
|
::Slic3r::SVG svg(path.c_str(), bbox);
|
|
|
|
|
|
|
|
for (LayerRegion *region : regions)
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
for (const Surface &surface : region->slices.surfaces)
|
|
|
|
svg.draw_outline(surface, "blue", "cyan", stroke_width);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
svg.draw_outline(processed_input_expolygons, "red", "pink", stroke_width);
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_INPUT
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
2022-07-15 15:37:19 +00:00
|
|
|
static void export_painted_lines_to_svg(const std::string &path, const std::vector<std::vector<PaintedLine>> &all_painted_lines, const ExPolygons &lslices)
|
|
|
|
{
|
|
|
|
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "yellow"};
|
|
|
|
coordf_t stroke_width = scale_(0.05);
|
|
|
|
BoundingBox bbox = get_extents(lslices);
|
|
|
|
bbox.offset(scale_(1.));
|
|
|
|
::Slic3r::SVG svg(path.c_str(), bbox);
|
|
|
|
|
|
|
|
for (const Line &line : to_lines(lslices))
|
|
|
|
svg.draw(line, "green", stroke_width);
|
|
|
|
|
|
|
|
for (const std::vector<PaintedLine> &painted_lines : all_painted_lines)
|
|
|
|
for (const PaintedLine &painted_line : painted_lines)
|
|
|
|
svg.draw(painted_line.projected_line, painted_line.color < int(colors.size()) ? colors[painted_line.color] : "black", stroke_width);
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS
|
|
|
|
static void export_colorized_polygons_to_svg(const std::string &path, const std::vector<ColoredLines> &colorized_polygons, const ExPolygons &lslices)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "green", "yellow"};
|
|
|
|
coordf_t stroke_width = scale_(0.05);
|
|
|
|
BoundingBox bbox = get_extents(lslices);
|
|
|
|
bbox.offset(scale_(1.));
|
|
|
|
::Slic3r::SVG svg(path.c_str(), bbox);
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
for (const ColoredLines &colorized_polygon : colorized_polygons)
|
2022-07-15 15:37:19 +00:00
|
|
|
for (const ColoredLine &colorized_line : colorized_polygon)
|
|
|
|
svg.draw(colorized_line.line, colorized_line.color < int(colors.size())? colors[colorized_line.color] : "black", stroke_width);
|
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#endif // MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
// Check if all ColoredLine representing a single layer uses the same color.
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
static bool has_layer_only_one_color(const std::vector<ColoredLines> &colored_polygons)
|
2022-07-15 15:37:19 +00:00
|
|
|
{
|
|
|
|
assert(!colored_polygons.empty());
|
|
|
|
assert(!colored_polygons.front().empty());
|
|
|
|
int first_line_color = colored_polygons.front().front().color;
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
for (const ColoredLines &colored_polygon : colored_polygons)
|
2022-07-15 15:37:19 +00:00
|
|
|
for (const ColoredLine &colored_line : colored_polygon)
|
|
|
|
if (first_line_color != colored_line.color)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::vector<ExPolygons>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function<void()> &throw_on_cancel_callback)
|
|
|
|
{
|
|
|
|
const size_t num_extruders = print_object.print()->config().filament_colour.size();
|
|
|
|
const size_t num_layers = print_object.layers().size();
|
|
|
|
std::vector<std::vector<ExPolygons>> segmented_regions(num_layers);
|
|
|
|
segmented_regions.assign(num_layers, std::vector<ExPolygons>(num_extruders + 1));
|
|
|
|
std::vector<std::vector<PaintedLine>> painted_lines(num_layers);
|
|
|
|
std::array<std::mutex, 64> painted_lines_mutex;
|
|
|
|
std::vector<EdgeGrid::Grid> edge_grids(num_layers);
|
|
|
|
const ConstLayerPtrsAdaptor layers = print_object.layers();
|
|
|
|
std::vector<ExPolygons> input_expolygons(num_layers);
|
|
|
|
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG
|
|
|
|
static int iRun = 0;
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Merge all regions and remove small holes
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - slices preparation in parallel - begin";
|
2022-07-15 15:37:19 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&layers, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
ExPolygons ex_polygons;
|
|
|
|
for (LayerRegion *region : layers[layer_idx]->regions())
|
|
|
|
for (const Surface &surface : region->slices.surfaces)
|
|
|
|
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
|
|
|
|
// to ensure that very close polygons will be merged.
|
|
|
|
ex_polygons = union_ex(ex_polygons);
|
|
|
|
// Remove all expolygons and holes with an area less than 0.1mm^2
|
|
|
|
remove_small_and_small_holes(ex_polygons, Slic3r::sqr(scale_(0.1f)));
|
|
|
|
// Occasionally, some input polygons contained self-intersections that caused problems with Voronoi diagrams
|
|
|
|
// and consequently with the extraction of colored segments by function extract_colored_segments.
|
|
|
|
// Calling simplify_polygons removes these self-intersections.
|
|
|
|
// Also, occasionally input polygons contained several points very close together (distance between points is 1 or so).
|
|
|
|
// 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.
|
|
|
|
// Calling expolygons_simplify fixed these issues.
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
input_expolygons[layer_idx] = remove_duplicates(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), scaled<coord_t>(0.01), PI/6);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_INPUT
|
|
|
|
export_processed_input_expolygons_to_svg(debug_out_path("mm-input-%d-%d.svg", layer_idx, iRun), layers[layer_idx]->regions(), input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_INPUT
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}); // end of parallel_for
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - slices preparation in parallel - end";
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
std::vector<BoundingBox> layer_bboxes(num_layers);
|
|
|
|
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
layer_bboxes[layer_idx] = get_extents(layers[layer_idx]->regions());
|
|
|
|
layer_bboxes[layer_idx].merge(get_extents(input_expolygons[layer_idx]));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
BoundingBox bbox = layer_bboxes[layer_idx];
|
|
|
|
// Projected triangles could, in rare cases (as in GH issue #7299), belongs to polygons printed in the previous or the next layer.
|
|
|
|
// Let's merge the bounding box of the current layer with bounding boxes of the previous and the next layer to ensure that
|
|
|
|
// every projected triangle will be inside the resulting bounding box.
|
|
|
|
if (layer_idx > 1) bbox.merge(layer_bboxes[layer_idx - 1]);
|
|
|
|
if (layer_idx < num_layers - 1) bbox.merge(layer_bboxes[layer_idx + 1]);
|
|
|
|
// Projected triangles may slightly exceed the input polygons.
|
2024-10-18 08:42:12 +00:00
|
|
|
bbox.offset(30 * SCALED_EPSILON);
|
2022-07-15 15:37:19 +00:00
|
|
|
edge_grids[layer_idx].set_bbox(bbox);
|
|
|
|
edge_grids[layer_idx].create(input_expolygons[layer_idx], coord_t(scale_(10.)));
|
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - begin";
|
2022-07-15 15:37:19 +00:00
|
|
|
for (const ModelVolume *mv : print_object.model_object()->volumes) {
|
2024-09-19 06:06:06 +00:00
|
|
|
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
|
2022-07-15 15:37:19 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(1, num_extruders + 1), [&mv, &print_object, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
|
|
|
for (size_t extruder_idx = range.begin(); extruder_idx < range.end(); ++extruder_idx) {
|
2024-09-19 06:06:06 +00:00
|
|
|
#else
|
|
|
|
for (size_t extruder_idx = 1; extruder_idx < num_extruders + 1; ++extruder_idx) {
|
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
throw_on_cancel_callback();
|
|
|
|
const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx));
|
|
|
|
if (!mv->is_model_part() || custom_facets.indices.empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const Transform3f tr = print_object.trafo().cast<float>() * mv->get_matrix().cast<float>();
|
2024-09-19 06:06:06 +00:00
|
|
|
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
|
2022-07-15 15:37:19 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &layers, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range<size_t> &range) {
|
|
|
|
for (size_t facet_idx = range.begin(); facet_idx < range.end(); ++facet_idx) {
|
2024-09-19 06:06:06 +00:00
|
|
|
#else
|
|
|
|
for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) {
|
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
float min_z = std::numeric_limits<float>::max();
|
|
|
|
float max_z = std::numeric_limits<float>::lowest();
|
|
|
|
|
|
|
|
std::array<Vec3f, 3> facet;
|
|
|
|
for (int p_idx = 0; p_idx < 3; ++p_idx) {
|
|
|
|
facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)];
|
|
|
|
max_z = std::max(max_z, facet[p_idx].z());
|
|
|
|
min_z = std::min(min_z, facet[p_idx].z());
|
|
|
|
}
|
|
|
|
|
2024-03-12 06:51:30 +00:00
|
|
|
if (is_equal(min_z, max_z))
|
|
|
|
continue;
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Sort the vertices by z-axis for simplification of projected_facet on slices
|
|
|
|
std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); });
|
|
|
|
|
|
|
|
// Find lowest slice not below the triangle.
|
|
|
|
auto first_layer = std::upper_bound(layers.begin(), layers.end(), float(min_z - EPSILON),
|
|
|
|
[](float z, const Layer *l1) { return z < l1->slice_z; });
|
|
|
|
auto last_layer = std::upper_bound(layers.begin(), layers.end(), float(max_z + EPSILON),
|
|
|
|
[](float z, const Layer *l1) { return z < l1->slice_z; });
|
|
|
|
--last_layer;
|
|
|
|
|
|
|
|
for (auto layer_it = first_layer; layer_it != (last_layer + 1); ++layer_it) {
|
|
|
|
const Layer *layer = *layer_it;
|
|
|
|
size_t layer_idx = layer_it - layers.begin();
|
2023-03-29 07:22:21 +00:00
|
|
|
if (input_expolygons[layer_idx].empty() || is_less(layer->slice_z, facet[0].z()) || is_less(facet[2].z(), layer->slice_z))
|
2022-07-15 15:37:19 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// https://kandepet.com/3d-printing-slicing-3d-objects/
|
|
|
|
float t = (float(layer->slice_z) - facet[0].z()) / (facet[2].z() - facet[0].z());
|
|
|
|
Vec3f line_start_f = facet[0] + t * (facet[2] - facet[0]);
|
|
|
|
Vec3f line_end_f;
|
|
|
|
|
2023-03-29 07:22:21 +00:00
|
|
|
// BBS: When one side of a triangle coincides with the slice_z.
|
|
|
|
if ((is_equal(facet[0].z(), facet[1].z()) && is_equal(facet[1].z(), layer->slice_z))
|
|
|
|
|| (is_equal(facet[1].z(), facet[2].z()) && is_equal(facet[1].z(), layer->slice_z))) {
|
|
|
|
line_end_f = facet[1];
|
|
|
|
}
|
|
|
|
else if (facet[1].z() > layer->slice_z) {
|
2022-07-15 15:37:19 +00:00
|
|
|
// [P0, P2] and [P0, P1]
|
|
|
|
float t1 = (float(layer->slice_z) - facet[0].z()) / (facet[1].z() - facet[0].z());
|
|
|
|
line_end_f = facet[0] + t1 * (facet[1] - facet[0]);
|
|
|
|
} else {
|
|
|
|
// [P0, P2] and [P1, P2]
|
|
|
|
float t2 = (float(layer->slice_z) - facet[1].z()) / (facet[2].z() - facet[1].z());
|
|
|
|
line_end_f = facet[1] + t2 * (facet[2] - facet[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Line line_to_test(Point(scale_(line_start_f.x()), scale_(line_start_f.y())),
|
|
|
|
Point(scale_(line_end_f.x()), scale_(line_end_f.y())));
|
|
|
|
line_to_test.translate(-print_object.center_offset());
|
|
|
|
|
|
|
|
// BoundingBoxes for EdgeGrids are computed from printable regions. It is possible that the painted line (line_to_test) could
|
|
|
|
// be outside EdgeGrid's BoundingBox, for example, when the negative volume is used on the painted area (GH #7618).
|
|
|
|
// To ensure that the painted line is always inside EdgeGrid's BoundingBox, it is clipped by EdgeGrid's BoundingBox in cases
|
|
|
|
// when any of the endpoints of the line are outside the EdgeGrid's BoundingBox.
|
2024-10-18 08:42:12 +00:00
|
|
|
const BoundingBox& edge_grid_bbox = edge_grids[layer_idx].bbox();
|
2024-03-28 06:00:37 +00:00
|
|
|
if (!edge_grid_bbox.contains(line_to_test.a) || !edge_grid_bbox.contains(line_to_test.b)) {
|
2022-07-15 15:37:19 +00:00
|
|
|
// If the painted line (line_to_test) is entirely outside EdgeGrid's BoundingBox, skip this painted line.
|
|
|
|
if (!edge_grid_bbox.overlap(BoundingBox(Points{line_to_test.a, line_to_test.b})) ||
|
|
|
|
!line_to_test.clip_with_bbox(edge_grid_bbox))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t mutex_idx = layer_idx & 0x3F;
|
|
|
|
assert(mutex_idx < painted_lines_mutex.size());
|
|
|
|
|
|
|
|
PaintedLineVisitor visitor(edge_grids[layer_idx], painted_lines[layer_idx], painted_lines_mutex[mutex_idx], 16);
|
|
|
|
visitor.line_to_test = line_to_test;
|
|
|
|
visitor.color = int(extruder_idx);
|
2024-09-19 06:06:06 +00:00
|
|
|
edge_grids[layer_idx].visit_cells_intersecting_line(line_to_test.a, line_to_test.b, visitor, true);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
2024-09-19 06:06:06 +00:00
|
|
|
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
|
2022-07-15 15:37:19 +00:00
|
|
|
}); // end of parallel_for
|
2024-09-19 06:06:06 +00:00
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
2024-09-19 06:06:06 +00:00
|
|
|
#ifndef MM_SEGMENTATION_DEBUG_PAINT_LINE
|
2022-07-15 15:37:19 +00:00
|
|
|
}); // end of parallel_for
|
2024-09-19 06:06:06 +00:00
|
|
|
#endif
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - projection of painted triangles - end";
|
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - painted layers count: "
|
2022-07-15 15:37:19 +00:00
|
|
|
<< std::count_if(painted_lines.begin(), painted_lines.end(), [](const std::vector<PaintedLine> &pl) { return !pl.empty(); });
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - layers segmentation in parallel - begin";
|
2022-07-15 15:37:19 +00:00
|
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, num_layers), [&edge_grids, &input_expolygons, &painted_lines, &segmented_regions, &num_extruders, &throw_on_cancel_callback](const tbb::blocked_range<size_t> &range) {
|
|
|
|
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
if (!painted_lines[layer_idx].empty()) {
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
|
|
|
export_painted_lines_to_svg(debug_out_path("0-mm-painted-lines-%d-%d.svg", layer_idx, iRun), {painted_lines[layer_idx]}, input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
std::vector<std::vector<PaintedLine>> post_processed_painted_lines = post_process_painted_lines(edge_grids[layer_idx].contours(), std::move(painted_lines[layer_idx]));
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
|
|
|
export_painted_lines_to_svg(debug_out_path("1-mm-painted-lines-post-processed-%d-%d.svg", layer_idx, iRun), post_processed_painted_lines, input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_PAINTED_LINES
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
std::vector<ColoredLines> color_poly = colorize_contours(edge_grids[layer_idx].contours(), post_processed_painted_lines);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS
|
|
|
|
export_colorized_polygons_to_svg(debug_out_path("2-mm-colorized_polygons-%d-%d.svg", layer_idx, iRun), color_poly, input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
assert(!color_poly.empty());
|
|
|
|
assert(!color_poly.front().empty());
|
|
|
|
if (has_layer_only_one_color(color_poly)) {
|
|
|
|
// If the whole layer is painted using the same color, it is not needed to construct a Voronoi diagram for the segmentation of this layer.
|
|
|
|
segmented_regions[layer_idx][size_t(color_poly.front().front().color)] = input_expolygons[layer_idx];
|
|
|
|
} else {
|
2024-05-30 12:23:23 +00:00
|
|
|
MMU_Graph graph = build_graph(layer_idx, color_poly);
|
|
|
|
remove_multiple_edges_in_vertices(graph, color_poly);
|
|
|
|
graph.remove_nodes_with_one_arc();
|
|
|
|
segmented_regions[layer_idx] = extract_colored_segments(graph, num_extruders);
|
|
|
|
//segmented_regions[layer_idx] = extract_colored_segments(color_poly, num_extruders, layer_idx);
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_REGIONS
|
|
|
|
export_regions_to_svg(debug_out_path("3-mm-regions-sides-%d-%d.svg", layer_idx, iRun), segmented_regions[layer_idx], input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_REGIONS
|
2022-07-15 15:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}); // end of parallel_for
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "MM segmentation - layers segmentation in parallel - end";
|
2022-07-15 15:37:19 +00:00
|
|
|
throw_on_cancel_callback();
|
|
|
|
|
2024-06-30 15:25:15 +00:00
|
|
|
auto interlocking_beam = print_object.config().interlocking_beam;
|
|
|
|
if (auto max_width = print_object.config().mmu_segmented_region_max_width, interlocking_depth = print_object.config().mmu_segmented_region_interlocking_depth;
|
|
|
|
!interlocking_beam && (max_width > 0.f || interlocking_depth > 0.f)) {
|
2023-09-01 03:27:35 +00:00
|
|
|
cut_segmented_layers(input_expolygons, segmented_regions, float(scale_(max_width)), float(scale_(interlocking_depth)), throw_on_cancel_callback);
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
// The first index is extruder number (includes default extruder), and the second one is layer number
|
|
|
|
std::vector<std::vector<ExPolygons>> top_and_bottom_layers = mmu_segmentation_top_and_bottom_layers(print_object, input_expolygons, throw_on_cancel_callback);
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
|
|
|
|
std::vector<std::vector<ExPolygons>> segmented_regions_merged = merge_segmented_layers(segmented_regions, std::move(top_and_bottom_layers), num_extruders, throw_on_cancel_callback);
|
|
|
|
throw_on_cancel_callback();
|
|
|
|
|
ENH: modify the multi-material segmentation and voronoi
This patch is cherry pick from Prusa, thanks to Prusa
Rework multi-material segmentation to work directly on the Voronoi diagram without creating a copy of it.
Previous algorithms assume that they can get an invalid Voronoi diagram. Because of that, during the multi-material segmentation, a copy of the Voronoi diagram was created, and there were several attempts to fix missing vertices and edges. But as it shows, this wasn't a good enough approach and sometimes led to several issues like bleeding layers.
After generalization, our approach for detection and repairs of invalid Voronoi diagrams from Arachne, we could assume that multi-material segmentation gets non-invalid Voronoi diagrams.
With this assumption, we reimplement multi-materials segmentation to work directly on the Voronoi diagram. That should make multi-material segmentation more stable.
So, this should fix several issues like bleeding layers. Also, memory consumption should decrease by a lot. Also, there should be some speedup of multi-materials segmentation.
Jira: none
Change-Id: I72aa6e1f9634d9ee8759aa469a0b39a36ace62f5
2024-03-27 12:48:03 +00:00
|
|
|
#ifdef MM_SEGMENTATION_DEBUG_REGIONS
|
|
|
|
for (size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx)
|
|
|
|
export_regions_to_svg(debug_out_path("4-mm-regions-merged-%d-%d.svg", layer_idx, iRun), segmented_regions_merged[layer_idx], input_expolygons[layer_idx]);
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG_REGIONS
|
|
|
|
|
|
|
|
#ifdef MM_SEGMENTATION_DEBUG
|
|
|
|
++iRun;
|
|
|
|
#endif // MM_SEGMENTATION_DEBUG
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
return segmented_regions_merged;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Slic3r
|