mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 12:42:03 +08:00
Fix for sample between Tiny and Wide part of island
This commit is contained in:
parent
fd2193eb77
commit
0033deb1d4
@ -31,10 +31,10 @@ public:
|
||||
static bool is_majorit_x(const Vec2d &point);
|
||||
|
||||
/// <summary>
|
||||
/// Create perpendicular vector
|
||||
/// Create perpendicular vector[-y,x]
|
||||
/// </summary>
|
||||
/// <param name="vector">input vector from zero to point coordinate</param>
|
||||
/// <returns>Perpendicular vector</returns>
|
||||
/// <returns>Perpendicular[-vector.y, vector.x]</returns>
|
||||
static Point perp(const Point &vector);
|
||||
|
||||
/// <summary>
|
||||
|
@ -29,9 +29,9 @@ Slic3r::Polygon PolygonUtils::create_regular(size_t count_points,
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_equilateral_triangle(double edge_size)
|
||||
{
|
||||
return {{.0, .0},
|
||||
{edge_size, .0},
|
||||
{edge_size / 2., sqrt(edge_size * edge_size - edge_size * edge_size / 4)}};
|
||||
coord_t x = edge_size / 2;
|
||||
coord_t y = sqrt(edge_size * edge_size - edge_size * edge_size / 4) / 2;
|
||||
return {{-x, -y}, {x, -y}, {0, y}};
|
||||
}
|
||||
|
||||
Slic3r::Polygon PolygonUtils::create_isosceles_triangle(double side, double height)
|
||||
|
@ -49,6 +49,10 @@ struct SampleConfig
|
||||
|
||||
// Maximal count of align iteration
|
||||
size_t count_iteration = 100;
|
||||
|
||||
// Sample outline of Field by this value
|
||||
// Less than max_distance
|
||||
coord_t outline_sample_distance = 2;
|
||||
|
||||
// Maximal distance over Voronoi diagram edges to find closest point during aligning Support point
|
||||
coord_t max_align_distance = 0.;
|
||||
|
@ -63,6 +63,8 @@ public:
|
||||
result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * config.head_diameter;
|
||||
assert(result.min_width_for_outline_support >= result.max_width_for_center_support_line);
|
||||
|
||||
result.outline_sample_distance = result.max_distance;
|
||||
|
||||
// Align support points
|
||||
// TODO: propagate print resolution
|
||||
result.minimal_move = 1000; // [in nanometers], devide from print resolution to quater pixel
|
||||
|
@ -602,6 +602,22 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle(
|
||||
return result;
|
||||
}
|
||||
|
||||
void SampleIslandUtils::sample_field(
|
||||
VoronoiGraph::Position& field_start,
|
||||
SupportIslandPoints& points,
|
||||
CenterStarts& center_starts,
|
||||
std::set<const VoronoiGraph::Node *>& done,
|
||||
const Lines & lines,
|
||||
const SampleConfig &config)
|
||||
{
|
||||
auto field = create_field(field_start, center_starts, done, lines, config);
|
||||
SupportIslandPoints outline_support = sample_outline(field, config);
|
||||
points.insert(points.end(), std::move_iterator(outline_support.begin()),
|
||||
std::move_iterator(outline_support.end()));
|
||||
// TODO: sample field inside
|
||||
|
||||
}
|
||||
|
||||
SupportIslandPoints SampleIslandUtils::sample_expath(
|
||||
const VoronoiGraph::ExPath &path,
|
||||
const Lines & lines,
|
||||
@ -637,70 +653,75 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
|
||||
// TODO: 3) Triangle of points
|
||||
// eval outline and find three point create almost equilateral triangle
|
||||
|
||||
// IMPROVE: Erase continous sampling: Extract path and than sample uniformly whole path
|
||||
// IMPROVE: Erase continous sampling: Extract path and than sample uniformly whole path
|
||||
|
||||
CenterStarts center_starts;
|
||||
const VoronoiGraph::Node *start_node = path.nodes.front();
|
||||
// CHECK> Front of path is outline node
|
||||
assert(start_node->neighbors.size() == 1);
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = &start_node->neighbors.front();
|
||||
center_starts.emplace(neighbor, config.minimal_distance_from_outline);
|
||||
|
||||
std::set<const VoronoiGraph::Node *> done; // already done nodes
|
||||
done.insert(start_node);
|
||||
|
||||
SupportIslandPoints points; // result
|
||||
if (neighbor->max_width > config.max_width_for_center_support_line) {
|
||||
VoronoiGraph::Position field_start = VoronoiGraphUtils::get_position_with_distance(
|
||||
neighbor, config.min_width_for_outline_support, lines);
|
||||
double center_sample_distance = neighbor->edge_length * field_start.ratio;
|
||||
if (center_sample_distance > config.max_distance / 2.) {
|
||||
// sample field from node, start without change on begining
|
||||
sample_field(field_start, points, center_starts, done, lines, config);
|
||||
} else {
|
||||
const VoronoiGraph::Node::Neighbor *twin = VoronoiGraphUtils::get_twin(neighbor);
|
||||
done.insert(neighbor->node);
|
||||
coord_t support_in = neighbor->edge_length - center_sample_distance +
|
||||
config.max_distance / 2;
|
||||
center_starts.push(CenterStart(twin, support_in, {neighbor->node}));
|
||||
sample_field(field_start, points, center_starts, done, lines, config);
|
||||
}
|
||||
} else {
|
||||
done.insert(start_node);
|
||||
center_starts.push(CenterStart(neighbor, config.minimal_distance_from_outline));
|
||||
}
|
||||
|
||||
while (!center_starts.empty()) {
|
||||
FieldStart field_start;
|
||||
std::vector<CenterStart> new_starts = sample(center_starts.front(),
|
||||
config, done, points,
|
||||
field_start);
|
||||
std::optional<VoronoiGraph::Position> field_start = {};
|
||||
std::vector<CenterStart> new_starts =
|
||||
sample_center(center_starts.front(), config, done, points, lines, field_start);
|
||||
center_starts.pop();
|
||||
for (const CenterStart &start : new_starts) center_starts.push(start);
|
||||
if (field_start.neighbor != nullptr) {
|
||||
// TODO: create field
|
||||
auto field = create_field(field_start, center_starts, lines, config);
|
||||
if (field_start.has_value()){ // exist new field start?
|
||||
sample_field(field_start.value(), points, center_starts, done, lines, config);
|
||||
field_start = {};
|
||||
}
|
||||
}
|
||||
// Fix first point type
|
||||
if (!points.empty()) {
|
||||
auto &front = points.front();
|
||||
if (front->type == SupportIslandPoint::Type::center_line)
|
||||
front->type = SupportIslandPoint::Type::center_line_start;
|
||||
}
|
||||
|
||||
// TODO: remove next line, only for debug
|
||||
points.push_back(create_point_on_path(path.nodes, config.minimal_distance_from_outline));
|
||||
return std::move(points);
|
||||
return points;
|
||||
}
|
||||
|
||||
std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample(
|
||||
std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample_center(
|
||||
const CenterStart & start,
|
||||
const SampleConfig & config,
|
||||
std::set<const VoronoiGraph::Node *> &done,
|
||||
SupportIslandPoints & results,
|
||||
FieldStart & field_start)
|
||||
const Lines & lines,
|
||||
std::optional<VoronoiGraph::Position> &field_start)
|
||||
{
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = start.neighbor;
|
||||
const VoronoiGraph::Node *node = neighbor->node;
|
||||
if (done.find(node) != done.end()) return {};
|
||||
done.insert(node);
|
||||
|
||||
VoronoiGraph::Nodes path = start.path;
|
||||
std::vector<CenterStart> new_starts;
|
||||
double support_in = start.support_in;
|
||||
while (neighbor->max_width <= config.max_width_for_center_support_line) {
|
||||
do {
|
||||
double edge_length = neighbor->edge_length;
|
||||
while (edge_length > support_in) {
|
||||
while (edge_length >= support_in) {
|
||||
double ratio = support_in / edge_length;
|
||||
results.push_back(
|
||||
create_point(neighbor, ratio,
|
||||
SupportIslandPoint::Type::center_line));
|
||||
create_point(neighbor, ratio,
|
||||
SupportIslandPoint::Type::center_line));
|
||||
support_in += config.max_distance;
|
||||
}
|
||||
if (support_in > edge_length)
|
||||
support_in -= edge_length;
|
||||
|
||||
support_in -= edge_length;
|
||||
const VoronoiGraph::Node *node = neighbor->node;
|
||||
path.push_back(node);
|
||||
const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr;
|
||||
@ -733,9 +754,18 @@ std::vector<SampleIslandUtils::CenterStart> SampleIslandUtils::sample(
|
||||
} else {
|
||||
neighbor = next_neighbor;
|
||||
}
|
||||
} while (neighbor->max_width <= config.max_width_for_center_support_line);
|
||||
|
||||
field_start = VoronoiGraphUtils::get_position_with_distance(
|
||||
neighbor, config.min_width_for_outline_support, lines);
|
||||
double edge_length = neighbor->edge_length;
|
||||
double sample_length = edge_length * field_start->ratio;
|
||||
while (sample_length > support_in) {
|
||||
double ratio = support_in / edge_length;
|
||||
results.push_back(create_point(neighbor, ratio,
|
||||
SupportIslandPoint::Type::center_line));
|
||||
support_in += config.max_distance;
|
||||
}
|
||||
field_start.neighbor = neighbor;
|
||||
field_start.last_support = config.max_distance - support_in;
|
||||
return new_starts;
|
||||
}
|
||||
|
||||
@ -764,12 +794,14 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
|
||||
}
|
||||
|
||||
SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
const FieldStart &field_start,
|
||||
const VoronoiGraph::Position & field_start,
|
||||
CenterStarts & tiny_starts,
|
||||
std::set<const VoronoiGraph::Node *> &tiny_done,
|
||||
const Lines & lines,
|
||||
const SampleConfig &config)
|
||||
{
|
||||
using VD = Slic3r::Geometry::VoronoiDiagram;
|
||||
const coord_t min_width = config.min_width_for_outline_support;
|
||||
|
||||
// DTO represents one island change from wide to tiny part
|
||||
// it is stored inside map under source line index
|
||||
@ -804,21 +836,25 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
// store shortening of outline segments
|
||||
// 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
|
||||
auto add_wide_tiny_change = [&](const VoronoiGraph::Node::Neighbor *neighbor){
|
||||
VoronoiGraph::Position position =
|
||||
VoronoiGraphUtils::get_position_with_distance(neighbor, min_width, lines);
|
||||
Point p1, p2;
|
||||
std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines);
|
||||
const VD::edge_type *edge = neighbor->edge;
|
||||
size_t i1 = edge->cell()->source_index();
|
||||
size_t i2 = edge->twin()->cell()->source_index();
|
||||
auto add_wide_tiny_change =
|
||||
[&](const VoronoiGraph::Position &position,
|
||||
const VoronoiGraph::Node * source_node)->bool {
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = position.neighbor;
|
||||
|
||||
auto add = [&](const Point &p1, const Point &p2, size_t i1, size_t i2) {
|
||||
// TODO: check not only one neighbor but all path to edge
|
||||
if (VoronoiGraphUtils::is_last_neighbor(neighbor) &&
|
||||
neighbor->edge_length * (1. - position.ratio) <= config.max_distance / 2)
|
||||
return false;
|
||||
|
||||
// function to add sorted change from wide to tiny
|
||||
// stored uder line index or line shorten in point b
|
||||
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);
|
||||
auto item = wide_tiny_changes.find(i1);
|
||||
if (item == wide_tiny_changes.end()) {
|
||||
wide_tiny_changes[i1] = {change};
|
||||
} else {
|
||||
@ -826,22 +862,35 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
VectorUtils::insert_sorted(item->second, change, pred);
|
||||
}
|
||||
};
|
||||
|
||||
Point p1, p2;
|
||||
std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position,
|
||||
lines);
|
||||
const VD::edge_type *edge = neighbor->edge;
|
||||
size_t i1 = edge->cell()->source_index();
|
||||
size_t i2 = edge->twin()->cell()->source_index();
|
||||
|
||||
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
|
||||
// line1 is shorten on side line1.a --> line2 is shorten on
|
||||
// side line2.b
|
||||
add(p2, p1, i2, i1);
|
||||
} else {
|
||||
// line1 is shorten on side line1.b
|
||||
add(p1, p2, i1, i2);
|
||||
}
|
||||
coord_t support_in = neighbor->edge_length * position.ratio + config.max_distance/2;
|
||||
CenterStart tiny_start(neighbor, support_in, {source_node});
|
||||
tiny_starts.push(tiny_start);
|
||||
tiny_done.insert(source_node);
|
||||
return true;
|
||||
};
|
||||
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = field_start.neighbor;
|
||||
const VoronoiGraph::Node::Neighbor *twin_neighbor = VoronoiGraphUtils::get_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);
|
||||
}
|
||||
VoronoiGraph::Position position(twin_neighbor, 1. - field_start.ratio);
|
||||
add_wide_tiny_change(position, neighbor->node);
|
||||
|
||||
std::set<const VoronoiGraph::Node*> done;
|
||||
done.insert(twin_neighbor->node);
|
||||
std::queue<const VoronoiGraph::Node *> process;
|
||||
@ -864,9 +913,11 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
size_t index2 = edge->twin()->cell()->source_index();
|
||||
field_line_indexes.insert(index1);
|
||||
field_line_indexes.insert(index2);
|
||||
if (neighbor.max_width < config.min_width_for_outline_support) {
|
||||
add_wide_tiny_change(&neighbor);
|
||||
continue;
|
||||
if (VoronoiGraphUtils::is_last_neighbor(&neighbor) || neighbor.max_width < min_width) {
|
||||
VoronoiGraph::Position position =
|
||||
VoronoiGraphUtils::get_position_with_distance(&neighbor, min_width, lines);
|
||||
if(add_wide_tiny_change(position, node))
|
||||
continue;
|
||||
}
|
||||
if (done.find(neighbor.node) != done.end()) continue; // loop back
|
||||
if (next_node == nullptr) {
|
||||
@ -884,6 +935,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
std::map<size_t, size_t> b_connection =
|
||||
LineUtils::create_line_connection_over_b(lines);
|
||||
|
||||
std::vector<size_t> source_indexes;
|
||||
auto inser_point_b = [&](size_t& index, Points& points, std::set<size_t>& done)
|
||||
{
|
||||
const Line &line = lines[index];
|
||||
@ -892,29 +944,21 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
assert(connection_item != b_connection.end());
|
||||
done.insert(index);
|
||||
index = connection_item->second;
|
||||
source_indexes.push_back(index);
|
||||
};
|
||||
|
||||
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 {
|
||||
auto change_item = wide_tiny_changes.find(outline_index);
|
||||
while(change_item != wide_tiny_changes.end()) {
|
||||
auto insert_changes = [&](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);
|
||||
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;
|
||||
const Point & last_point = points.back();
|
||||
LineUtils::SortFromAToB pred(lines[index]);
|
||||
bool no_change = false;
|
||||
while (pred.compare(changes[change_index].new_b, last_point)) {
|
||||
++change_index;
|
||||
if (change_index >= changes.size()) {
|
||||
@ -924,29 +968,44 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
}
|
||||
if (no_change) break;
|
||||
}
|
||||
const WideTinyChange& change = changes[change_index];
|
||||
const WideTinyChange &change = changes[change_index];
|
||||
// prevent double points
|
||||
if (points.empty() || !PointUtils::is_equal(points.back(),change.new_b)){
|
||||
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)){
|
||||
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);
|
||||
}
|
||||
done.insert(index);
|
||||
index = change.next_line_index;
|
||||
// end of conture
|
||||
if (!is_first && index == input_index) return false;
|
||||
change_item = wide_tiny_changes.find(index);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
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;
|
||||
do {
|
||||
if (!insert_changes(outline_index, points, done_indexes, input_index))
|
||||
break;
|
||||
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()) {
|
||||
@ -961,39 +1020,101 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
|
||||
field.border.holes.emplace_back(hole_points);
|
||||
}
|
||||
}
|
||||
field.source_indexe_for_change = source_indexe_for_change;
|
||||
field.source_indexes = std::move(source_indexes);
|
||||
|
||||
#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;
|
||||
bool draw_source_line_indexes = true;
|
||||
bool draw_border_line_indexes = false;
|
||||
bool draw_field_source_indexes = true;
|
||||
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);
|
||||
}
|
||||
LineUtils::draw(svg, lines, source_line_color, 0., draw_source_line_indexes);
|
||||
draw(svg, field, draw_border_line_indexes, draw_field_source_indexes);
|
||||
}
|
||||
#endif //SLA_SAMPLING_STORE_FIELD_TO_SVG
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
SupportIslandPoints SampleIslandUtils::sample_outline(
|
||||
const Field &field, const SampleConfig &config)
|
||||
{
|
||||
coord_t sample_distance = config.outline_sample_distance;
|
||||
coord_t outline_distance = config.minimal_distance_from_outline;
|
||||
SupportIslandPoints result;
|
||||
auto add_sample = [&](const Line &line, size_t source_index, coord_t& last_support) {
|
||||
double line_length_double = line.length();
|
||||
coord_t line_length = static_cast<coord_t>(line_length_double);
|
||||
if (last_support + line_length > sample_distance) {
|
||||
Point dir = LineUtils::direction(line);
|
||||
Point perp = PointUtils::perp(dir);
|
||||
double size = perp.cast<double>().norm();
|
||||
Point move_from_outline = perp * (outline_distance / size);
|
||||
do {
|
||||
double ratio = (sample_distance - last_support) / line_length_double;
|
||||
Point point = line.a + dir * ratio + move_from_outline;
|
||||
result.emplace_back(std::make_unique<SupportOutlineIslandPoint>(
|
||||
point, source_index, SupportIslandPoint::Type::outline));
|
||||
last_support -= sample_distance;
|
||||
} while (last_support + line_length > sample_distance);
|
||||
}
|
||||
last_support += line_length;
|
||||
};
|
||||
Lines contour_lines = to_lines(field.border.contour);
|
||||
coord_t last_support = sample_distance / 2;
|
||||
for (const Line &line : contour_lines) {
|
||||
size_t index = &line - &contour_lines.front();
|
||||
assert(field.source_indexes.size() > index);
|
||||
size_t source_index = field.source_indexes[index];
|
||||
if (source_index == field.source_indexe_for_change) {
|
||||
last_support = sample_distance / 2;
|
||||
continue;
|
||||
}
|
||||
add_sample(line, source_index, last_support);
|
||||
}
|
||||
size_t index_offset = contour_lines.size();
|
||||
for (const Polygon &hole : field.border.holes) {
|
||||
Lines hole_lines = to_lines(hole);
|
||||
coord_t last_support = sample_distance / 2;
|
||||
for (const Line &line : hole_lines) {
|
||||
size_t hole_line_index = (&line - &hole_lines.front());
|
||||
size_t index = index_offset + hole_line_index;
|
||||
assert(field.source_indexes.size() > index);
|
||||
size_t source_index = field.source_indexes[index];
|
||||
add_sample(line, source_index, last_support);
|
||||
}
|
||||
index_offset += hole_lines.size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SampleIslandUtils::draw(SVG & svg,
|
||||
const Field &field,
|
||||
bool draw_border_line_indexes,
|
||||
bool draw_field_source_indexes)
|
||||
{
|
||||
const char *field_color = "red";
|
||||
const char *border_line_color = "blue";
|
||||
const char *source_index_text_color = "blue";
|
||||
svg.draw(field.border, field_color);
|
||||
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(), source_index_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleIslandUtils::draw(SVG & svg,
|
||||
const SupportIslandPoints &supportIslandPoints,
|
||||
double size,
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define slic3r_SLA_SuppotstIslands_SampleIslandUtils_hpp_
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
#include <libslic3r/Geometry.hpp>
|
||||
#include <libslic3r/Point.hpp>
|
||||
@ -173,12 +174,6 @@ public:
|
||||
/// <returns>Distance move of original point</returns>
|
||||
static coord_t align_support(SupportIslandPoint &support, const Point &wanted, double max_distance);
|
||||
|
||||
static void draw(SVG & svg,
|
||||
const SupportIslandPoints &supportIslandPoints,
|
||||
double size,
|
||||
const char *color = "lightgreen",
|
||||
bool write_type = true);
|
||||
|
||||
/// <summary>
|
||||
/// DTO hold information for start sampling VD in center
|
||||
/// </summary>
|
||||
@ -201,26 +196,7 @@ public:
|
||||
using CenterStarts = std::queue<CenterStart>;
|
||||
|
||||
/// <summary>
|
||||
/// DTO extend VG neighbor with information about last sample
|
||||
/// </summary>
|
||||
struct FieldStart
|
||||
{
|
||||
// define edge where start field
|
||||
const VoronoiGraph::Node::Neighbor *neighbor = nullptr;
|
||||
|
||||
// distance to last support
|
||||
// when last support lay on neighbor edge it is negative value
|
||||
coord_t last_support = 0; // [nano meters]
|
||||
|
||||
FieldStart() = default;
|
||||
FieldStart(const VoronoiGraph::Node::Neighbor *neighbor,
|
||||
coord_t last_support)
|
||||
: neighbor(neighbor), last_support(last_support)
|
||||
{}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Sample VG in center.
|
||||
/// Sample VG in center --> sample tiny part of island
|
||||
/// Detection of wide neighbor which start field
|
||||
/// Creating of new starts (from VG cross -> multi neighbors)
|
||||
/// </summary>
|
||||
@ -228,17 +204,19 @@ public:
|
||||
/// <param name="config">Parameters for sampling</param>
|
||||
/// <param name="done">Already done nodes</param>
|
||||
/// <param name="results">Result of sampling</param>
|
||||
/// <param name="liness">Source line for VD. To decide position of change from tiny to wide part</param>
|
||||
/// <param name="field_start">Output: Wide neighbor, start of field</param>
|
||||
/// <returns>New start of sampling</returns>
|
||||
static std::vector<CenterStart> sample(
|
||||
static std::vector<CenterStart> sample_center(
|
||||
const CenterStart & start,
|
||||
const SampleConfig & config,
|
||||
std::set<const VoronoiGraph::Node *> &done,
|
||||
SupportIslandPoints & results,
|
||||
FieldStart& field_start);
|
||||
const Lines &lines,
|
||||
std::optional<VoronoiGraph::Position> &field_start);
|
||||
|
||||
/// <summary>
|
||||
/// DTO represents area to sample
|
||||
/// DTO represents Wide parts of island to sample
|
||||
/// extend polygon with information about source lines
|
||||
/// </summary>
|
||||
struct Field
|
||||
@ -250,22 +228,60 @@ public:
|
||||
// indexes to source island lines
|
||||
// in case (index > lines.size()) it means fill the gap from tiny part of island
|
||||
std::vector<size_t> source_indexes;
|
||||
// value for source index of change from wide to tiny part of island
|
||||
size_t source_indexe_for_change;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create & sample field -- wide part of island
|
||||
/// </summary>
|
||||
/// <param name="field_start">Start neighbor, first occur of wide neighbor.</param>
|
||||
/// <param name="tiny_starts">Append new founded tiny parts of island.</param>
|
||||
/// <param name="tiny_done">Already sampled node sets. Filled only node inside field imediate after change</param>
|
||||
/// <param name="lines">Source lines for VG --> outline of island.</param>
|
||||
/// <param name="config">Containe Minimal width in field and sample distance for center line</param>
|
||||
static void sample_field(VoronoiGraph::Position &field_start,
|
||||
SupportIslandPoints & points,
|
||||
CenterStarts & center_starts,
|
||||
std::set<const VoronoiGraph::Node *> &done,
|
||||
const Lines & lines,
|
||||
const SampleConfig & config);
|
||||
|
||||
/// <summary>
|
||||
/// Create field from input neighbor
|
||||
/// </summary>
|
||||
/// <param name="field_start">Start neighbor, first occur of wide neighbor.</param>
|
||||
/// <param name="tiny_starts">Append new founded tiny parts of island.</param>
|
||||
/// <param name="tiny_done">Already sampled node sets. Filled only node inside field imediate after change</param>
|
||||
/// <param name="lines">Source lines for VG --> outline of island.</param>
|
||||
/// <param name="config">Parameters for sampling.</param>
|
||||
/// <param name="config">Containe Minimal width in field and sample distance for center line</param>
|
||||
/// <returns>New created field</returns>
|
||||
static Field create_field(const FieldStart & field_start,
|
||||
CenterStarts &tiny_starts,
|
||||
const Lines & lines,
|
||||
static Field create_field(const VoronoiGraph::Position &field_start,
|
||||
CenterStarts & tiny_starts,
|
||||
std::set<const VoronoiGraph::Node *> &tiny_done,
|
||||
const Lines & lines,
|
||||
const SampleConfig &config);
|
||||
|
||||
/// <summary>
|
||||
/// create support points on border of field
|
||||
/// </summary>
|
||||
/// <param name="field">Input field</param>
|
||||
/// <param name="config">Parameters for sampling.</param>
|
||||
/// <returns>support for outline</returns>
|
||||
static SupportIslandPoints sample_outline(const Field & field,
|
||||
const SampleConfig &config);
|
||||
|
||||
// debug draw functions
|
||||
static void draw(SVG & svg,
|
||||
const Field &field,
|
||||
bool draw_border_line_indexes = false,
|
||||
bool draw_field_source_indexes = true);
|
||||
|
||||
static void draw(SVG & svg,
|
||||
const SupportIslandPoints &supportIslandPoints,
|
||||
double size,
|
||||
const char *color = "lightgreen",
|
||||
bool write_type = true);
|
||||
};
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
|
@ -1177,6 +1177,10 @@ void VoronoiGraphUtils::draw(SVG & svg,
|
||||
draw(svg, path.nodes, width, mainPathColor);
|
||||
}
|
||||
|
||||
bool VoronoiGraphUtils::is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor)
|
||||
{
|
||||
return (neighbor->node->neighbors.size() == 1);
|
||||
}
|
||||
|
||||
void VoronoiGraphUtils::draw(const Polygon &polygon,
|
||||
const Lines & lines,
|
||||
|
@ -409,6 +409,13 @@ public:
|
||||
static double get_max_width(const VoronoiGraph::Nodes &path);
|
||||
static double get_max_width(const VoronoiGraph::Node *node);
|
||||
|
||||
/// <summary>
|
||||
/// Check if neighbor is end of VG
|
||||
/// </summary>
|
||||
/// <param name="neighbor">Neighbor to test</param>
|
||||
/// <returns>True when neighbor node has only one neighbor</returns>
|
||||
static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor);
|
||||
|
||||
public: // draw function for debug
|
||||
static void draw(SVG &svg, const VoronoiGraph &graph, coord_t width, bool pointer_caption = false);
|
||||
static void draw(SVG & svg,
|
||||
|
@ -222,7 +222,7 @@ ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||
{
|
||||
double hole_size = wide;
|
||||
double width = (3 + 1) * wide + 3 * hole_size;
|
||||
double height = wide + 2*tiny + 2*hole_size;
|
||||
double height = 2*wide + 2*tiny + 3*hole_size;
|
||||
auto outline = PolygonUtils::create_rect( width, height);
|
||||
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
|
||||
hole.reverse();
|
||||
@ -231,7 +231,7 @@ ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||
auto hole4 = hole; // copy
|
||||
|
||||
int hole_move_x = wide + hole_size;
|
||||
int hole_move_y = wide / 2 + hole_size / 2;
|
||||
int hole_move_y = wide + hole_size;
|
||||
hole.translate(hole_move_x, hole_move_y);
|
||||
hole2.translate(-hole_move_x, hole_move_y);
|
||||
hole3.translate(hole_move_x, -hole_move_y);
|
||||
@ -243,8 +243,15 @@ ExPolygon create_tiny_wide_test(double wide, double tiny)
|
||||
hole5.translate(0, hole_move_y);
|
||||
hole6.translate(0, -hole_move_y);
|
||||
|
||||
auto hole7 = PolygonUtils::create_equilateral_triangle(hole_size);
|
||||
hole7.reverse();
|
||||
auto hole8 = PolygonUtils::create_circle(hole_size/2, 7, Point(hole_move_x,0));
|
||||
hole8.reverse();
|
||||
auto hole9 = PolygonUtils::create_circle(hole_size/2, 5, Point(-hole_move_x,0));
|
||||
hole9.reverse();
|
||||
|
||||
ExPolygon result(outline);
|
||||
result.holes = {hole, hole2, hole3, hole4, hole5, hole6};
|
||||
result.holes = {hole, hole2, hole3, hole4, hole5, hole6, hole7, hole8, hole9};
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -415,6 +422,7 @@ SampleConfig create_sample_config(double size) {
|
||||
cfg.max_length_for_two_support_points = 4*size;
|
||||
cfg.max_width_for_center_support_line = size;
|
||||
cfg.min_width_for_outline_support = cfg.max_width_for_center_support_line;
|
||||
cfg.outline_sample_distance = cfg.max_distance;
|
||||
|
||||
cfg.minimal_move = std::max(1000., size/1000);
|
||||
cfg.count_iteration = 100;
|
||||
|
Loading…
x
Reference in New Issue
Block a user