Chenge is_last_neighbor to end_in_distance

This commit is contained in:
Filip Sykala - NTB T15p 2024-09-19 14:49:37 +02:00 committed by Lukas Matena
parent d26f0358fe
commit 7216e819b3
6 changed files with 184 additions and 124 deletions

View File

@ -70,7 +70,12 @@ struct SampleConfig
coord_t outline_sample_distance = 2; coord_t outline_sample_distance = 2;
// Maximal distance over Voronoi diagram edges to find closest point during aligning Support point // Maximal distance over Voronoi diagram edges to find closest point during aligning Support point
coord_t max_align_distance = 0.; coord_t max_align_distance = 0; // [nano meter]
// There is no need to calculate with precisse island
// NOTE: Slice of Cylinder bottom has tip of trinagles on contour
// (neighbor coordinate - create issue in voronoi)
double simplification_tolerance = 1e4; // [nm]
}; };
} // namespace Slic3r::sla } // namespace Slic3r::sla
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_ #endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_

View File

@ -17,10 +17,9 @@ public:
static SampleConfig create(const SupportPointGenerator::Config &config) static SampleConfig create(const SupportPointGenerator::Config &config)
{ {
coord_t head_diameter = scale_(config.head_diameter); coord_t head_diameter = scale_(config.head_diameter);
coord_t min_distance = scale_(config.minimal_distance); coord_t min_distance = head_diameter/2 + scale_(config.minimal_distance);
coord_t max_distance = 3 * min_distance; coord_t max_distance = 3 * min_distance;
coord_t sample_multiplicator = 10; // allign is made by selecting from samples coord_t sample_multiplicator = 8; // allign is made by selecting from samples
// TODO: find valid params !!!! // TODO: find valid params !!!!
SampleConfig result; SampleConfig result;

View File

@ -250,9 +250,10 @@ SupportIslandPoints SampleIslandUtils::create_side_points(
{ {
VoronoiGraph::Nodes reverse_path = path; // copy VoronoiGraph::Nodes reverse_path = path; // copy
std::reverse(reverse_path.begin(), reverse_path.end()); std::reverse(reverse_path.begin(), reverse_path.end());
coord_t distance2 = max_side_distance; // copy coord_t side_distance1 = max_side_distance; // copy
auto pos1 = create_position_on_path(path, lines, width, max_side_distance); coord_t side_distance2 = max_side_distance; // copy
auto pos2 = create_position_on_path(reverse_path, lines, width, distance2); auto pos1 = create_position_on_path(path, lines, width, side_distance1);
auto pos2 = create_position_on_path(reverse_path, lines, width, side_distance2);
assert(pos1.has_value()); assert(pos1.has_value());
assert(pos2.has_value()); assert(pos2.has_value());
SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points; SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points;
@ -423,7 +424,7 @@ void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
static int counter = 0; static int counter = 0;
SVG svg(("aligned_" + std::to_string(counter++) + ".svg").c_str(),BoundingBox(island)); SVG svg(("aligned_" + std::to_string(counter++) + ".svg").c_str(),BoundingBox(island.contour.points));
svg.draw(island); svg.draw(island);
draw(svg, samples, config.head_radius); draw(svg, samples, config.head_radius);
svg.Close(); svg.Close();
@ -463,7 +464,7 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
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; static int counter = 0;
BoundingBox bbox(island); BoundingBox bbox(island.contour.points);
SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox); SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox);
svg.draw(island, color_of_island ); svg.draw(island, color_of_island );
@ -888,9 +889,9 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph(
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
{ {
static int counter = 0; static int counter = 0;
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, 1e6, true); VoronoiGraphUtils::draw(svg, graph, lines, config.head_radius / 10, true);
} }
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
@ -924,13 +925,16 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
double max_width = VoronoiGraphUtils::get_max_width(path); double max_width = VoronoiGraphUtils::get_max_width(path);
if (max_width < config.max_width_for_center_support_line) { if (max_width < config.max_width_for_center_support_line) {
// 2) Two support points // 2) Two support points have to stretch island even if haed is not fully under island.
if (path.length < config.max_length_for_two_support_points) { if (path.length < config.max_length_for_two_support_points) {
coord_t max_distance = coord_t max_distance_by_length = static_cast<coord_t>(path.length / 4);
std::min(config.half_distance, static_cast<coord_t>(path.length / 2)); coord_t max_distance = std::min(config.half_distance, max_distance_by_length);
return create_side_points(path.nodes, lines,
2 * config.minimal_distance_from_outline, // Be carefull tiny island could contain overlapped support points
max_distance); assert(max_distance < (static_cast<coord_t>(path.length / 2) - config.head_radius));
coord_t min_width = 2 * config.head_radius; //minimal_distance_from_outline;
return create_side_points(path.nodes, lines, min_width, max_distance);
} }
// othewise sample path // othewise sample path
@ -995,7 +999,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
return points; return points;
} }
void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start, void SampleIslandUtils::sample_field(const VoronoiGraph::Position &field_start,
SupportIslandPoints & points, SupportIslandPoints & points,
CenterStarts & center_starts, CenterStarts & center_starts,
std::set<const VoronoiGraph::Node *> &done, std::set<const VoronoiGraph::Node *> &done,
@ -1029,13 +1033,11 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
const Lines & lines, const Lines & lines,
const SampleConfig & config) const SampleConfig & config)
{ {
const VoronoiGraph::Node::Neighbor *neighbor = nullptr; CenterStart start(nullptr, {}, {});
VoronoiGraph::Nodes path;
coord_t support_in;
bool use_new_start = true; bool use_new_start = true;
bool is_continous = false; bool is_continous = false;
while (use_new_start || neighbor->max_width() <= config.max_width_for_center_support_line) { while (use_new_start || start.neighbor->max_width() <= config.max_width_for_center_support_line) {
// !! do not check max width for new start, it could be wide to tiny change // !! do not check max width for new start, it could be wide to tiny change
if (use_new_start) { if (use_new_start) {
use_new_start = false; use_new_start = false;
@ -1046,31 +1048,28 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
if (new_starts.empty()) return {}; if (new_starts.empty()) return {};
} }
// fill new start // fill new start
const CenterStart & new_start = new_starts.back(); start = std::move(new_starts.back());
neighbor = new_start.neighbor;
path = new_start.path; // copy
support_in = new_start.support_in;
new_starts.pop_back(); new_starts.pop_back();
is_continous = false; is_continous = false;
} }
// add support on actual neighbor edge // add support on actual neighbor edge
coord_t edge_length = static_cast<coord_t>(neighbor->length()); coord_t edge_length = static_cast<coord_t>(start.neighbor->length());
while (edge_length >= support_in) { while (edge_length >= start.support_in) {
double ratio = support_in / neighbor->length(); double ratio = start.support_in / start.neighbor->length();
VoronoiGraph::Position position(neighbor, ratio); VoronoiGraph::Position position(start.neighbor, ratio);
results.push_back(std::make_unique<SupportCenterIslandPoint>( results.push_back(std::make_unique<SupportCenterIslandPoint>(
position, &config, SupportIslandPoint::Type::center_line1)); position, &config, SupportIslandPoint::Type::center_line1));
support_in += config.max_distance; start.support_in += config.max_distance;
is_continous = true; is_continous = true;
} }
support_in -= edge_length; start.support_in -= edge_length;
const VoronoiGraph::Node *node = 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
path.push_back(node); start.path.push_back(node);
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; if (done.find(node_neighbor.node) != done.end()) continue;
@ -1078,13 +1077,13 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
next_neighbor = &node_neighbor; next_neighbor = &node_neighbor;
continue; continue;
} }
new_starts.emplace_back(&node_neighbor, support_in, 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 (neighbor->min_width() != 0) { if (start.neighbor->min_width() != 0) {
std::reverse(path.begin(), path.end()); std::reverse(start.path.begin(), start.path.end());
auto position_opt = create_position_on_path(path, support_in / 2); auto position_opt = create_position_on_path(start.path, start.support_in / 2);
if (position_opt.has_value()) { if (position_opt.has_value()) {
results.push_back( results.push_back(
std::make_unique<SupportCenterIslandPoint>( std::make_unique<SupportCenterIslandPoint>(
@ -1093,29 +1092,30 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
} }
} else { } else {
// no neighbor to continue // no neighbor to continue
create_sample_center_end(*neighbor, is_continous, path, create_sample_center_end(*start.neighbor, is_continous, start.path,
support_in, lines, results, start.support_in, lines, results,
new_starts, config); new_starts, config);
} }
use_new_start = true; use_new_start = true;
} else { } else {
neighbor = next_neighbor; start.neighbor = next_neighbor;
} }
} }
// create field start // create field start
auto result = VoronoiGraphUtils::get_position_with_width( auto result = VoronoiGraphUtils::get_position_with_width(
neighbor, config.min_width_for_outline_support, lines); start.neighbor, config.min_width_for_outline_support, lines
);
// sample rest of neighbor before field // sample rest of neighbor before field
double edge_length = neighbor->length(); double edge_length = start.neighbor->length();
double sample_length = edge_length * result.ratio; double sample_length = edge_length * result.ratio;
while (sample_length > support_in) { while (sample_length > start.support_in) {
double ratio = support_in / edge_length; double ratio = start.support_in / edge_length;
VoronoiGraph::Position position(neighbor, ratio); VoronoiGraph::Position position(start.neighbor, ratio);
results.push_back(std::make_unique<SupportCenterIslandPoint>( results.push_back(std::make_unique<SupportCenterIslandPoint>(
position, &config, SupportIslandPoint::Type::center_line2)); position, &config, SupportIslandPoint::Type::center_line2));
support_in += config.max_distance; start.support_in += config.max_distance;
} }
return result; return result;
} }
@ -1140,22 +1140,25 @@ void SampleIslandUtils::create_sample_center_end(
// exist place for support? // exist place for support?
VoronoiGraph::Nodes path_reverse = path; // copy VoronoiGraph::Nodes path_reverse = path; // copy
std::reverse(path_reverse.begin(), path_reverse.end()); std::reverse(path_reverse.begin(), path_reverse.end());
coord_t width = 2 * config.minimal_distance_from_outline; coord_t width = 2 * config.minimal_distance_from_outline;
coord_t distance = config.maximal_distance_from_outline; coord_t distance = config.maximal_distance_from_outline;
auto position_opt = create_position_on_path(path_reverse, lines, width, distance); auto position_opt = create_position_on_path(path_reverse, lines, width, distance);
if (!position_opt.has_value()) return; if (!position_opt.has_value()) return;
// check if exist popable result if(!create_sample_center_end(*position_opt, results, new_starts, config))
if (is_continous && config.max_distance < (support_in + distance)) { return;
// check if exist unneccesary support point before no move end
if (is_continous && config.max_distance < (support_in + distance) && results.size()>2) {
// one support point should be enough // one support point should be enough
// when max_distance > maximal_distance_from_outline // when max_distance > maximal_distance_from_outline
results.pop_back(); // remove support point
// one before last is not needed
results.erase(results.end() - 2);// remove support point
} }
create_sample_center_end(*position_opt, results, new_starts, config);
} }
void SampleIslandUtils::create_sample_center_end( bool SampleIslandUtils::create_sample_center_end(
const VoronoiGraph::Position &position, const VoronoiGraph::Position &position,
SupportIslandPoints & results, SupportIslandPoints & results,
CenterStarts & new_starts, CenterStarts & new_starts,
@ -1172,61 +1175,54 @@ void SampleIslandUtils::create_sample_center_end(
Point diff = point - res->point; Point diff = point - res->point;
if (abs(diff.x()) > minimal_support_distance) continue; if (abs(diff.x()) > minimal_support_distance) continue;
if (abs(diff.y()) > minimal_support_distance) continue; if (abs(diff.y()) > minimal_support_distance) continue;
// do not add overlapping end point
if (diff.x() < config.head_radius &&
diff.y() < config.head_radius) return false;
// create raw pointer, used only in function scope // create raw pointer, used only in function scope
near_no_move.push_back(&*res); near_no_move.push_back(&*res);
} }
std::map<const VoronoiGraph::Node::Neighbor *, coord_t> distances; std::map<const VoronoiGraph::Node::Neighbor *, coord_t> distances;
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)>
collect_distances = [&](const auto &neighbor, coord_t act_distance) {
distances[&neighbor] = act_distance;
};
VoronoiGraphUtils::for_neighbor_at_distance(position, minimal_support_distance, collect_distances);
bool exist_no_move = false;
if (!near_no_move.empty()) { if (!near_no_move.empty()) {
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)>
collect_distances = [&distances](const auto &neighbor, coord_t act_distance) {
distances[&neighbor] = act_distance;
};
VoronoiGraphUtils::for_neighbor_at_distance(position, minimal_support_distance, collect_distances);
for (const auto &item : distances) { for (const auto &item : distances) {
const VoronoiGraph::Node::Neighbor &neighbor = *item.first; const VoronoiGraph::Node::Neighbor &neighbor = *item.first;
// TODO: create belongs for parabola, when start sampling at parabola // TODO: create belongs for parabola, when start sampling at parabola
Line edge(VoronoiGraphUtils::to_point(neighbor.edge->vertex0()), Line edge(VoronoiGraphUtils::to_point(neighbor.edge->vertex0()),
VoronoiGraphUtils::to_point(neighbor.edge->vertex1())); VoronoiGraphUtils::to_point(neighbor.edge->vertex1()));
for (const auto &support_point : near_no_move) { for (const auto &support_point : near_no_move) {
if (LineUtils::belongs(edge, support_point->point, 10000)) { if (LineUtils::belongs(edge, support_point->point, 10000))
exist_no_move = true; return false;
break;
}
} }
if (exist_no_move) break;
} }
} }
if (!exist_no_move) { // fix value of support_in
// fix value of support_in // for new_starts in sampled path
// for new_starts in sampled path // by distance to position
// by distance to position for (CenterStart &new_start : new_starts) {
for (CenterStart &new_start : new_starts) { auto item = distances.find(new_start.neighbor);
auto item = distances.find(new_start.neighbor); if (item != distances.end()) {
coord_t support_distance = item->second;
coord_t new_support_in = config.max_distance - support_distance;
new_start.support_in = std::max(new_start.support_in, new_support_in);
} else {
const VoronoiGraph::Node::Neighbor *twin =
VoronoiGraphUtils::get_twin(*new_start.neighbor);
item = distances.find(twin);
if (item != distances.end()) { if (item != distances.end()) {
coord_t support_distance = item->second; coord_t support_distance = item->second + static_cast<coord_t>(twin->length());
coord_t new_support_in = config.max_distance - item->second; coord_t new_support_in = config.max_distance - support_distance;
new_start.support_in = std::max(new_start.support_in, new_start.support_in = std::max(new_start.support_in, new_support_in);
new_support_in);
} else {
const VoronoiGraph::Node::Neighbor *twin =
VoronoiGraphUtils::get_twin(*new_start.neighbor);
auto item = distances.find(twin);
if (item != distances.end()) {
coord_t support_distance = item->second + twin->length();
coord_t new_support_in = config.max_distance -
support_distance;
new_start.support_in = std::max(new_start.support_in,
new_support_in);
}
} }
} }
results.push_back(
std::make_unique<SupportIslandNoMovePoint>(point, no_move_type));
} }
results.push_back(std::make_unique<SupportIslandNoMovePoint>(point, no_move_type));
return true;
} }
@ -1238,7 +1234,6 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
const SampleConfig &config) const SampleConfig &config)
{ {
using VD = Slic3r::Geometry::VoronoiDiagram; 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 // DTO represents one island change from wide to tiny part
// it is stored inside map under source line index // it is stored inside map under source line index
@ -1269,31 +1264,26 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
}; };
}; };
using WideTinyChanges = std::vector<WideTinyChange>; using WideTinyChanges = std::vector<WideTinyChange>;
// store shortening of outline segments // store shortening of outline segments
// line index, vector<next line index + 2x shortening points> // line index, vector<next line index + 2x shortening points>
std::map<size_t, WideTinyChanges> wide_tiny_changes; std::map<size_t, WideTinyChanges> wide_tiny_changes;
coord_t minimal_edge_length = std::max(config.max_distance / 2, 2*config.minimal_distance_from_outline); coord_t minimal_edge_length = std::max(config.max_distance / 2, 2*config.minimal_distance_from_outline);
coord_t half_max_distance = config.max_distance / 2;
// 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
auto add_wide_tiny_change = auto add_wide_tiny_change =
[&](const VoronoiGraph::Position &position, [minimal_edge_length, half_max_distance, &wide_tiny_changes,
const VoronoiGraph::Node * source_node)->bool { &lines, &tiny_starts, &tiny_done]
const VoronoiGraph::Node::Neighbor *neighbor = position.neighbor; (const VoronoiGraph::Position &position, const VoronoiGraph::Node *source_node)->bool{
if (VoronoiGraphUtils::ends_in_distanace(position, minimal_edge_length))
// IMPROVE: check not only one neighbor but all path to edge
coord_t rest_size = static_cast<coord_t>(neighbor->length() * (1. - position.ratio));
if (VoronoiGraphUtils::is_last_neighbor(neighbor) &&
rest_size <= minimal_edge_length)
return false; // no change only rich outline return false; // no change only rich outline
// function to add sorted change from wide to tiny // function to add sorted change from wide to tiny
// stored uder line index or line shorten in point b // stored uder line index or line shorten in point b
auto add = [&](const Point &p1, const Point &p2, size_t i1, auto add = [&](const Point &p1, const Point &p2, size_t i1, size_t i2) {
size_t i2) {
WideTinyChange change(p1, p2, 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()) { if (item == wide_tiny_changes.end()) {
wide_tiny_changes[i1] = {change}; wide_tiny_changes[i1] = {change};
} else { } else {
@ -1304,26 +1294,27 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
Point p1, p2; Point p1, p2;
std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines); std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines);
const VoronoiGraph::Node::Neighbor *neighbor = position.neighbor;
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();
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 // line1 is shorten on side line1.a --> line2 is shorten on side line2.b
// side line2.b
add(p2, p1, i2, i1); add(p2, p1, i2, i1);
} else { } else {
// line1 is shorten on side line1.b // line1 is shorten on side line1.b
add(p1, p2, i1, i2); add(p1, p2, i1, i2);
} }
coord_t support_in = neighbor->length() * position.ratio + config.max_distance/2; coord_t support_in = neighbor->length() * position.ratio + half_max_distance;
CenterStart tiny_start(neighbor, support_in, {source_node}); CenterStart tiny_start(neighbor, support_in, {source_node});
tiny_starts.push_back(tiny_start); tiny_starts.push_back(tiny_start);
tiny_done.insert(source_node); tiny_done.insert(source_node);
return true; return true;
}; };
const coord_t min_width = config.min_width_for_outline_support;
const VoronoiGraph::Node::Neighbor *tiny_wide_neighbor = field_start.neighbor; const VoronoiGraph::Node::Neighbor *tiny_wide_neighbor = field_start.neighbor;
const VoronoiGraph::Node::Neighbor *wide_tiny_neighbor = VoronoiGraphUtils::get_twin(*tiny_wide_neighbor); const VoronoiGraph::Node::Neighbor *wide_tiny_neighbor = VoronoiGraphUtils::get_twin(*tiny_wide_neighbor);
VoronoiGraph::Position position(wide_tiny_neighbor, 1. - field_start.ratio); VoronoiGraph::Position position(wide_tiny_neighbor, 1. - field_start.ratio);
@ -1380,7 +1371,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
LineUtils::create_line_connection_over_b(lines); LineUtils::create_line_connection_over_b(lines);
std::vector<size_t> source_indexes; std::vector<size_t> source_indexes;
auto inser_point_b = [&](size_t& index, Points& points, std::set<size_t>& done) auto inser_point_b = [&lines, &b_connection, &source_indexes]
(size_t &index, Points &points, std::set<size_t> &done)
{ {
const Line &line = lines[index]; const Line &line = lines[index];
points.push_back(line.b); points.push_back(line.b);
@ -1392,14 +1384,15 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
}; };
size_t source_indexe_for_change = lines.size(); size_t source_indexe_for_change = lines.size();
auto insert_changes = [&](size_t &index, Points &points, std::set<size_t> &done, size_t input_index)->bool { 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 {
bool is_first = points.empty(); 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 (!points.empty()) { if (!is_first) {
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;
@ -1413,11 +1406,9 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
if (no_change) break; if (no_change) break;
// Field ends with change into first index // Field ends with change into first index
if (!is_first && change_item->first == input_index && if (change_item->first == input_index &&
change_index == 0) { change_index == 0) {
return false; return false;
} else {
is_first = false;
} }
} }
const WideTinyChange &change = changes[change_index]; const WideTinyChange &change = changes[change_index];
@ -1442,6 +1433,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
return true; return true;
}; };
// Collect outer points of field
Points points; Points points;
points.reserve(field_line_indexes.size()); points.reserve(field_line_indexes.size());
std::vector<size_t> outline_indexes; std::vector<size_t> outline_indexes;

