Added a lot of debugging outputs (SVG) into SkeletalTrapezoidation.

This commit is contained in:
Lukáš Hejl 2022-08-10 16:25:15 +02:00
parent 4d19eb9ace
commit e838acdcd1
4 changed files with 186 additions and 25 deletions

View File

@ -22,8 +22,6 @@
#define SKELETAL_TRAPEZOIDATION_BEAD_SEARCH_MAX 1000 //A limit to how long it'll keep searching for adjacent beads. Increasing will re-use beadings more often (saving performance), but search longer for beading (costing performance).
//#define ARACHNE_DEBUG
namespace boost::polygon {
template<> struct geometry_concept<Slic3r::Arachne::PolygonsSegmentIndex>
@ -46,6 +44,71 @@ template<> struct segment_traits<Slic3r::Arachne::PolygonsSegmentIndex>
namespace Slic3r::Arachne
{
#ifdef ARACHNE_DEBUG
static void export_graph_to_svg(const std::string &path,
SkeletalTrapezoidationGraph &graph,
const Polygons &polys,
const std::vector<std::shared_ptr<LineJunctions>> &edge_junctions = {},
const bool beat_count = true,
const bool transition_middles = true,
const bool transition_ends = true)
{
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "green", "yellow"};
coordf_t stroke_width = scale_(0.03);
BoundingBox bbox = get_extents(polys);
for (const auto &node : graph.nodes)
bbox.merge(node.p);
bbox.offset(scale_(1.));
::Slic3r::SVG svg(path.c_str(), bbox);
for (const auto &line : to_lines(polys))
svg.draw(line, "gray", stroke_width);
for (const auto &edge : graph.edges)
svg.draw(Line(edge.from->p, edge.to->p), (edge.data.centralIsSet() && edge.data.isCentral()) ? "blue" : "cyan", stroke_width);
for (const auto &line_junction : edge_junctions)
for (const auto &extrusion_junction : *line_junction)
svg.draw(extrusion_junction.p, "orange", coord_t(stroke_width * 2.));
if (beat_count) {
for (const auto &node : graph.nodes) {
svg.draw(node.p, "red", coord_t(stroke_width * 1.6));
svg.draw_text(node.p, std::to_string(node.data.bead_count).c_str(), "black", 1);
}
}
if (transition_middles) {
for (auto &edge : graph.edges) {
if (std::shared_ptr<std::list<SkeletalTrapezoidationEdge::TransitionMiddle>> transitions = edge.data.getTransitions(); transitions) {
for (auto &transition : *transitions) {
Line edge_line = Line(edge.to->p, edge.from->p);
double edge_length = edge_line.length();
Point pt = edge_line.a + (edge_line.vector().cast<double>() * (double(transition.pos) / edge_length)).cast<coord_t>();
svg.draw(pt, "magenta", coord_t(stroke_width * 1.5));
svg.draw_text(pt, std::to_string(transition.lower_bead_count).c_str(), "black", 1);
}
}
}
}
if (transition_ends) {
for (auto &edge : graph.edges) {
if (std::shared_ptr<std::list<SkeletalTrapezoidationEdge::TransitionEnd>> transitions = edge.data.getTransitionEnds(); transitions) {
for (auto &transition : *transitions) {
Line edge_line = Line(edge.to->p, edge.from->p);
double edge_length = edge_line.length();
Point pt = edge_line.a + (edge_line.vector().cast<double>() * (double(transition.pos) / edge_length)).cast<coord_t>();
svg.draw(pt, transition.is_lower_end ? "green" : "lime", coord_t(stroke_width * 1.5));
svg.draw_text(pt, std::to_string(transition.lower_bead_count).c_str(), "black", 1);
}
}
}
}
}
#endif
SkeletalTrapezoidation::node_t& SkeletalTrapezoidation::makeNode(vd_t::vertex_type& vd_node, Point p)
{
auto he_node_it = vd_node_to_he_node.find(&vd_node);
@ -489,6 +552,10 @@ inline static void rotate_back_skeletal_trapezoidation_graph_after_fix(SkeletalT
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
{
#ifdef ARACHNE_DEBUG
this->outline = polys;
#endif
// Check self intersections.
assert([&polys]() -> bool {
EdgeGrid::Grid grid;
@ -517,7 +584,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
Geometry::VoronoiDiagram voronoi_diagram;
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
#ifdef ARACHNE_DEBUG
#ifdef ARACHNE_DEBUG_VORONOI
{
static int iRun = 0;
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
@ -694,45 +761,62 @@ void SkeletalTrapezoidation::separatePointyQuadEndNodes()
// vvvvvvvvvvvvvvvvvvvvv
//
#if 0
static void export_graph_to_svg(const std::string &path, const SkeletalTrapezoidationGraph &graph, const Polygons &polys)
{
const std::vector<std::string> colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "green", "yellow"};
coordf_t stroke_width = scale_(0.05);
BoundingBox bbox;
for (const auto &node : graph.nodes)
bbox.merge(node.p);
bbox.offset(scale_(1.));
::Slic3r::SVG svg(path.c_str(), bbox);
for (const auto &line : to_lines(polys))
svg.draw(line, "red", stroke_width);
for (const auto &edge : graph.edges)
svg.draw(Line(edge.from->p, edge.to->p), "cyan", scale_(0.01));
}
#endif
void SkeletalTrapezoidation::generateToolpaths(std::vector<VariableWidthLines> &generated_toolpaths, bool filter_outermost_central_edges)
{
#ifdef ARACHNE_DEBUG
static int iRun = 0;
#endif
p_generated_toolpaths = &generated_toolpaths;
updateIsCentral();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-updateIsCentral-final-%d.svg", iRun), this->graph, this->outline);
#endif
filterCentral(central_filter_dist);
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-filterCentral-final-%d.svg", iRun), this->graph, this->outline);
#endif
if (filter_outermost_central_edges)
filterOuterCentral();
updateBeadCount();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-updateBeadCount-final-%d.svg", iRun), this->graph, this->outline);
#endif
filterNoncentralRegions();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-filterNoncentralRegions-final-%d.svg", iRun), this->graph, this->outline);
#endif
generateTransitioningRibs();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateTransitioningRibs-final-%d.svg", iRun), this->graph, this->outline);
#endif
generateExtraRibs();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateExtraRibs-final-%d.svg", iRun), this->graph, this->outline);
#endif
generateSegments();
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateSegments-final-%d.svg", iRun), this->graph, this->outline);
#endif
#ifdef ARACHNE_DEBUG
++iRun;
#endif
}
void SkeletalTrapezoidation::updateIsCentral()
@ -944,11 +1028,24 @@ void SkeletalTrapezoidation::generateTransitioningRibs()
filterTransitionMids();
#ifdef ARACHNE_DEBUG
static int iRun = 0;
export_graph_to_svg(debug_out_path("ST-generateTransitioningRibs-mids-%d.svg", iRun++), this->graph, this->outline);
#endif
ptr_vector_t<std::list<TransitionEnd>> edge_transition_ends; // We only map the half edge in the upward direction. mapped items are not sorted
generateAllTransitionEnds(edge_transition_ends);
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateTransitioningRibs-ends-%d.svg", iRun++), this->graph, this->outline);
#endif
applyTransitions(edge_transition_ends);
// Note that the shared pointer lists will be out of scope and thus destroyed here, since the remaining refs are weak_ptr.
#ifdef ARACHNE_DEBUG
++iRun;
#endif
}
@ -1668,17 +1765,38 @@ void SkeletalTrapezoidation::generateSegments()
}
}
}
#ifdef ARACHNE_DEBUG
static int iRun = 0;
export_graph_to_svg(debug_out_path("ST-generateSegments-before-propagation-%d.svg", iRun), this->graph, this->outline);
#endif
propagateBeadingsUpward(upward_quad_mids, node_beadings);
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateSegments-upward-propagation-%d.svg", iRun), this->graph, this->outline);
#endif
propagateBeadingsDownward(upward_quad_mids, node_beadings);
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateSegments-downward-propagation-%d.svg", iRun), this->graph, this->outline);
#endif
ptr_vector_t<LineJunctions> edge_junctions; // junctions ordered high R to low R
generateJunctions(node_beadings, edge_junctions);
#ifdef ARACHNE_DEBUG
export_graph_to_svg(debug_out_path("ST-generateSegments-junctions-%d.svg", iRun), this->graph, this->outline, edge_junctions);
#endif
connectJunctions(edge_junctions);
generateLocalMaximaSingleBeads();
#ifdef ARACHNE_DEBUG
++iRun;
#endif
}
SkeletalTrapezoidation::edge_t* SkeletalTrapezoidation::getQuadMaxRedgeTo(edge_t* quad_start_edge)

View File

@ -20,6 +20,9 @@
#include "SkeletalTrapezoidationGraph.hpp"
#include "../Geometry/Voronoi.hpp"
//#define ARACHNE_DEBUG
//#define ARACHNE_DEBUG_VORONOI
namespace Slic3r::Arachne
{
@ -123,6 +126,10 @@ public:
*/
void generateToolpaths(std::vector<VariableWidthLines> &generated_toolpaths, bool filter_outermost_central_edges = false);
#ifdef ARACHNE_DEBUG
Polygons outline;
#endif
protected:
/*!
* Auxiliary for referencing one transition along an edge which may contain multiple transitions

View File

@ -12,6 +12,13 @@
#include <stack>
#include <unordered_map>
//#define ARACHNE_DEBUG
#ifdef ARACHNE_DEBUG
#include "SVG.hpp"
#include "Utils.hpp"
#endif
namespace Slic3r {
ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance)
@ -537,6 +544,27 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
return extrusion_coll;
}
#ifdef ARACHNE_DEBUG
static void export_perimeters_to_svg(const std::string &path, const Polygons &contours, const std::vector<Arachne::VariableWidthLines> &perimeters, const ExPolygons &infill_area)
{
coordf_t stroke_width = scale_(0.03);
BoundingBox bbox = get_extents(contours);
bbox.offset(scale_(1.));
::Slic3r::SVG svg(path.c_str(), bbox);
svg.draw(infill_area, "cyan");
for (const Arachne::VariableWidthLines &perimeter : perimeters)
for (const Arachne::ExtrusionLine &extrusion_line : perimeter) {
ThickPolyline thick_polyline = to_thick_polyline(extrusion_line);
svg.draw({thick_polyline}, "green", "blue", stroke_width);
}
for (const Line &line : to_lines(contours))
svg.draw(line, "red", stroke_width);
}
#endif
// Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
void PerimeterGenerator::process_arachne()
@ -578,6 +606,13 @@ void PerimeterGenerator::process_arachne()
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
loop_number = int(perimeters.size()) - 1;
#ifdef ARACHNE_DEBUG
{
static int iRun = 0;
export_perimeters_to_svg(debug_out_path("arachne-perimeters-%d-%d.svg", layer_id, iRun++), to_polygons(last), perimeters, union_ex(wallToolPaths.getInnerContour()));
}
#endif
// All closed ExtrusionLine should have the same the first and the last point.
// But in rare cases, Arachne produce ExtrusionLine marked as closed but without
// equal the first and the last point.

View File

@ -287,9 +287,10 @@ void SVG::draw_text(const Point &pt, const char *text, const char *color, const
void SVG::draw_legend(const Point &pt, const char *text, const char *color, const coordf_t font_size)
{
fprintf(this->f,
R"(<circle cx="%f" cy="%f" r="10" fill="%s"/>)",
R"(<circle cx="%f" cy="%f" r="%f" fill="%s"/>)",
to_svg_x(float(pt.x() - origin.x())),
to_svg_y(float(pt.y() - origin.y())),
font_size,
color);
fprintf(this->f,
R"(<text x="%f" y="%f" font-family="sans-serif" font-size="%fpx" fill="%s">%s</text>)",