mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 13:42:01 +08:00
Successfull creation of field with indexes
Add visualization of Field
This commit is contained in:
parent
214f1acea6
commit
fd2193eb77
@ -7,6 +7,7 @@
|
||||
#include <map>
|
||||
#include <libslic3r/Line.hpp>
|
||||
#include <libslic3r/SVG.hpp>
|
||||
#include "PointUtils.hpp"
|
||||
|
||||
namespace Slic3r::sla {
|
||||
|
||||
@ -142,6 +143,41 @@ public:
|
||||
/// <returns>map of connected lines over point line::b</returns>
|
||||
static std::map<size_t, size_t> create_line_connection_over_b(const Lines &lines);
|
||||
|
||||
/// <summary>
|
||||
/// Comparator to sort points laying on line from point a to point b
|
||||
/// </summary>
|
||||
struct SortFromAToB
|
||||
{
|
||||
std::function<bool(const Point &, const Point &)> compare;
|
||||
SortFromAToB(const Line &line)
|
||||
{
|
||||
Point dir = LineUtils::direction(line);
|
||||
compare = (PointUtils::is_majorit_x(dir)) ?
|
||||
((dir.x() < 0) ? is_x_grater : is_x_smaller) :
|
||||
((dir.y() < 0) ? is_y_grater : is_y_smaller);
|
||||
}
|
||||
static bool is_x_grater(const Point &left, const Point &right)
|
||||
{
|
||||
return left.x() > right.x();
|
||||
}
|
||||
static bool is_x_smaller(const Point &left, const Point &right)
|
||||
{
|
||||
return left.x() < right.x();
|
||||
}
|
||||
static bool is_y_grater(const Point &left, const Point &right)
|
||||
{
|
||||
return left.y() > right.y();
|
||||
}
|
||||
static bool is_y_smaller(const Point &left, const Point &right)
|
||||
{
|
||||
return left.y() < right.y();
|
||||
}
|
||||
bool operator()(const Point &left, const Point &right)
|
||||
{
|
||||
return compare(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
static void draw(SVG & svg,
|
||||
const Line &line,
|
||||
const char *color = "gray",
|
||||
|
@ -18,6 +18,10 @@
|
||||
|
||||
// comment definition of NDEBUG to enable assert()
|
||||
// #define NDEBUG
|
||||
|
||||
#define SLA_SAMPLING_STORE_FIELD_TO_SVG
|
||||
#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace Slic3r::sla;
|
||||
@ -747,6 +751,15 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
|
||||
assert(start_node != nullptr);
|
||||
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
|
||||
// longest_path = create_longest_path_recursive(start_node);
|
||||
|
||||
#ifdef SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
||||
{
|
||||
static int counter=0;
|
||||
SVG svg("voronoiGraph"+std::to_string(counter++)+".svg", LineUtils::create_bounding_box(lines));
|
||||
LineUtils::draw(svg, lines, "black",0., true);
|
||||
VoronoiGraphUtils::draw(svg, graph, 1e6, true);
|
||||
}
|
||||
#endif // SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
||||
return sample_expath(longest_path, lines, config);
|
||||
}
|
||||
|
||||
@ -758,7 +771,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
{
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
|
||||
// DTO represents one island change from tiny part to wide part
|
||||
// DTO represents one island change from wide to tiny part
|
||||
// it is stored inside map under source line index
|
||||
struct WideTinyChange{
|
||||
// new coordinate for line.b point
|
||||
Point new_b;
|
||||
@ -772,11 +786,24 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
, next_new_a(next_new_a)
|
||||
, next_line_index(next_line_index)
|
||||
{}
|
||||
|
||||
// is used only when multi wide tiny change are on same Line
|
||||
struct SortFromAToB
|
||||
{
|
||||
LineUtils::SortFromAToB compare;
|
||||
SortFromAToB(const Line &line) : compare(line) {}
|
||||
bool operator()(const WideTinyChange &left,
|
||||
const WideTinyChange &right)
|
||||
{
|
||||
return compare.compare(left.new_b, right.new_b);
|
||||
}
|
||||
};
|
||||
};
|
||||
using WideTinyChanges = std::vector<WideTinyChange>;
|
||||
|
||||
// store shortening of outline segments
|
||||
// line index, <next line index + 2x shortening points>
|
||||
std::map<size_t, WideTinyChange> wide_tiny_changes;
|
||||
// line index, vector<next line index + 2x shortening points>
|
||||
std::map<size_t, WideTinyChanges> wide_tiny_changes;
|
||||
const coord_t min_width = config.min_width_for_outline_support;
|
||||
// cut lines at place where neighbor has width = min_width_for_outline_support
|
||||
// neighbor must be in direction from wide part to tiny part of island
|
||||
@ -788,21 +815,33 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
const VD::edge_type *edge = neighbor->edge;
|
||||
size_t i1 = edge->cell()->source_index();
|
||||
size_t i2 = edge->twin()->cell()->source_index();
|
||||
|
||||
auto add = [&](const Point &p1, const Point &p2, size_t i1, size_t i2) {
|
||||
WideTinyChange change(p1, p2, i2);
|
||||
auto item = wide_tiny_changes.find(i1);
|
||||
if (item == wide_tiny_changes.end()) {
|
||||
wide_tiny_changes[i1] = {change};
|
||||
} else {
|
||||
WideTinyChange::SortFromAToB pred(lines[i1]);
|
||||
VectorUtils::insert_sorted(item->second, change, pred);
|
||||
}
|
||||
};
|
||||
const Line &l1 = lines[i1];
|
||||
if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) {
|
||||
// line1 is shorten on side line1.a --> line2 is shorten on side line2.b
|
||||
assert(wide_tiny_changes.find(i2) == wide_tiny_changes.end());
|
||||
wide_tiny_changes.insert({i2, WideTinyChange(p2, p1, i1)});
|
||||
add(p2, p1, i2, i1);
|
||||
} else {
|
||||
// line1 is shorten on side line1.b
|
||||
assert(wide_tiny_changes.find(i1) == wide_tiny_changes.end());
|
||||
wide_tiny_changes.insert({i1, WideTinyChange(p1, p2, i2)});
|
||||
add(p1, p2, i1, i2);
|
||||
}
|
||||
};
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = field_start.neighbor;
|
||||
const VoronoiGraph::Node::Neighbor *twin_neighbor = VoronoiGraphUtils::get_twin(neighbor);
|
||||
|
||||
add_wide_tiny_change(twin_neighbor);
|
||||
// is input wide tiny change
|
||||
// first input could be from border of Voronoi Graph
|
||||
if (twin_neighbor->node->neighbors.size() != 1) {
|
||||
add_wide_tiny_change(twin_neighbor);
|
||||
}
|
||||
std::set<const VoronoiGraph::Node*> done;
|
||||
done.insert(twin_neighbor->node);
|
||||
std::queue<const VoronoiGraph::Node *> process;
|
||||
@ -841,14 +880,9 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
} while (node != nullptr);
|
||||
}
|
||||
|
||||
// connection of line on island
|
||||
std::map<size_t, size_t> b_connection =
|
||||
LineUtils::create_line_connection_over_b(lines);
|
||||
// Continue along line indexes create polygon field
|
||||
|
||||
Points points;
|
||||
points.reserve(field_line_indexes.size());
|
||||
std::vector<size_t> outline_indexes;
|
||||
outline_indexes.reserve(field_line_indexes.size());
|
||||
|
||||
auto inser_point_b = [&](size_t& index, Points& points, std::set<size_t>& done)
|
||||
{
|
||||
@ -859,23 +893,60 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
done.insert(index);
|
||||
index = connection_item->second;
|
||||
};
|
||||
|
||||
Points points;
|
||||
points.reserve(field_line_indexes.size());
|
||||
std::vector<size_t> outline_indexes;
|
||||
outline_indexes.reserve(field_line_indexes.size());
|
||||
|
||||
size_t input_index = neighbor->edge->cell()->source_index();
|
||||
size_t outline_index = input_index;
|
||||
std::set<size_t> done_indexes;
|
||||
std::vector<size_t> source_indexes;
|
||||
size_t source_indexe_for_change = lines.size();
|
||||
// Continue along line indexes and create polygon field
|
||||
do {
|
||||
const auto &change_item = wide_tiny_changes.find(outline_index);
|
||||
if (change_item != wide_tiny_changes.end()) {
|
||||
const WideTinyChange &change = change_item->second;
|
||||
points.push_back(change.new_b);
|
||||
points.push_back(change.next_new_a);
|
||||
auto change_item = wide_tiny_changes.find(outline_index);
|
||||
while(change_item != wide_tiny_changes.end()) {
|
||||
const WideTinyChanges &changes = change_item->second;
|
||||
assert(!changes.empty());
|
||||
size_t change_index = 0;
|
||||
if (!points.empty()) {
|
||||
const Point &last_point = points.back();
|
||||
LineUtils::SortFromAToB pred(lines[outline_index]);
|
||||
bool no_change = false;
|
||||
while (pred.compare(changes[change_index].new_b, last_point)) {
|
||||
++change_index;
|
||||
if (change_index >= changes.size()) {
|
||||
no_change = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (no_change) break;
|
||||
}
|
||||
const WideTinyChange& change = changes[change_index];
|
||||
// prevent double points
|
||||
if (points.empty() || !PointUtils::is_equal(points.back(),change.new_b)){
|
||||
points.push_back(change.new_b);
|
||||
source_indexes.push_back(source_indexe_for_change);
|
||||
} else {
|
||||
source_indexes.back() = source_indexe_for_change;
|
||||
}
|
||||
// prevent double points
|
||||
if (!PointUtils::is_equal(lines[change.next_line_index].b, change.next_new_a)){
|
||||
points.push_back(change.next_new_a);
|
||||
source_indexes.push_back(change.next_line_index);
|
||||
}
|
||||
done_indexes.insert(outline_index);
|
||||
outline_index = change.next_line_index;
|
||||
change_item = wide_tiny_changes.find(outline_index);
|
||||
}
|
||||
inser_point_b(outline_index, points, done_indexes);
|
||||
source_indexes.push_back(outline_index);
|
||||
} while (outline_index != input_index);
|
||||
|
||||
Field field;
|
||||
field.source_indexes = std::move(source_indexes);
|
||||
field.border.contour = Polygon(points);
|
||||
// finding holes
|
||||
if (done_indexes.size() < field_line_indexes.size()) {
|
||||
@ -890,6 +961,36 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
field.border.holes.emplace_back(hole_points);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SLA_SAMPLING_STORE_FIELD_TO_SVG
|
||||
{
|
||||
bool draw_border_line_indexes = false;
|
||||
bool draw_source_line_indexes = true;
|
||||
bool draw_field_source_indexes = true;
|
||||
const char *field_color = "red";
|
||||
const char *source_line_color = "black";
|
||||
const char *border_line_color = "blue";
|
||||
|
||||
static int counter = 0;
|
||||
std::string file_name = "field_" + std::to_string(counter++) + ".svg";
|
||||
|
||||
SVG svg(file_name, LineUtils::create_bounding_box(lines));
|
||||
svg.draw(field.border, field_color);
|
||||
LineUtils::draw(svg,lines, source_line_color,0., draw_source_line_indexes);
|
||||
Lines border_lines = to_lines(field.border);
|
||||
LineUtils::draw(svg, border_lines, border_line_color, 0., draw_border_line_indexes);
|
||||
if (draw_field_source_indexes)
|
||||
for (auto &line : border_lines) {
|
||||
size_t index = &line - &border_lines.front();
|
||||
// start of holes
|
||||
if (index >= field.source_indexes.size()) break;
|
||||
Point middle_point = (line.a + line.b) / 2;
|
||||
std::string text = std::to_string(field.source_indexes[index]);
|
||||
svg.draw_text(middle_point, text.c_str(), field_color);
|
||||
}
|
||||
}
|
||||
#endif //SLA_SAMPLING_STORE_FIELD_TO_SVG
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
|
@ -248,8 +248,8 @@ public:
|
||||
|
||||
// same size as polygon.points.size()
|
||||
// indexes to source island lines
|
||||
// in case (index == -1) it means fill the gap from tiny part of island
|
||||
std::vector<size_t> source_indexes;
|
||||
// in case (index > lines.size()) it means fill the gap from tiny part of island
|
||||
std::vector<size_t> source_indexes;
|
||||
};
|
||||
|
||||
|
||||
|
@ -123,6 +123,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert item into sorted vector of items
|
||||
/// </summary>
|
||||
/// <param name="data">Sorted vector with items</param>
|
||||
/// <param name="item">Item to insert</param>
|
||||
/// <param name="pred">Predicate for sorting</param>
|
||||
/// <returns>now inserted item</returns>
|
||||
template<typename T, typename Pred>
|
||||
static typename std::vector<T>::iterator insert_sorted(
|
||||
std::vector<T> &data, const T &item, Pred pred)
|
||||
{
|
||||
auto iterator = std::upper_bound(data.begin(), data.end(), item, pred);
|
||||
return data.insert(iterator, item);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
|
@ -221,7 +221,7 @@ Slic3r::Polygon create_V_shape(double height, double line_width, double angle =
|
||||
ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||
{
|
||||
double hole_size = wide;
|
||||
double width = (2 + 1) * wide + 2 * hole_size;
|
||||
double width = (3 + 1) * wide + 3 * hole_size;
|
||||
double height = wide + 2*tiny + 2*hole_size;
|
||||
auto outline = PolygonUtils::create_rect( width, height);
|
||||
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
|
||||
@ -230,14 +230,21 @@ ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||
auto hole3 = hole; // copy
|
||||
auto hole4 = hole; // copy
|
||||
|
||||
int hole_move_x = wide / 2 + hole_size / 2;
|
||||
int hole_move_x = wide + hole_size;
|
||||
int hole_move_y = wide / 2 + hole_size / 2;
|
||||
hole.translate({hole_move_x, hole_move_y});
|
||||
hole2.translate({-hole_move_x, hole_move_y});
|
||||
hole3.translate({hole_move_x, -hole_move_y});
|
||||
hole4.translate({-hole_move_x, -hole_move_y});
|
||||
hole.translate(hole_move_x, hole_move_y);
|
||||
hole2.translate(-hole_move_x, hole_move_y);
|
||||
hole3.translate(hole_move_x, -hole_move_y);
|
||||
hole4.translate(-hole_move_x, -hole_move_y);
|
||||
|
||||
auto hole5 = PolygonUtils::create_circle(hole_size / 2, 16);
|
||||
hole5.reverse();
|
||||
auto hole6 = hole5; // copy
|
||||
hole5.translate(0, hole_move_y);
|
||||
hole6.translate(0, -hole_move_y);
|
||||
|
||||
ExPolygon result(outline);
|
||||
result.holes = {hole, hole2, hole3, hole4};
|
||||
result.holes = {hole, hole2, hole3, hole4, hole5, hole6};
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -275,6 +282,9 @@ ExPolygons createTestIslands(double size)
|
||||
create_disc(3*size, size / 4, 30),
|
||||
create_square_with_4holes(5 * size, 5 * size / 2 - size / 3),
|
||||
|
||||
// Tiny and wide part together with holes
|
||||
create_tiny_wide_test(3 * size, 2 / 3. * size),
|
||||
|
||||
// still problem
|
||||
// three support points
|
||||
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user