View File

@ -304,7 +304,8 @@ private:
/// <param name="config">Parameters for sampling, /// <param name="config">Parameters for sampling,
/// minimal_support_distance - search distance in VD /// minimal_support_distance - search distance in VD
/// max_distance - for fix new_start</param> /// max_distance - for fix new_start</param>
static void create_sample_center_end( /// <returns>True when add point into result otherwise false</returns>
static bool create_sample_center_end(
const VoronoiGraph::Position &position, const VoronoiGraph::Position &position,
SupportIslandPoints & results, SupportIslandPoints & results,
CenterStarts & new_starts, CenterStarts & new_starts,
@ -341,7 +342,7 @@ public :
/// <param name="tiny_done">Already sampled node sets. Filled only node inside field imediate after change</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="lines">Source lines for VG --> outline of island.</param>
/// <param name="config">Containe Minimal width in field and sample distance for center line</param> /// <param name="config">Containe Minimal width in field and sample distance for center line</param>
static void sample_field(VoronoiGraph::Position &field_start, static void sample_field(const VoronoiGraph::Position &field_start,
SupportIslandPoints & points, SupportIslandPoints & points,
CenterStarts & center_starts, CenterStarts & center_starts,
std::set<const VoronoiGraph::Node *> &done, std::set<const VoronoiGraph::Node *> &done,

View File

@ -922,6 +922,8 @@ Slic3r::Point VoronoiGraphUtils::create_edge_point(const VD::edge_type *edge,
return Point(v0->x() + dir.x(), v0->y() + dir.y()); return Point(v0->x() + dir.x(), v0->y() + dir.y());
} }
// NOTE: Heuristic is bad -> Width is not linear on edge e.g. VD of hexagon
// Solution: Edge has to know width changes.
VoronoiGraph::Position VoronoiGraphUtils::get_position_with_width( VoronoiGraph::Position VoronoiGraphUtils::get_position_with_width(
const VoronoiGraph::Node::Neighbor *neighbor, coord_t width, const Slic3r::Lines &lines) const VoronoiGraph::Node::Neighbor *neighbor, coord_t width, const Slic3r::Lines &lines)
{ {
@ -1164,10 +1166,70 @@ coord_t VoronoiGraphUtils::get_max_width(const VoronoiGraph::Node *node)
return max; return max;
} }
bool VoronoiGraphUtils::is_last_neighbor( // START use instead of is_last_neighbor
const VoronoiGraph::Node::Neighbor *neighbor) bool VoronoiGraphUtils::ends_in_distanace(const VoronoiGraph::Position &position, coord_t max_distance) {
{ const VoronoiGraph::Node *node = position.neighbor->node;
return (neighbor->node->neighbors.size() == 1); coord_t rest_distance = max_distance - position.calc_rest_distance();
if (rest_distance < 0)
return false;
// speed up - end of gpraph is no need investigate further
if (node->neighbors.size() == 1)
return true;
// Already processed nodes
std::set<const VoronoiGraph::Node *> done;
done.insert(get_twin_node(*position.neighbor));
struct Next{
const VoronoiGraph::Node *node;
coord_t rest_distance;
};
// sorted by distance from position from biggest
std::vector<Next> process_queue;
do {
done.insert(node);
for (const VoronoiGraph::Node::Neighbor &neighbor: node->neighbors){
const VoronoiGraph::Node *neighbor_node = neighbor.node;
// Check whether node is already done
// Nodes are processed from closer to position
// soo done neighbor have to has bigger rest_distance
if (done.find(neighbor_node) != done.end())
// node is already explore
continue;
coord_t neighbor_rest = rest_distance - static_cast<coord_t>(neighbor.length());
if (neighbor_rest < 0)
// exist node far than max distance
return false;
// speed up - end of gpraph is no need to add to the process queue
if (neighbor_node->neighbors.size() == 1)
continue;
// check whether exist in queue this node with farer path and fix it
auto it = std::find_if(process_queue.begin(), process_queue.end(),
[neighbor_node](const Next &n) { return n.node == neighbor_node;});
if (it == process_queue.end()){
process_queue.emplace_back(Next{neighbor_node, neighbor_rest});
} else if (it->rest_distance < neighbor_rest) {
// found shorter path to node
it->rest_distance = neighbor_rest;
}
}
if (process_queue.empty())
return true;
// find biggest rest distance -> closest to input position
auto next = std::max_element(process_queue.begin(), process_queue.end(),
[](const Next& n1, const Next& n2){
return n1.rest_distance < n2.rest_distance;
});
rest_distance = next->rest_distance;
node = next->node;
process_queue.erase(next); // process queue pop
} while (true);
} }
void VoronoiGraphUtils::for_neighbor_at_distance( void VoronoiGraphUtils::for_neighbor_at_distance(

View File

@ -448,11 +448,12 @@ public:
static coord_t get_max_width(const VoronoiGraph::Node *node); static coord_t get_max_width(const VoronoiGraph::Node *node);
/// <summary> /// <summary>
/// Check if neighbor is end of VG /// Check wheather VG ends in smaller distance than given one
/// </summary> /// </summary>
/// <param name="neighbor">Neighbor to test</param> /// <param name="position">Position in direction to checked end</param>
/// <returns>True when neighbor node has only one neighbor</returns> /// <param name="max_distance">distance to explore</param>
static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor); /// <returns>True when there is only smaller VD path to edge</returns>
static bool ends_in_distanace(const VoronoiGraph::Position &position, coord_t max_distance);
/// <summary> /// <summary>
/// only line created VG /// only line created VG