mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-01 10:02: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 <map>
|
||||||
#include <libslic3r/Line.hpp>
|
#include <libslic3r/Line.hpp>
|
||||||
#include <libslic3r/SVG.hpp>
|
#include <libslic3r/SVG.hpp>
|
||||||
|
#include "PointUtils.hpp"
|
||||||
|
|
||||||
namespace Slic3r::sla {
|
namespace Slic3r::sla {
|
||||||
|
|
||||||
@ -142,6 +143,41 @@ public:
|
|||||||
/// <returns>map of connected lines over point line::b</returns>
|
/// <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);
|
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,
|
static void draw(SVG & svg,
|
||||||
const Line &line,
|
const Line &line,
|
||||||
const char *color = "gray",
|
const char *color = "gray",
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
// comment definition of NDEBUG to enable assert()
|
// comment definition of NDEBUG to enable assert()
|
||||||
// #define NDEBUG
|
// #define NDEBUG
|
||||||
|
|
||||||
|
#define SLA_SAMPLING_STORE_FIELD_TO_SVG
|
||||||
|
#define SLA_SAMPLING_STORE_VORONOI_GRAPH_TO_SVG
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
using namespace Slic3r::sla;
|
using namespace Slic3r::sla;
|
||||||
@ -747,6 +751,15 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
|
|||||||
assert(start_node != nullptr);
|
assert(start_node != nullptr);
|
||||||
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
|
longest_path = VoronoiGraphUtils::create_longest_path(start_node);
|
||||||
// longest_path = create_longest_path_recursive(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);
|
return sample_expath(longest_path, lines, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +771,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
{
|
{
|
||||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
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{
|
struct WideTinyChange{
|
||||||
// new coordinate for line.b point
|
// new coordinate for line.b point
|
||||||
Point new_b;
|
Point new_b;
|
||||||
@ -772,11 +786,24 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
, next_new_a(next_new_a)
|
, next_new_a(next_new_a)
|
||||||
, next_line_index(next_line_index)
|
, 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
|
// store shortening of outline segments
|
||||||
// line index, <next line index + 2x shortening points>
|
// line index, vector<next line index + 2x shortening points>
|
||||||
std::map<size_t, WideTinyChange> wide_tiny_changes;
|
std::map<size_t, WideTinyChanges> wide_tiny_changes;
|
||||||
const coord_t min_width = config.min_width_for_outline_support;
|
const coord_t min_width = config.min_width_for_outline_support;
|
||||||
// cut lines at place where neighbor has width = 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
|
// 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;
|
const VD::edge_type *edge = neighbor->edge;
|
||||||
size_t i1 = edge->cell()->source_index();
|
size_t i1 = edge->cell()->source_index();
|
||||||
size_t i2 = edge->twin()->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];
|
const Line &l1 = lines[i1];
|
||||||
if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) {
|
if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) {
|
||||||
// line1 is shorten on side line1.a --> line2 is shorten on side line2.b
|
// line1 is shorten on side line1.a --> line2 is shorten on side line2.b
|
||||||
assert(wide_tiny_changes.find(i2) == wide_tiny_changes.end());
|
add(p2, p1, i2, i1);
|
||||||
wide_tiny_changes.insert({i2, WideTinyChange(p2, p1, i1)});
|
|
||||||
} else {
|
} else {
|
||||||
// line1 is shorten on side line1.b
|
// line1 is shorten on side line1.b
|
||||||
assert(wide_tiny_changes.find(i1) == wide_tiny_changes.end());
|
add(p1, p2, i1, i2);
|
||||||
wide_tiny_changes.insert({i1, WideTinyChange(p1, p2, i2)});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const VoronoiGraph::Node::Neighbor *neighbor = field_start.neighbor;
|
const VoronoiGraph::Node::Neighbor *neighbor = field_start.neighbor;
|
||||||
const VoronoiGraph::Node::Neighbor *twin_neighbor = VoronoiGraphUtils::get_twin(neighbor);
|
const VoronoiGraph::Node::Neighbor *twin_neighbor = VoronoiGraphUtils::get_twin(neighbor);
|
||||||
|
// is input wide tiny change
|
||||||
add_wide_tiny_change(twin_neighbor);
|
// 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;
|
std::set<const VoronoiGraph::Node*> done;
|
||||||
done.insert(twin_neighbor->node);
|
done.insert(twin_neighbor->node);
|
||||||
std::queue<const VoronoiGraph::Node *> process;
|
std::queue<const VoronoiGraph::Node *> process;
|
||||||
@ -841,14 +880,9 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
} while (node != nullptr);
|
} while (node != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connection of line on island
|
||||||
std::map<size_t, size_t> b_connection =
|
std::map<size_t, size_t> b_connection =
|
||||||
LineUtils::create_line_connection_over_b(lines);
|
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)
|
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);
|
done.insert(index);
|
||||||
index = connection_item->second;
|
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 input_index = neighbor->edge->cell()->source_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;
|
||||||
|
std::vector<size_t> source_indexes;
|
||||||
|
size_t source_indexe_for_change = lines.size();
|
||||||
|
// Continue along line indexes and create polygon field
|
||||||
do {
|
do {
|
||||||
const auto &change_item = wide_tiny_changes.find(outline_index);
|
auto change_item = wide_tiny_changes.find(outline_index);
|
||||||
if (change_item != wide_tiny_changes.end()) {
|
while(change_item != wide_tiny_changes.end()) {
|
||||||
const WideTinyChange &change = change_item->second;
|
const WideTinyChanges &changes = change_item->second;
|
||||||
points.push_back(change.new_b);
|
assert(!changes.empty());
|
||||||
points.push_back(change.next_new_a);
|
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);
|
done_indexes.insert(outline_index);
|
||||||
outline_index = change.next_line_index;
|
outline_index = change.next_line_index;
|
||||||
|
change_item = wide_tiny_changes.find(outline_index);
|
||||||
}
|
}
|
||||||
inser_point_b(outline_index, points, done_indexes);
|
inser_point_b(outline_index, points, done_indexes);
|
||||||
|
source_indexes.push_back(outline_index);
|
||||||
} while (outline_index != input_index);
|
} while (outline_index != input_index);
|
||||||
|
|
||||||
Field field;
|
Field field;
|
||||||
|
field.source_indexes = std::move(source_indexes);
|
||||||
field.border.contour = Polygon(points);
|
field.border.contour = Polygon(points);
|
||||||
// finding holes
|
// finding holes
|
||||||
if (done_indexes.size() < field_line_indexes.size()) {
|
if (done_indexes.size() < field_line_indexes.size()) {
|
||||||
@ -890,6 +961,36 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
|||||||
field.border.holes.emplace_back(hole_points);
|
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;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,8 +248,8 @@ public:
|
|||||||
|
|
||||||
// same size as polygon.points.size()
|
// same size as polygon.points.size()
|
||||||
// indexes to source island lines
|
// indexes to source island lines
|
||||||
// in case (index == -1) it means fill the gap from tiny part of island
|
// in case (index > lines.size()) it means fill the gap from tiny part of island
|
||||||
std::vector<size_t> source_indexes;
|
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
|
} // 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)
|
ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||||
{
|
{
|
||||||
double hole_size = wide;
|
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;
|
double height = wide + 2*tiny + 2*hole_size;
|
||||||
auto outline = PolygonUtils::create_rect( width, height);
|
auto outline = PolygonUtils::create_rect( width, height);
|
||||||
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
|
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 hole3 = hole; // copy
|
||||||
auto hole4 = 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;
|
int hole_move_y = wide / 2 + hole_size / 2;
|
||||||
hole.translate({hole_move_x, hole_move_y});
|
hole.translate(hole_move_x, hole_move_y);
|
||||||
hole2.translate({-hole_move_x, hole_move_y});
|
hole2.translate(-hole_move_x, hole_move_y);
|
||||||
hole3.translate({hole_move_x, -hole_move_y});
|
hole3.translate(hole_move_x, -hole_move_y);
|
||||||
hole4.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);
|
ExPolygon result(outline);
|
||||||
result.holes = {hole, hole2, hole3, hole4};
|
result.holes = {hole, hole2, hole3, hole4, hole5, hole6};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +282,9 @@ ExPolygons createTestIslands(double size)
|
|||||||
create_disc(3*size, size / 4, 30),
|
create_disc(3*size, size / 4, 30),
|
||||||
create_square_with_4holes(5 * size, 5 * size / 2 - size / 3),
|
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
|
// still problem
|
||||||
// three support points
|
// three support points
|
||||||
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
|
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user