mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 06:26:06 +08:00
Fix sampling selfconnected thiny part of island sampled on voronoi skelet
This commit is contained in:
parent
54bc516da6
commit
5a38e9b4b3
@ -1,6 +1,7 @@
|
|||||||
#ifndef slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
|
#ifndef slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
|
||||||
#define slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
|
#define slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_
|
||||||
|
|
||||||
|
#include "SampleConfig.hpp"
|
||||||
#include "../SupportPointGenerator.hpp"
|
#include "../SupportPointGenerator.hpp"
|
||||||
|
|
||||||
namespace Slic3r::sla {
|
namespace Slic3r::sla {
|
||||||
@ -14,16 +15,16 @@ public:
|
|||||||
SampleConfigFactory() = delete;
|
SampleConfigFactory() = delete;
|
||||||
|
|
||||||
// factory method to iniciate config
|
// factory method to iniciate config
|
||||||
static SampleConfig create(const SupportPointGenerator::Config &config)
|
static SampleConfig create(const SupportPointGeneratorConfig &config)
|
||||||
{
|
{
|
||||||
coord_t head_diameter = scale_(config.head_diameter);
|
coord_t head_diameter = scale_((double)config.head_diameter.min);
|
||||||
coord_t min_distance = head_diameter/2 + scale_(config.minimal_distance);
|
coord_t minimal_distance = head_diameter * 7;
|
||||||
coord_t max_distance = 3 * min_distance;
|
coord_t min_distance = head_diameter / 2 + minimal_distance;
|
||||||
coord_t sample_multiplicator = 8; // allign is made by selecting from samples
|
coord_t max_distance = 3 * min_distance;
|
||||||
|
|
||||||
// TODO: find valid params !!!!
|
// TODO: find valid params !!!!
|
||||||
SampleConfig result;
|
SampleConfig result;
|
||||||
result.max_distance = max_distance / sample_multiplicator;
|
result.max_distance = max_distance;
|
||||||
result.half_distance = result.max_distance / 2;
|
result.half_distance = result.max_distance / 2;
|
||||||
result.head_radius = head_diameter / 2;
|
result.head_radius = head_diameter / 2;
|
||||||
result.minimal_distance_from_outline = result.head_radius;
|
result.minimal_distance_from_outline = result.head_radius;
|
||||||
@ -73,7 +74,7 @@ public:
|
|||||||
result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter;
|
result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter;
|
||||||
assert(result.min_width_for_outline_support <= result.max_width_for_center_support_line);
|
assert(result.min_width_for_outline_support <= result.max_width_for_center_support_line);
|
||||||
|
|
||||||
result.outline_sample_distance = result.max_distance/20;
|
result.outline_sample_distance = result.max_distance/4;
|
||||||
|
|
||||||
// Align support points
|
// Align support points
|
||||||
// TODO: propagate print resolution
|
// TODO: propagate print resolution
|
||||||
|
@ -23,14 +23,61 @@
|
|||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
|
|
||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
|
||||||
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
|
||||||
|
|
||||||
|
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH "C:/data/temp/Align_once_<<COUNTER>>.svg"
|
||||||
|
//#define SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH "C:/data/temp/island_cell.svg"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::sla;
|
using namespace Slic3r::sla;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const ExPolygon &get_expolygon_with_biggest_contour(const ExPolygons &expolygons) {
|
||||||
|
assert(!expolygons.empty());
|
||||||
|
const ExPolygon *biggest = &expolygons.front();
|
||||||
|
for (size_t index = 1; index < expolygons.size(); ++index) {
|
||||||
|
const ExPolygon *current = &expolygons[index];
|
||||||
|
if (biggest->contour.size() < current->contour.size())
|
||||||
|
biggest = current;
|
||||||
|
}
|
||||||
|
return *biggest;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SupportIslandPoints SampleIslandUtils::uniform_cover_island(
|
||||||
|
const ExPolygon &island, const SampleConfig &config
|
||||||
|
) {
|
||||||
|
// closing similar to FDM arachne do before voronoi
|
||||||
|
// inspired by make_expolygons inside TriangleMeshSlicer
|
||||||
|
float closing_radius = scale_(0.0499f);
|
||||||
|
float offset_out = closing_radius;
|
||||||
|
float offset_in = -closing_radius;
|
||||||
|
ExPolygons closed_expolygons = offset2_ex({island}, offset_out, offset_in); // mitter
|
||||||
|
ExPolygon closed_expolygon = get_expolygon_with_biggest_contour(closed_expolygons);
|
||||||
|
|
||||||
|
// "Close" operation create neighbor pixel for sharp triangle tip
|
||||||
|
double tolerance = scale_(0.05);
|
||||||
|
ExPolygons simplified_expolygons = island.simplify(tolerance);
|
||||||
|
ExPolygon simplified_expolygon = get_expolygon_with_biggest_contour(simplified_expolygons);
|
||||||
|
|
||||||
|
Slic3r::Geometry::VoronoiDiagram vd;
|
||||||
|
Lines lines = to_lines(simplified_expolygon);
|
||||||
|
vd.construct_voronoi(lines.begin(), lines.end());
|
||||||
|
Slic3r::Voronoi::annotate_inside_outside(vd, lines);
|
||||||
|
VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines);
|
||||||
|
VoronoiGraph::ExPath longest_path;
|
||||||
|
|
||||||
|
SupportIslandPoints samples =
|
||||||
|
SampleIslandUtils::sample_voronoi_graph(skeleton, lines, config, longest_path);
|
||||||
|
|
||||||
|
// allign samples
|
||||||
|
SampleIslandUtils::align_samples(samples, island, config);
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Slic3r::Vec2f> SampleIslandUtils::sample_expolygon(
|
std::vector<Slic3r::Vec2f> SampleIslandUtils::sample_expolygon(
|
||||||
const ExPolygon &expoly, float samples_per_mm2)
|
const ExPolygon &expoly, float samples_per_mm2)
|
||||||
{
|
{
|
||||||
@ -440,115 +487,145 @@ void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Polygons create_voronoi_cells_boost(const Points &points, coord_t max_distance) {
|
||||||
|
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||||
|
VD vd;
|
||||||
|
vd.construct_voronoi(points.begin(), points.end());
|
||||||
|
assert(points.size() == vd.cells().size());
|
||||||
|
Polygons cells(points.size());
|
||||||
|
for (const VD::cell_type &cell : vd.cells())
|
||||||
|
cells[cell.source_index()] = VoronoiGraphUtils::to_polygon(cell, points, max_distance);
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string replace_first(
|
||||||
|
std::string s,
|
||||||
|
const std::string& toReplace,
|
||||||
|
const std::string& replaceWith
|
||||||
|
) {
|
||||||
|
std::size_t pos = s.find(toReplace);
|
||||||
|
if (pos == std::string::npos) return s;
|
||||||
|
s.replace(pos, toReplace.length(), replaceWith);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_points_in_distance(const Slic3r::Point & p,
|
bool is_points_in_distance(const Slic3r::Point & p,
|
||||||
const Slic3r::Points &points,
|
const Slic3r::Points &points,
|
||||||
double max_distance)
|
double max_distance)
|
||||||
{
|
{
|
||||||
for (const auto &p2 : points) {
|
for (const auto &p2 : points) {
|
||||||
double d = (p - p2).cast<double>().norm();
|
double d = (p - p2).cast<double>().norm();
|
||||||
if (d > max_distance) return false;
|
if (d > max_distance)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
|
coord_t SampleIslandUtils::align_once(
|
||||||
const ExPolygon & island,
|
SupportIslandPoints &samples,
|
||||||
const SampleConfig & config)
|
const ExPolygon &island,
|
||||||
|
const SampleConfig &config)
|
||||||
{
|
{
|
||||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
// IMPROVE1: add accessor to point coordinate do not copy points
|
||||||
VD vd;
|
// IMPROVE2: add filter for create cell polygon only for moveable samples
|
||||||
Slic3r::Points points = SampleIslandUtils::to_points(samples);
|
Slic3r::Points points = SampleIslandUtils::to_points(samples);
|
||||||
coord_t max_move = 0;
|
|
||||||
|
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
Polygons cell_polygons = //*
|
||||||
std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap
|
create_voronoi_cells_boost
|
||||||
std::string color_point_cell = "lightgray"; // bigger than island but NOT self overlap
|
/*/
|
||||||
|
create_voronoi_cells_cgal
|
||||||
|
//*/
|
||||||
|
(points, config.max_distance);
|
||||||
|
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
|
std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap
|
||||||
|
std::string color_point_cell = "lightgray"; // bigger than island but NOT self overlap
|
||||||
std::string color_island_cell_intersection = "gray"; // Should full overlap island !!
|
std::string color_island_cell_intersection = "gray"; // Should full overlap island !!
|
||||||
std::string color_old_point = "lightblue"; // Center of island cell intersection
|
std::string color_old_point = "lightblue"; // Center of island cell intersection
|
||||||
std::string color_wanted_point = "darkblue"; // Center of island cell intersection
|
std::string color_wanted_point = "darkblue"; // Center of island cell intersection
|
||||||
std::string color_new_point = "blue"; // Center of island cell intersection
|
std::string color_new_point = "blue"; // Center of island cell intersection
|
||||||
std::string color_static_point = "black";
|
std::string color_static_point = "black";
|
||||||
static int counter = 0;
|
|
||||||
BoundingBox bbox(island.contour.points);
|
BoundingBox bbox(island.contour.points);
|
||||||
|
static int counter = 0;
|
||||||
|
Slic3r::SVG svg(replace_first(SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH,
|
||||||
|
"<<COUNTER>>", std::to_string(counter++)).c_str(), bbox);
|
||||||
|
svg.draw(island, color_of_island);
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
|
|
||||||
SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox);
|
// Maximal move during align each loop of align it should decrease
|
||||||
svg.draw(island, color_of_island );
|
coord_t max_move = 0;
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
for (size_t i = 0; i < points.size(); i++) {
|
||||||
|
const Polygon &cell_polygon = cell_polygons[i];
|
||||||
|
SupportIslandPointPtr &sample = samples[i];
|
||||||
|
|
||||||
// create voronoi diagram with points
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
vd.construct_voronoi(points.begin(), points.end());
|
if (!sample->can_move()) { // draww freezed support points
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
|
|
||||||
static int vd_counter = 0;
|
|
||||||
BoundingBox bbox(island);
|
|
||||||
std::string name = "align_VD_" + std::to_string(vd_counter++) + ".svg";
|
|
||||||
SVG svg(name.c_str(), bbox);
|
|
||||||
svg.draw(island);
|
|
||||||
for (const Point &point : points) {
|
|
||||||
size_t index = &point - &points.front();
|
|
||||||
svg.draw(point, "black", config.head_radius);
|
|
||||||
svg.draw_text(point + Point(config.head_radius,0), std::to_string(index).c_str(), "black");
|
|
||||||
}
|
|
||||||
Lines island_lines = to_lines(island);
|
|
||||||
svg.draw(island_lines, "blue");
|
|
||||||
for (const auto &edge: vd.edges()) {
|
|
||||||
std::optional<Line> line =
|
|
||||||
VoronoiGraphUtils::to_line(edge, points, config.max_distance);
|
|
||||||
if (!line.has_value()) continue;
|
|
||||||
svg.draw(*line, "green", 1e6);
|
|
||||||
}
|
|
||||||
svg.Close();
|
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
|
|
||||||
size_t max_move_index = -1;
|
|
||||||
for (const VD::cell_type &cell : vd.cells()) {
|
|
||||||
SupportIslandPointPtr &sample = samples[cell.source_index()];
|
|
||||||
|
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
|
||||||
if (!sample->can_move()) {
|
|
||||||
svg.draw(sample->point, color_static_point, config.head_radius);
|
svg.draw(sample->point, color_static_point, config.head_radius);
|
||||||
svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str());
|
svg.draw_text(sample->point + Point(config.head_radius, 0),
|
||||||
|
SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str());
|
||||||
}
|
}
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
if (!sample->can_move()) continue;
|
if (!sample->can_move())
|
||||||
Polygon cell_polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance);
|
continue;
|
||||||
|
|
||||||
|
// polygon must be at least triangle
|
||||||
|
assert(cell_polygon.points.size() >= 3);
|
||||||
|
if (cell_polygon.points.size() < 3)
|
||||||
|
continue; // do not align point with invalid cell
|
||||||
|
|
||||||
|
// IMPROVE: add intersection polygon with expolygon
|
||||||
Polygons intersections = Slic3r::intersection(island, ExPolygon(cell_polygon));
|
Polygons intersections = Slic3r::intersection(island, ExPolygon(cell_polygon));
|
||||||
const Polygon *island_cell = nullptr;
|
const Polygon *island_cell = nullptr;
|
||||||
for (const Polygon &intersection : intersections) {
|
for (const Polygon &intersection : intersections) {
|
||||||
if (intersection.contains(sample->point)) {
|
if (intersection.contains(sample->point)) {
|
||||||
island_cell = &intersection;
|
island_cell = &intersection;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intersection island and cell made by suppot point
|
||||||
|
// must generate polygon containing initial source for voronoi cell
|
||||||
|
// otherwise it is invalid voronoi diagram
|
||||||
assert(island_cell != nullptr);
|
assert(island_cell != nullptr);
|
||||||
Point center = island_cell->centroid();
|
if (island_cell == nullptr)
|
||||||
/*{
|
continue;
|
||||||
SVG cell_svg("island_cell.svg", island_cell->points);
|
|
||||||
cell_svg.draw(cell_polygon, "lightgray");
|
// new aligned position for sample
|
||||||
cell_svg.draw(points, "darkgray", config.head_radius);
|
Point island_cell_center = island_cell->centroid();
|
||||||
cell_svg.draw(*island_cell, "gray");
|
|
||||||
cell_svg.draw(sample->point, "green", config.head_radius);
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH
|
||||||
cell_svg.draw(center, "black", config.head_radius);
|
{SVG cell_svg(SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH, island_cell->points);
|
||||||
}*/
|
cell_svg.draw(island, "lightgreen");
|
||||||
assert(is_points_in_distance(center, island_cell->points, config.max_distance));
|
cell_svg.draw(cell_polygon, "lightgray");
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
cell_svg.draw(points, "darkgray", config.head_radius);
|
||||||
|
cell_svg.draw(*island_cell, "gray");
|
||||||
|
cell_svg.draw(sample->point, "green", config.head_radius);
|
||||||
|
cell_svg.draw(island_cell_center, "black", config.head_radius);}
|
||||||
|
#endif //SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH
|
||||||
|
// Check that still points do not have bigger distance from each other
|
||||||
|
assert(is_points_in_distance(island_cell_center, island_cell->points, config.max_distance));
|
||||||
|
|
||||||
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
svg.draw(cell_polygon, color_point_cell);
|
svg.draw(cell_polygon, color_point_cell);
|
||||||
svg.draw(*island_cell, color_island_cell_intersection);
|
svg.draw(*island_cell, color_island_cell_intersection);
|
||||||
svg.draw(Line(sample->point, center), color_wanted_point, config.head_radius / 5);
|
svg.draw(Line(sample->point, island_cell_center), color_wanted_point, config.head_radius / 5);
|
||||||
svg.draw(sample->point, color_old_point, config.head_radius);
|
svg.draw(sample->point, color_old_point, config.head_radius);
|
||||||
svg.draw(center, color_wanted_point, config.head_radius); // wanted position
|
svg.draw(island_cell_center, color_wanted_point, config.head_radius); // wanted position
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
coord_t act_move = sample->move(center);
|
|
||||||
if (max_move < act_move) {
|
// say samples to use its restriction to change posion close to center
|
||||||
|
coord_t act_move = sample->move(island_cell_center);
|
||||||
|
if (max_move < act_move)
|
||||||
max_move = act_move;
|
max_move = act_move;
|
||||||
max_move_index = cell.source_index();
|
|
||||||
}
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
|
||||||
svg.draw(sample->point, color_new_point, config.head_radius);
|
svg.draw(sample->point, color_new_point, config.head_radius);
|
||||||
svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str());
|
svg.draw_text(sample->point + Point(config.head_radius, 0),
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str());
|
||||||
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
}
|
}
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
|
||||||
svg.Close();
|
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
|
||||||
return max_move;
|
return max_move;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,6 +974,7 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
|
|||||||
SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg",
|
SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg",
|
||||||
LineUtils::create_bounding_box(lines));
|
LineUtils::create_bounding_box(lines));
|
||||||
VoronoiGraphUtils::draw(svg, graph, lines, config.head_radius / 10, true);
|
VoronoiGraphUtils::draw(svg, graph, lines, config.head_radius / 10, true);
|
||||||
|
VoronoiGraphUtils::draw(svg, longest_path, config.head_radius / 10);
|
||||||
}
|
}
|
||||||
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
|
|
||||||
@ -1031,6 +1109,83 @@ void SampleIslandUtils::sample_field(const VoronoiGraph::Position &field_start,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool pop_start(
|
||||||
|
SampleIslandUtils::CenterStart &start,
|
||||||
|
SampleIslandUtils::CenterStarts &starts,
|
||||||
|
const std::set<const VoronoiGraph::Node *> &done
|
||||||
|
) {
|
||||||
|
// skip done starts
|
||||||
|
if (starts.empty())
|
||||||
|
return false; // no start
|
||||||
|
while (done.find(starts.back().neighbor->node) != done.end()) {
|
||||||
|
starts.pop_back();
|
||||||
|
if (starts.empty())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// fill new start
|
||||||
|
start = std::move(starts.back());
|
||||||
|
starts.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool add_support_on_neighbor_edge(
|
||||||
|
const VoronoiGraph::Node::Neighbor *neighbor,
|
||||||
|
coord_t& support_in,
|
||||||
|
SupportIslandPoints &results,
|
||||||
|
const SampleConfig &config
|
||||||
|
) {
|
||||||
|
bool added = false;
|
||||||
|
coord_t edge_length = static_cast<coord_t>(neighbor->length());
|
||||||
|
while (edge_length >= support_in) {
|
||||||
|
double ratio = support_in / neighbor->length();
|
||||||
|
VoronoiGraph::Position position(neighbor, ratio);
|
||||||
|
results.push_back(std::make_unique<SupportCenterIslandPoint>(
|
||||||
|
position, &config, SupportIslandPoint::Type::center_line1
|
||||||
|
));
|
||||||
|
support_in += config.max_distance;
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
support_in -= edge_length;
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Solve place where loop ends in already sampled area of island
|
||||||
|
/// NOTE: still make a mistake in place of 2 ends
|
||||||
|
/// (example could be logo of anarchy with already sampled circle and process inner 'Y')
|
||||||
|
/// NOTE: do not count with supported distance in place of connect
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node_neighbor">Last neighbor to sample</param>
|
||||||
|
/// <param name="support_in"></param>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="results"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
void sample_connection_into_sampled_area(
|
||||||
|
const VoronoiGraph::Node::Neighbor &node_neighbor,
|
||||||
|
coord_t support_in,
|
||||||
|
VoronoiGraph::Nodes path, // wanted copy
|
||||||
|
SupportIslandPoints &results,
|
||||||
|
const SampleConfig &config
|
||||||
|
) {
|
||||||
|
add_support_on_neighbor_edge(&node_neighbor, support_in, results, config);
|
||||||
|
return; // TODO: sample small rest part WRT distance on connected place
|
||||||
|
|
||||||
|
if (support_in > config.max_distance / 2)
|
||||||
|
return; // no need to add new support
|
||||||
|
|
||||||
|
// add last support before connection into already supported area
|
||||||
|
path.push_back(node_neighbor.node);
|
||||||
|
std::reverse(path.begin(), path.end());
|
||||||
|
auto position_opt = SampleIslandUtils::create_position_on_path(path, 1 - support_in / 2);
|
||||||
|
if (position_opt.has_value()) {
|
||||||
|
results.push_back(std::make_unique<SupportCenterIslandPoint>(
|
||||||
|
*position_opt, &config, SupportIslandPoint::Type::center_line3
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
|
std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
|
||||||
CenterStarts & new_starts,
|
CenterStarts & new_starts,
|
||||||
std::set<const VoronoiGraph::Node *> &done,
|
std::set<const VoronoiGraph::Node *> &done,
|
||||||
@ -1038,73 +1193,61 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
|
|||||||
const Lines & lines,
|
const Lines & lines,
|
||||||
const SampleConfig & config)
|
const SampleConfig & config)
|
||||||
{
|
{
|
||||||
|
// Current place to sample
|
||||||
CenterStart start(nullptr, {}, {});
|
CenterStart start(nullptr, {}, {});
|
||||||
bool use_new_start = true;
|
if (!pop_start(start, new_starts, done)) return {};
|
||||||
|
|
||||||
|
// sign that there was added point on start.path
|
||||||
|
// used to distiquish whether add support point on island edge
|
||||||
bool is_continous = false;
|
bool is_continous = false;
|
||||||
|
|
||||||
while (use_new_start || start.neighbor->max_width() <= config.max_width_for_center_support_line) {
|
// Loop over thin part of island which need to be sampled on the voronoi skeleton.
|
||||||
// !! do not check max width for new start, it could be wide to tiny change
|
while (start.neighbor->max_width() <= config.max_width_for_center_support_line) {
|
||||||
if (use_new_start) {
|
assert(done.find(start.neighbor->node) == done.end()); // not proccessed only
|
||||||
use_new_start = false;
|
// add support when it is in distance from last added
|
||||||
// skip done starts
|
if (add_support_on_neighbor_edge(start.neighbor, start.support_in, results, config))
|
||||||
if (new_starts.empty()) return {}; // no start
|
|
||||||
while (done.find(new_starts.back().neighbor->node) != done.end()) {
|
|
||||||
new_starts.pop_back();
|
|
||||||
if (new_starts.empty()) return {};
|
|
||||||
}
|
|
||||||
// fill new start
|
|
||||||
start = std::move(new_starts.back());
|
|
||||||
new_starts.pop_back();
|
|
||||||
is_continous = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add support on actual neighbor edge
|
|
||||||
coord_t edge_length = static_cast<coord_t>(start.neighbor->length());
|
|
||||||
while (edge_length >= start.support_in) {
|
|
||||||
double ratio = start.support_in / start.neighbor->length();
|
|
||||||
VoronoiGraph::Position position(start.neighbor, ratio);
|
|
||||||
results.push_back(std::make_unique<SupportCenterIslandPoint>(
|
|
||||||
position, &config, SupportIslandPoint::Type::center_line1));
|
|
||||||
start.support_in += config.max_distance;
|
|
||||||
is_continous = true;
|
is_continous = true;
|
||||||
}
|
|
||||||
start.support_in -= edge_length;
|
|
||||||
|
|
||||||
const VoronoiGraph::Node *node = start.neighbor->node;
|
const VoronoiGraph::Node *node = start.neighbor->node;
|
||||||
done.insert(node);
|
done.insert(node);
|
||||||
// IMPROVE: A) limit length of path to config.minimal_support_distance
|
// IMPROVE: A) limit length of path to config.minimal_support_distance
|
||||||
// IMPROVE: B) store node in reverse order
|
// IMPROVE: B) store node in reverse order
|
||||||
start.path.push_back(node);
|
start.path.push_back(node);
|
||||||
|
|
||||||
|
// next neighbor is short cut to not push back and pop new_starts
|
||||||
const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr;
|
const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr;
|
||||||
for (const auto &node_neighbor : node->neighbors) {
|
for (const auto &node_neighbor : node->neighbors) {
|
||||||
if (done.find(node_neighbor.node) != done.end()) continue;
|
// Check wheather node is not previous one
|
||||||
|
if (start.path.size() > 1 &&
|
||||||
|
start.path[start.path.size() - 2] == node_neighbor.node)
|
||||||
|
continue;
|
||||||
|
// Check other nodes wheather they are already done
|
||||||
|
if (done.find(node_neighbor.node) != done.end()) {
|
||||||
|
sample_connection_into_sampled_area(node_neighbor, start.support_in, start.path, results, config);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (next_neighbor == nullptr) {
|
if (next_neighbor == nullptr) {
|
||||||
next_neighbor = &node_neighbor;
|
next_neighbor = &node_neighbor;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new_starts.emplace_back(&node_neighbor, start.support_in, start.path); // search in side branch
|
new_starts.emplace_back(&node_neighbor, start.support_in, start.path); // search in side branch
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_neighbor == nullptr) {
|
if (next_neighbor != nullptr) {
|
||||||
if (start.neighbor->min_width() != 0) {
|
|
||||||
std::reverse(start.path.begin(), start.path.end());
|
|
||||||
auto position_opt = create_position_on_path(start.path, start.support_in / 2);
|
|
||||||
if (position_opt.has_value()) {
|
|
||||||
results.push_back(
|
|
||||||
std::make_unique<SupportCenterIslandPoint>(
|
|
||||||
*position_opt, &config,
|
|
||||||
SupportIslandPoint::Type::center_line3));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no neighbor to continue
|
|
||||||
create_sample_center_end(*start.neighbor, is_continous, start.path,
|
|
||||||
start.support_in, lines, results,
|
|
||||||
new_starts, config);
|
|
||||||
}
|
|
||||||
use_new_start = true;
|
|
||||||
} else {
|
|
||||||
start.neighbor = next_neighbor;
|
start.neighbor = next_neighbor;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no neighbor to continue so sample edge of island
|
||||||
|
if(start.neighbor->min_width() == 0)
|
||||||
|
create_sample_center_end(*start.neighbor, is_continous, start.path,
|
||||||
|
start.support_in, lines, results,
|
||||||
|
new_starts, config);
|
||||||
|
// select next start
|
||||||
|
if (!pop_start(start, new_starts, done))
|
||||||
|
return {}; // finished
|
||||||
|
is_continous = false; // new branch for start was just selected
|
||||||
}
|
}
|
||||||
|
|
||||||
// create field start
|
// create field start
|
||||||
@ -1136,6 +1279,7 @@ void SampleIslandUtils::create_sample_center_end(
|
|||||||
const SampleConfig & config)
|
const SampleConfig & config)
|
||||||
{
|
{
|
||||||
// last neighbor?
|
// last neighbor?
|
||||||
|
assert(neighbor.min_width() == 0);
|
||||||
if (neighbor.min_width() != 0) return;
|
if (neighbor.min_width() != 0) return;
|
||||||
|
|
||||||
// sharp corner?
|
// sharp corner?
|
||||||
@ -1389,18 +1533,25 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t source_indexe_for_change = lines.size();
|
size_t source_indexe_for_change = lines.size();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Insert change into
|
||||||
|
/// NOTE: separate functionality to be able force break from second loop
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lines">island(ExPolygon) converted to lines</param>
|
||||||
|
/// <param name="index"></param> ...
|
||||||
|
/// <returns>False when change lead to close loop(into first change) otherwise True</returns>
|
||||||
auto insert_changes = [&wide_tiny_changes, &lines, &source_indexes, source_indexe_for_change]
|
auto insert_changes = [&wide_tiny_changes, &lines, &source_indexes, source_indexe_for_change]
|
||||||
(size_t &index, Points &points, std::set<size_t> &done, size_t input_index)->bool {
|
(size_t &index, Points &points, std::set<size_t> &done, size_t input_index)->bool {
|
||||||
bool is_first = points.empty();
|
|
||||||
auto change_item = wide_tiny_changes.find(index);
|
auto change_item = wide_tiny_changes.find(index);
|
||||||
while (change_item != wide_tiny_changes.end()) {
|
while (change_item != wide_tiny_changes.end()) {
|
||||||
const WideTinyChanges &changes = change_item->second;
|
const WideTinyChanges &changes = change_item->second;
|
||||||
assert(!changes.empty());
|
assert(!changes.empty());
|
||||||
size_t change_index = 0;
|
size_t change_index = 0;
|
||||||
if (!is_first) {
|
if (!points.empty()) { // Not first point, could lead to termination
|
||||||
const Point & last_point = points.back();
|
const Point &last_point = points.back();
|
||||||
LineUtils::SortFromAToB pred(lines[index]);
|
LineUtils::SortFromAToB pred(lines[index]);
|
||||||
bool no_change = false;
|
bool no_change = false;
|
||||||
while (pred.compare(changes[change_index].new_b, last_point)) {
|
while (pred.compare(changes[change_index].new_b, last_point)) {
|
||||||
++change_index;
|
++change_index;
|
||||||
if (change_index >= changes.size()) {
|
if (change_index >= changes.size()) {
|
||||||
@ -1445,7 +1596,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
outline_indexes.reserve(field_line_indexes.size());
|
outline_indexes.reserve(field_line_indexes.size());
|
||||||
size_t input_index1 = tiny_wide_neighbor->edge->cell()->source_index();
|
size_t input_index1 = tiny_wide_neighbor->edge->cell()->source_index();
|
||||||
size_t input_index2 = tiny_wide_neighbor->edge->twin()->cell()->source_index();
|
size_t input_index2 = tiny_wide_neighbor->edge->twin()->cell()->source_index();
|
||||||
size_t input_index = std::min(input_index1, input_index2);
|
size_t input_index = std::min(input_index1, input_index2); // Why select min index?
|
||||||
size_t outline_index = input_index;
|
size_t outline_index = input_index;
|
||||||
std::set<size_t> done_indexes;
|
std::set<size_t> done_indexes;
|
||||||
do {
|
do {
|
||||||
@ -1778,13 +1929,10 @@ bool SampleIslandUtils::is_visualization_disabled()
|
|||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
|
||||||
|
@ -24,6 +24,16 @@ class SampleIslandUtils
|
|||||||
public:
|
public:
|
||||||
SampleIslandUtils() = delete;
|
SampleIslandUtils() = delete;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main entry for sample island
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="island">Shape of island</param>
|
||||||
|
/// <param name="config">Configuration for sampler</param>
|
||||||
|
/// <returns>List of support points</returns>
|
||||||
|
static SupportIslandPoints uniform_cover_island(
|
||||||
|
const ExPolygon &island, const SampleConfig &config
|
||||||
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uniform sample expolygon area by points inside Equilateral triangle center
|
/// Uniform sample expolygon area by points inside Equilateral triangle center
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
#include "libslic3r/Execution/Execution.hpp"
|
#include "libslic3r/Execution/Execution.hpp"
|
||||||
#include "libslic3r/KDTreeIndirect.hpp"
|
#include "libslic3r/KDTreeIndirect.hpp"
|
||||||
|
|
||||||
|
// SupportIslands
|
||||||
|
#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp"
|
||||||
|
#include "libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::sla;
|
using namespace Slic3r::sla;
|
||||||
|
|
||||||
@ -183,14 +187,14 @@ Point intersection(const Point &p1, const Point &p2, const Point &cnt, double r2
|
|||||||
/// <param name="part">Current layer part to process</param>
|
/// <param name="part">Current layer part to process</param>
|
||||||
/// <param name="prev_grids">Grids which will be moved to current grid</param>
|
/// <param name="prev_grids">Grids which will be moved to current grid</param>
|
||||||
/// <returns>Grid for given part</returns>
|
/// <returns>Grid for given part</returns>
|
||||||
NearPoints create_part_grid(
|
NearPoints create_near_points(
|
||||||
const LayerParts &prev_layer_parts,
|
const LayerParts &prev_layer_parts,
|
||||||
const LayerPart &part,
|
const LayerPart &part,
|
||||||
std::vector<NearPoints> &prev_grids
|
std::vector<NearPoints> &prev_grids
|
||||||
) {
|
) {
|
||||||
const LayerParts::const_iterator &prev_part_it = part.prev_parts.front().part_it;
|
const LayerParts::const_iterator &prev_part_it = part.prev_parts.front().part_it;
|
||||||
size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin();
|
size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin();
|
||||||
NearPoints part_grid = (prev_part_it->next_parts.size() == 1)?
|
NearPoints near_points = (prev_part_it->next_parts.size() == 1)?
|
||||||
std::move(prev_grids[index_of_prev_part]) :
|
std::move(prev_grids[index_of_prev_part]) :
|
||||||
// Need a copy there are multiple parts above previus one
|
// Need a copy there are multiple parts above previus one
|
||||||
prev_grids[index_of_prev_part]; // copy
|
prev_grids[index_of_prev_part]; // copy
|
||||||
@ -200,27 +204,27 @@ NearPoints create_part_grid(
|
|||||||
const LayerParts::const_iterator &prev_part_it = part.prev_parts[i].part_it;
|
const LayerParts::const_iterator &prev_part_it = part.prev_parts[i].part_it;
|
||||||
size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin();
|
size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin();
|
||||||
if (prev_part_it->next_parts.size() == 1) {
|
if (prev_part_it->next_parts.size() == 1) {
|
||||||
part_grid.merge(std::move(prev_grids[index_of_prev_part]));
|
near_points.merge(std::move(prev_grids[index_of_prev_part]));
|
||||||
} else { // Need a copy there are multiple parts above previus one
|
} else { // Need a copy there are multiple parts above previus one
|
||||||
NearPoints grid_ = prev_grids[index_of_prev_part]; // copy
|
NearPoints grid_ = prev_grids[index_of_prev_part]; // copy
|
||||||
part_grid.merge(std::move(grid_));
|
near_points.merge(std::move(grid_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return part_grid;
|
return near_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add support point to part_grid when it is neccessary
|
/// Add support point to near_points when it is neccessary
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="part">Current part - keep samples</param>
|
/// <param name="part">Current part - keep samples</param>
|
||||||
/// <param name="config">Configuration to sample</param>
|
/// <param name="config">Configuration to sample</param>
|
||||||
/// <param name="part_grid">Keep previous sampled suppport points</param>
|
/// <param name="near_points">Keep previous sampled suppport points</param>
|
||||||
/// <param name="part_z">current z coordinate of part</param>
|
/// <param name="part_z">current z coordinate of part</param>
|
||||||
/// <param name="maximal_radius">Max distance to seach support for sample</param>
|
/// <param name="maximal_radius">Max distance to seach support for sample</param>
|
||||||
void support_part_overhangs(
|
void support_part_overhangs(
|
||||||
const LayerPart &part,
|
const LayerPart &part,
|
||||||
const SupportPointGeneratorConfig &config,
|
const SupportPointGeneratorConfig &config,
|
||||||
NearPoints &part_grid,
|
NearPoints &near_points,
|
||||||
float part_z,
|
float part_z,
|
||||||
coord_t maximal_radius
|
coord_t maximal_radius
|
||||||
) {
|
) {
|
||||||
@ -239,9 +243,9 @@ void support_part_overhangs(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (const Point &p : part.samples) {
|
for (const Point &p : part.samples) {
|
||||||
if (!part_grid.exist_true_in_radius(p, maximal_radius, is_supported)) {
|
if (!near_points.exist_true_in_radius(p, maximal_radius, is_supported)) {
|
||||||
// not supported sample, soo create new support point
|
// not supported sample, soo create new support point
|
||||||
part_grid.add(LayerSupportPoint{
|
near_points.add(LayerSupportPoint{
|
||||||
SupportPoint{
|
SupportPoint{
|
||||||
Vec3f{unscale<float>(p.x()), unscale<float>(p.y()), part_z},
|
Vec3f{unscale<float>(p.x()), unscale<float>(p.y()), part_z},
|
||||||
/* head_front_radius */ 0.4f,
|
/* head_front_radius */ 0.4f,
|
||||||
@ -256,30 +260,31 @@ void support_part_overhangs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Points uniformly_sample(const ExPolygon &island, const SupportPointGeneratorConfig &cfg) {
|
|
||||||
// TODO: Implement it
|
|
||||||
return Points{island.contour.centroid()};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sample part as Island
|
/// Sample part as Island
|
||||||
/// Result store to grid
|
/// Result store to grid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="part">Island to support</param>
|
/// <param name="part">Island to support</param>
|
||||||
/// <param name="part_grid">OUT place to store new supports</param>
|
/// <param name="near_points">OUT place to store new supports</param>
|
||||||
/// <param name="part_z">z coordinate of part</param>
|
/// <param name="part_z">z coordinate of part</param>
|
||||||
/// <param name="cfg"></param>
|
/// <param name="cfg"></param>
|
||||||
void support_island(const LayerPart &part, NearPoints& part_grid, float part_z,
|
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
||||||
const SupportPointGeneratorConfig &cfg) {
|
const SupportPointGeneratorConfig &cfg) {
|
||||||
Points pts = uniformly_sample(*part.shape, cfg);
|
SampleConfig sample_cfg = SampleConfigFactory::create(cfg);
|
||||||
for (const Point &pt : pts)
|
SupportIslandPoints samples = SampleIslandUtils::uniform_cover_island(*part.shape, sample_cfg);
|
||||||
part_grid.add(LayerSupportPoint{
|
//samples = {std::make_unique<SupportIslandPoint>(island.contour.centroid())};
|
||||||
|
for (const SupportIslandPointPtr &sample : samples)
|
||||||
|
near_points.add(LayerSupportPoint{
|
||||||
SupportPoint{
|
SupportPoint{
|
||||||
Vec3f{unscale<float>(pt.x()), unscale<float>(pt.y()), part_z},
|
Vec3f{
|
||||||
|
unscale<float>(sample->point.x()),
|
||||||
|
unscale<float>(sample->point.y()),
|
||||||
|
part_z
|
||||||
|
},
|
||||||
/* head_front_radius */ 0.4f,
|
/* head_front_radius */ 0.4f,
|
||||||
SupportPointType::island
|
SupportPointType::island
|
||||||
},
|
},
|
||||||
/* position_on_layer */ pt,
|
/* position_on_layer */ sample->point,
|
||||||
/* direction_to_mass */ Point(0,0), // direction from bottom
|
/* direction_to_mass */ Point(0,0), // direction from bottom
|
||||||
/* radius_curve_index */ 0,
|
/* radius_curve_index */ 0,
|
||||||
/* current_radius */ static_cast<coord_t>(scale_(cfg.support_curve.front().x()))
|
/* current_radius */ static_cast<coord_t>(scale_(cfg.support_curve.front().x()))
|
||||||
@ -471,15 +476,15 @@ void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z,
|
|||||||
/// Due to be able support in same area again(overhang above another overhang)
|
/// Due to be able support in same area again(overhang above another overhang)
|
||||||
/// Wanted Side effect, it supports thiny part of overhangs
|
/// Wanted Side effect, it supports thiny part of overhangs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="part_grid"></param>
|
/// <param name="near_points"></param>
|
||||||
/// <param name="part"></param>
|
/// <param name="part"></param>
|
||||||
void remove_supports_out_of_part(NearPoints& part_grid, const LayerPart &part) {
|
void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part) {
|
||||||
|
|
||||||
// Must be greater than surface texture and lower than self supporting area
|
// Must be greater than surface texture and lower than self supporting area
|
||||||
// May be use maximal island distance
|
// May be use maximal island distance
|
||||||
float delta = scale_(5.);
|
float delta = scale_(5.);
|
||||||
ExPolygons extend_shape = offset_ex(*part.shape, delta, ClipperLib::jtSquare);
|
ExPolygons extend_shape = offset_ex(*part.shape, delta, ClipperLib::jtSquare);
|
||||||
part_grid.remove_out_of(extend_shape);
|
near_points.remove_out_of(extend_shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -651,10 +656,10 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
|||||||
// first layer should have empty prev_part
|
// first layer should have empty prev_part
|
||||||
assert(layer_id != 0);
|
assert(layer_id != 0);
|
||||||
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
||||||
NearPoints part_grid = create_part_grid(prev_layer_parts, part, prev_grids);
|
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
||||||
remove_supports_out_of_part(part_grid, part);
|
remove_supports_out_of_part(near_points, part);
|
||||||
support_part_overhangs(part, config, part_grid, layer.print_z, maximal_radius);
|
support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius);
|
||||||
grids.push_back(std::move(part_grid));
|
grids.push_back(std::move(near_points));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prev_grids = std::move(grids);
|
prev_grids = std::move(grids);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user