Add outline angle rule to decide when support centre line

This commit is contained in:
Filip Sykala 2021-05-11 20:19:05 +02:00 committed by Lukas Matena
parent fe5f9ac382
commit 5d2b3cfc1e
10 changed files with 282 additions and 115 deletions

View File

@ -306,6 +306,16 @@ bool LineUtils::belongs(const Line &line, const Point &point, double benevolence
return false; return false;
} }
Slic3r::Point LineUtils::direction(const Line &line)
{
return line.b - line.a;
}
Slic3r::Point LineUtils::middle(const Line &line) {
// division before adding to prevent data type overflow
return line.a / 2 + line.b / 2;
}
double LineUtils::foot(const Line &line, const Point &point) double LineUtils::foot(const Line &line, const Point &point)
{ {
Vec2d a = line.a.cast<double>(); Vec2d a = line.a.cast<double>();

View File

@ -127,8 +127,15 @@ public:
/// Direction vector is represented as point /// Direction vector is represented as point
/// </summary> /// </summary>
/// <param name="line">input line</param> /// <param name="line">input line</param>
/// <returns>line direction</returns> /// <returns>line direction | b - a </returns>
static Point direction(const Line &line) { return line.b - line.a; } static Point direction(const Line &line);
/// <summary>
/// middle point, center of line
/// </summary>
/// <param name="line"></param>
/// <returns>ceneter of line | a+b / 2 </returns>
static Point middle(const Line &line);
/// <summary> /// <summary>
/// Calculate foot point in maner of Geometry::foot_pt /// Calculate foot point in maner of Geometry::foot_pt

View File

@ -29,6 +29,11 @@ struct SampleConfig
// Must be bigger than minimal_distance_from_outline // Must be bigger than minimal_distance_from_outline
coord_t maximal_distance_from_outline = 1.;// [nano meter] coord_t maximal_distance_from_outline = 1.;// [nano meter]
// When angle on outline is smaller than max_interesting_angle
// than create unmovable support point.
// Should be in range from Pi/2 to Pi
double max_interesting_angle = 2. / 3. * M_PI; // [radians]
// Distinguish when to add support point on VD outline point(center line sample) // Distinguish when to add support point on VD outline point(center line sample)
// MUST be bigger than minimal_distance_from_outline // MUST be bigger than minimal_distance_from_outline
coord_t minimal_support_distance = 0; coord_t minimal_support_distance = 0;

View File

@ -23,6 +23,7 @@
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG
@ -404,7 +405,15 @@ void SampleIslandUtils::align_samples(SupportIslandPoints &samples,
const ExPolygon & island, const ExPolygon & island,
const SampleConfig & config) const SampleConfig & config)
{ {
assert(samples.size() > 2); bool exist_moveable = false;
for (const auto &sample : samples) {
if (sample->can_move()) {
exist_moveable = true;
break;
}
}
if (!exist_moveable) return;
size_t count_iteration = config.count_iteration; // copy size_t count_iteration = config.count_iteration; // copy
coord_t max_move = 0; coord_t max_move = 0;
while (--count_iteration > 1) { while (--count_iteration > 1) {
@ -440,7 +449,6 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
const ExPolygon & island, const ExPolygon & island,
const SampleConfig & config) const SampleConfig & config)
{ {
assert(samples.size() > 2);
using VD = Slic3r::Geometry::VoronoiDiagram; using VD = Slic3r::Geometry::VoronoiDiagram;
VD vd; VD vd;
Slic3r::Points points = SampleIslandUtils::to_points(samples); Slic3r::Points points = SampleIslandUtils::to_points(samples);
@ -463,6 +471,28 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
// create voronoi diagram with points // create voronoi diagram with points
construct_voronoi(points.begin(), points.end(), &vd); construct_voronoi(points.begin(), points.end(), &vd);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
static int vd_counter = 0;
BoundingBox bbox(island);
std::string name = "align_VD_" + std::to_string(vd_counter++) + ".svg";
SVG svg(name.c_str(), bbox);
svg.draw(island);
for (const Point &point : points) {
size_t index = &point - &points.front();
svg.draw(point, "black", config.head_radius);
svg.draw_text(point + Point(config.head_radius,0), std::to_string(index).c_str(), "black");
}
Lines island_lines = to_lines(island);
svg.draw(island_lines, "blue");
for (const auto &edge: vd.edges()) {
std::optional<Line> line =
VoronoiGraphUtils::to_line(edge, points, config.max_distance);
if (!line.has_value()) continue;
svg.draw(*line, "green", 1e6);
}
svg.Close();
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
size_t max_move_index = -1;
for (const VD::cell_type &cell : vd.cells()) { for (const VD::cell_type &cell : vd.cells()) {
SupportIslandPointPtr &sample = samples[cell.source_index()]; SupportIslandPointPtr &sample = samples[cell.source_index()];
@ -482,12 +512,9 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
break; break;
} }
} }
assert(island_cell != nullptr); assert(island_cell != nullptr);
Point center = island_cell->centroid();
/*{
Point center = island_cell->centroid();
/*
{
SVG cell_svg("island_cell.svg", island_cell->points); SVG cell_svg("island_cell.svg", island_cell->points);
cell_svg.draw(cell_polygon, "lightgray"); cell_svg.draw(cell_polygon, "lightgray");
cell_svg.draw(points, "darkgray", config.head_radius); cell_svg.draw(points, "darkgray", config.head_radius);
@ -504,7 +531,10 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples,
svg.draw(center, color_wanted_point, config.head_radius); // wanted position svg.draw(center, color_wanted_point, config.head_radius); // wanted position
#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
coord_t act_move = sample->move(center); coord_t act_move = sample->move(center);
if (max_move < act_move) max_move = act_move; if (max_move < act_move) {
max_move = act_move;
max_move_index = cell.source_index();
}
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG
svg.draw(sample->point, color_new_point, config.head_radius); svg.draw(sample->point, color_new_point, config.head_radius);
svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str()); svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str());
@ -930,6 +960,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath(
if (position.has_value()) { if (position.has_value()) {
points.push_back(create_no_move_point( points.push_back(create_no_move_point(
*position, SupportIslandPoint::Type::center_line_start)); *position, SupportIslandPoint::Type::center_line_start));
// move nodes to done set
VoronoiGraph::Nodes start_path; VoronoiGraph::Nodes start_path;
for (const auto &node : path.nodes) { for (const auto &node : path.nodes) {
if (node == position->neighbor->node) break; if (node == position->neighbor->node) break;
@ -978,16 +1009,11 @@ void SampleIslandUtils::sample_field(VoronoiGraph::Position &field_start,
// Erode island to not sampled island around border, // Erode island to not sampled island around border,
// minimal value must be -config.minimal_distance_from_outline // minimal value must be -config.minimal_distance_from_outline
Polygons polygons = offset(field.border, -2.f * config.minimal_distance_from_outline, Polygons polygons = offset(field.border,
-2.f * config.minimal_distance_from_outline,
ClipperLib::jtSquare); ClipperLib::jtSquare);
if (polygons.empty()) return; if (polygons.empty()) return;
auto inner = std::make_shared<ExPolygon>(field.inner);
auto inner = std::make_shared<ExPolygon>(polygons.front());
for (size_t i = 1; i < polygons.size(); ++i) {
Polygon &hole = polygons[i];
inner->holes.push_back(hole);
}
Points inner_points = sample_expolygon(*inner, config.max_distance); Points inner_points = sample_expolygon(*inner, config.max_distance);
std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(points), std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(points),
[&](const Point &point) { [&](const Point &point) {
@ -1008,6 +1034,7 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
coord_t support_in; 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 || 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) {
@ -1033,7 +1060,7 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
double ratio = support_in / neighbor->length(); double ratio = support_in / neighbor->length();
VoronoiGraph::Position position(neighbor, ratio); VoronoiGraph::Position position(neighbor, ratio);
results.push_back(std::make_unique<SupportCenterIslandPoint>( results.push_back(std::make_unique<SupportCenterIslandPoint>(
position, &config, SupportIslandPoint::Type::center_line)); position, &config, SupportIslandPoint::Type::center_line1));
support_in += config.max_distance; support_in += config.max_distance;
is_continous = true; is_continous = true;
} }
@ -1051,24 +1078,24 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
next_neighbor = &node_neighbor; next_neighbor = &node_neighbor;
continue; continue;
} }
coord_t next_support_in = (support_in >= config.half_distance) ? new_starts.emplace_back(&node_neighbor, support_in, path); // search in side branch
support_in : (config.max_distance - support_in);
new_starts.emplace_back(&node_neighbor, next_support_in, path); // search in side branch
} }
if (next_neighbor == nullptr) { if (next_neighbor == nullptr) {
// no neighbor to continue if (neighbor->min_width() != 0) {
VoronoiGraph::Nodes path_reverse = path; // copy std::reverse(path.begin(), path.end());
std::reverse(path_reverse.begin(), path_reverse.end()); auto position_opt = create_position_on_path(path, support_in / 2);
coord_t width = 2 * config.minimal_distance_from_outline; if (position_opt.has_value()) {
coord_t distance = config.maximal_distance_from_outline; results.push_back(
auto position_opt = create_position_on_path(path_reverse, lines, width, distance); std::make_unique<SupportCenterIslandPoint>(
if (position_opt.has_value()) { *position_opt, &config,
if (is_continous && config.max_distance < (support_in+distance) ) { SupportIslandPoint::Type::center_line3));
// one support point should be enough
// when max_distance > maximal_distance_from_outline
results.pop_back(); // remove support point
} }
create_sample_center_end(*position_opt, results, new_starts, config); } else {
// no neighbor to continue
create_sample_center_end(*neighbor, is_continous, path,
support_in, lines, results,
new_starts, config);
} }
use_new_start = true; use_new_start = true;
} else { } else {
@ -1087,12 +1114,47 @@ std::optional<VoronoiGraph::Position> SampleIslandUtils::sample_center(
double ratio = support_in / edge_length; double ratio = support_in / edge_length;
VoronoiGraph::Position position(neighbor, ratio); VoronoiGraph::Position position(neighbor, ratio);
results.push_back(std::make_unique<SupportCenterIslandPoint>( results.push_back(std::make_unique<SupportCenterIslandPoint>(
position, &config,SupportIslandPoint::Type::center_line)); position, &config, SupportIslandPoint::Type::center_line2));
support_in += config.max_distance; support_in += config.max_distance;
} }
return result; return result;
} }
void SampleIslandUtils::create_sample_center_end(
const VoronoiGraph::Node::Neighbor &neighbor,
bool is_continous,
const VoronoiGraph::Nodes & path,
coord_t support_in,
const Lines & lines,
SupportIslandPoints & results,
CenterStarts & new_starts,
const SampleConfig & config)
{
// last neighbor?
if (neighbor.min_width() != 0) return;
// sharp corner?
double angle = VoronoiGraphUtils::outline_angle(neighbor, lines);
if (angle > config.max_interesting_angle) return;
// exist place for support?
VoronoiGraph::Nodes path_reverse = path; // copy
std::reverse(path_reverse.begin(), path_reverse.end());
coord_t width = 2 * config.minimal_distance_from_outline;
coord_t distance = config.maximal_distance_from_outline;
auto position_opt = create_position_on_path(path_reverse, lines, width, distance);
if (!position_opt.has_value()) return;
// check if exist popable result
if (is_continous && config.max_distance < (support_in + distance)) {
// one support point should be enough
// when max_distance > maximal_distance_from_outline
results.pop_back(); // remove support point
}
create_sample_center_end(*position_opt, results, new_starts, config);
}
void SampleIslandUtils::create_sample_center_end( void SampleIslandUtils::create_sample_center_end(
const VoronoiGraph::Position &position, const VoronoiGraph::Position &position,
SupportIslandPoints & results, SupportIslandPoints & results,
@ -1110,8 +1172,8 @@ 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;
near_no_move.push_back( // create raw pointer, used only in function scope
&*res); // create raw pointer, used only in function scope near_no_move.push_back(&*res);
} }
std::map<const VoronoiGraph::Node::Neighbor *, coord_t> distances; std::map<const VoronoiGraph::Node::Neighbor *, coord_t> distances;
@ -1412,6 +1474,8 @@ SampleIslandUtils::Field SampleIslandUtils::create_field(
} }
field.source_indexe_for_change = source_indexe_for_change; field.source_indexe_for_change = source_indexe_for_change;
field.source_indexes = std::move(source_indexes); field.source_indexes = std::move(source_indexes);
std::tie(field.inner, field.field_2_inner) =
outline_offset(field.border, config.minimal_distance_from_outline);
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
{ {
@ -1446,6 +1510,8 @@ SampleIslandUtils::outline_offset(const Slic3r::ExPolygon &island,
// TODO: Connect indexes for convert during creation of offset // TODO: Connect indexes for convert during creation of offset
// !! this implementation was fast for develop BUT NOT for running !! // !! this implementation was fast for develop BUT NOT for running !!
const double angle_tolerace = 1e-4;
const double distance_tolerance = 20.;
Lines island_lines = to_lines(island); Lines island_lines = to_lines(island);
Lines offset_lines = to_lines(offseted); Lines offset_lines = to_lines(offseted);
// Convert index map from island index to offseted index // Convert index map from island index to offseted index
@ -1459,15 +1525,23 @@ SampleIslandUtils::outline_offset(const Slic3r::ExPolygon &island,
Vec2d dir2 = LineUtils::direction(offset_line).cast<double>(); Vec2d dir2 = LineUtils::direction(offset_line).cast<double>();
dir2.normalize(); dir2.normalize();
double angle = acos(dir1.dot(dir2)); double angle = acos(dir1.dot(dir2));
if (fabs(angle) < 1e-4) { // in similar direction // not similar direction
Point middle = offset_line.a / 2 + offset_line.b / 2;
double distance = island_line.perp_distance_to(middle); if (fabs(angle) > angle_tolerace) continue;
if (fabs(distance - offset_distance) < 20) {
// found offseted line Point offset_middle = LineUtils::middle(offset_line);
converter[island_line_index] = offset_line_index; Point island_middle = LineUtils::middle(island_line);
break; Point diff_middle = offset_middle - island_middle;
} if (fabs(diff_middle.x()) > 2 * offset_distance ||
} fabs(diff_middle.y()) > 2 * offset_distance) continue;
double distance = island_line.perp_distance_to(offset_middle);
if (fabs(distance - offset_distance) > distance_tolerance)
continue;
// found offseted line
converter[island_line_index] = offset_line_index;
break;
} }
} }
@ -1480,10 +1554,6 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
const ExPolygon &border = field.border; const ExPolygon &border = field.border;
const Polygon &contour = border.contour; const Polygon &contour = border.contour;
assert(field.source_indexes.size() >= contour.size()); assert(field.source_indexes.size() >= contour.size());
// convert map from field index to inner(line index)
std::map<size_t, size_t> field_2_inner;
ExPolygon inner;
std::tie(inner, field_2_inner) = outline_offset(border, config.minimal_distance_from_outline);
coord_t max_align_distance = config.max_align_distance; coord_t max_align_distance = config.max_align_distance;
coord_t sample_distance = config.outline_sample_distance; coord_t sample_distance = config.outline_sample_distance;
SupportIslandPoints result; SupportIslandPoints result;
@ -1574,6 +1644,9 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
} }
}; };
// convert map from field index to inner(line index)
const std::map<size_t, size_t>& field_2_inner = field.field_2_inner;
const size_t& change_index = field.source_indexe_for_change; const size_t& change_index = field.source_indexe_for_change;
auto sample_polygon = [&](const Polygon &polygon, auto sample_polygon = [&](const Polygon &polygon,
const Polygon &inner_polygon, const Polygon &inner_polygon,
@ -1630,11 +1703,11 @@ SupportIslandPoints SampleIslandUtils::sample_outline(
}; };
size_t index_offset = 0; size_t index_offset = 0;
sample_polygon(contour, inner.contour, index_offset); sample_polygon(contour, field.inner.contour, index_offset);
index_offset = contour.size(); index_offset = contour.size();
for (size_t hole_index = 0; hole_index < border.holes.size(); ++hole_index) { for (size_t hole_index = 0; hole_index < border.holes.size(); ++hole_index) {
const Polygon &hole = border.holes[hole_index]; const Polygon &hole = border.holes[hole_index];
sample_polygon(hole, inner.holes[hole_index], index_offset); sample_polygon(hole, field.inner.holes[hole_index], index_offset);
index_offset += hole.size(); index_offset += hole.size();
} }
return result; return result;
@ -1646,7 +1719,8 @@ void SampleIslandUtils::draw(SVG & svg,
bool draw_field_source_indexes) bool draw_field_source_indexes)
{ {
const char *field_color = "red"; const char *field_color = "red";
const char *border_line_color = "blue"; const char *border_line_color = "blue";
const char *inner_line_color = "green";
const char *source_index_text_color = "blue"; const char *source_index_text_color = "blue";
svg.draw(field.border, field_color); svg.draw(field.border, field_color);
Lines border_lines = to_lines(field.border); Lines border_lines = to_lines(field.border);
@ -1657,10 +1731,27 @@ void SampleIslandUtils::draw(SVG & svg,
size_t index = &line - &border_lines.front(); size_t index = &line - &border_lines.front();
// start of holes // start of holes
if (index >= field.source_indexes.size()) break; if (index >= field.source_indexes.size()) break;
Point middle_point = (line.a + line.b) / 2; Point middle_point = LineUtils::middle(line);
std::string text = std::to_string(field.source_indexes[index]); std::string text = std::to_string(field.source_indexes[index]);
auto item = field.field_2_inner.find(index);
if (item != field.field_2_inner.end()) {
text += " inner " + std::to_string(item->second);
}
svg.draw_text(middle_point, text.c_str(), source_index_text_color); svg.draw_text(middle_point, text.c_str(), source_index_text_color);
} }
// draw inner
Lines inner_lines = to_lines(field.inner);
LineUtils::draw(svg, inner_lines, inner_line_color, 0.,
draw_border_line_indexes);
if (draw_field_source_indexes)
for (auto &line : inner_lines) {
size_t index = &line - &inner_lines.front();
Point middle_point = LineUtils::middle(line);
std::string text = std::to_string(index);
svg.draw_text(middle_point, text.c_str(), inner_line_color);
}
} }
void SampleIslandUtils::draw(SVG & svg, void SampleIslandUtils::draw(SVG & svg,
@ -1690,6 +1781,9 @@ bool SampleIslandUtils::is_visualization_disabled()
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG
return false; return false;
#endif #endif
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG
return false;
#endif
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG
return false; return false;
#endif #endif

View File

@ -281,6 +281,19 @@ public:
const SampleConfig & config); const SampleConfig & config);
private: private:
/// <summary>
///
/// </summary>
static void create_sample_center_end(
const VoronoiGraph::Node::Neighbor &neighbor,
bool is_continous,
const VoronoiGraph::Nodes & path,
coord_t support_in,
const Lines & lines,
SupportIslandPoints & results,
CenterStarts & new_starts,
const SampleConfig & config);
/// <summary> /// <summary>
/// Check near supports if no exists there add to results /// Check near supports if no exists there add to results
/// </summary> /// </summary>
@ -313,6 +326,11 @@ public :
std::vector<size_t> source_indexes; std::vector<size_t> source_indexes;
// value for source index of change from wide to tiny part of island // value for source index of change from wide to tiny part of island
size_t source_indexe_for_change; size_t source_indexe_for_change;
// inner part of field
ExPolygon inner;
// map to convert field index to inner index
std::map<size_t, size_t> field_2_inner;
}; };
/// <summary> /// <summary>

View File

@ -50,6 +50,9 @@ std::string SupportIslandPoint::to_string(const Type &type)
{{Type::one_center_point, "one_center_point"}, {{Type::one_center_point, "one_center_point"},
{Type::two_points,"two_points"}, {Type::two_points,"two_points"},
{Type::center_line, "center_line"}, {Type::center_line, "center_line"},
{Type::center_line1, "center_line1"},
{Type::center_line2, "center_line2"},
{Type::center_line3, "center_line3"},
{Type::center_line_end, "center_line_end"}, {Type::center_line_end, "center_line_end"},
{Type::center_line_end2, "center_line_end2"}, {Type::center_line_end2, "center_line_end2"},
{Type::center_line_end3, "center_line_end3"}, {Type::center_line_end3, "center_line_end3"},

View File

@ -19,6 +19,9 @@ public:
one_center_point, one_center_point,
two_points, two_points,
center_line, center_line,
center_line1, // sample line in center
center_line2, // rest of neighbor edge before position of Field start
center_line3, // end of loop, next neighbors are already sampled
center_line_end, // end of branch center_line_end, // end of branch
center_line_end2, // start of main path(only one per VD) center_line_end2, // start of main path(only one per VD)
center_line_end3, // end in continous sampling center_line_end3, // end in continous sampling

View File

@ -226,13 +226,15 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines,
points.push_back(p2); points.push_back(p2);
} }
Polygon polygon(points); Polygon polygon(points);
//if (!polygon.contains(center)) draw(polygon, lines, center); if (!polygon.contains(center)) {
draw(polygon, lines, center);
}
assert(polygon.is_valid()); assert(polygon.is_valid());
assert(polygon.contains(center)); assert(polygon.contains(center));
assert(PolygonUtils::is_not_self_intersect(polygon, center)); assert(PolygonUtils::is_not_self_intersect(polygon, center));
return polygon; return polygon;
} }
Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell, Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell,
const Slic3r::Points &points, const Slic3r::Points &points,
double maximal_distance) double maximal_distance)
@ -1162,6 +1164,77 @@ coord_t VoronoiGraphUtils::get_max_width(const VoronoiGraph::Node *node)
return max; return max;
} }
bool VoronoiGraphUtils::is_last_neighbor(
const VoronoiGraph::Node::Neighbor *neighbor)
{
return (neighbor->node->neighbors.size() == 1);
}
void VoronoiGraphUtils::for_neighbor_at_distance(
const VoronoiGraph::Position &position,
coord_t max_distance,
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)> fnc)
{
coord_t act_distance = position.calc_distance();
const VoronoiGraph::Node *act_node = position.neighbor->node;
const VoronoiGraph::Node *twin_node = get_twin_node(*position.neighbor);
std::set<const VoronoiGraph::Node *> done;
done.insert(twin_node);
done.insert(act_node);
std::queue<std::pair<const VoronoiGraph::Node *, coord_t>> process;
coord_t distance = position.calc_rest_distance();
if (distance < max_distance) process.push({twin_node, distance});
while (true) {
const VoronoiGraph::Node *next_node = nullptr;
coord_t next_distance = 0;
for (const auto &neighbor : act_node->neighbors) {
if (done.find(neighbor.node) != done.end())
continue; // already checked
done.insert(neighbor.node);
fnc(neighbor, act_distance);
coord_t length = static_cast<coord_t>(neighbor.length());
coord_t distance = act_distance + length;
if (distance >= max_distance) continue;
if (next_node == nullptr) {
next_node = neighbor.node;
next_distance = distance;
} else {
process.push({neighbor.node, distance});
}
}
if (next_node != nullptr) { // exist next node
act_node = next_node;
act_distance = next_distance;
} else if (!process.empty()) { // exist next process
act_node = process.front().first;
act_distance = process.front().second;
process.pop();
} else { // no next node neither process
break;
}
}
}
double VoronoiGraphUtils::outline_angle(const VoronoiGraph::Node::Neighbor &neighbor, const Lines& lines)
{
assert(neighbor.edge->is_linear());
assert(neighbor.min_width() == 0);
const VD::cell_type *c1 = neighbor.edge->cell();
const VD::cell_type *c2 = neighbor.edge->twin()->cell();
const Line &l1 = lines[c1->source_index()];
const Line &l2 = lines[c2->source_index()];
Vec2d d1 = LineUtils::direction(l1).cast<double>();
Vec2d d2 = LineUtils::direction(l2).cast<double>();
double dot = d1.dot(-d2);
return std::acos(dot/d1.norm() / d2.norm());
}
void VoronoiGraphUtils::draw(SVG & svg, void VoronoiGraphUtils::draw(SVG & svg,
const VoronoiGraph &graph, const VoronoiGraph &graph,
const Lines & lines, const Lines & lines,
@ -1200,56 +1273,6 @@ void VoronoiGraphUtils::draw(SVG & svg,
} }
} }
void VoronoiGraphUtils::for_neighbor_at_distance(
const VoronoiGraph::Position & position,
coord_t max_distance,
std::function<void(const VoronoiGraph::Node::Neighbor &, coord_t)> fnc)
{
coord_t act_distance = position.calc_distance();
const VoronoiGraph::Node *act_node = position.neighbor->node;
const VoronoiGraph::Node *twin_node = get_twin_node(*position.neighbor);
std::set<const VoronoiGraph::Node *> done;
done.insert(twin_node);
done.insert(act_node);
std::queue<std::pair<const VoronoiGraph::Node *, coord_t>> process;
coord_t distance = position.calc_rest_distance();
if (distance < max_distance)
process.push({twin_node, distance});
while (true) {
const VoronoiGraph::Node *next_node = nullptr;
coord_t next_distance = 0;
for (const auto &neighbor : act_node->neighbors) {
if (done.find(neighbor.node) != done.end())
continue; // already checked
done.insert(neighbor.node);
fnc(neighbor, act_distance);
coord_t length = static_cast<coord_t>(neighbor.length());
coord_t distance = act_distance + length;
if (distance >= max_distance) continue;
if (next_node == nullptr) {
next_node = neighbor.node;
next_distance = distance;
} else {
process.push({neighbor.node, distance});
}
}
if (next_node != nullptr) { // exist next node
act_node = next_node;
act_distance = next_distance;
} else if (!process.empty()) { // exist next process
act_node = process.front().first;
act_distance = process.front().second;
process.pop();
} else { // no next node neither process
break;
}
}
}
void VoronoiGraphUtils::draw(SVG & svg, void VoronoiGraphUtils::draw(SVG & svg,
const VD::edge_type &edge, const VD::edge_type &edge,
const Lines & lines, const Lines & lines,
@ -1330,11 +1353,6 @@ void VoronoiGraphUtils::draw(SVG & svg,
draw(svg, path.nodes, width, mainPathColor); 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, void VoronoiGraphUtils::draw(const Polygon &polygon,
const Lines & lines, const Lines & lines,
const Point & center) const Point & center)

View File

@ -454,6 +454,15 @@ public:
/// <returns>True when neighbor node has only one neighbor</returns> /// <returns>True when neighbor node has only one neighbor</returns>
static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor); static bool is_last_neighbor(const VoronoiGraph::Node::Neighbor *neighbor);
/// <summary>
/// only line created VG
/// only last neighbor
/// Calculate angle of outline(source lines) at end of voronoi diagram
/// </summary>
/// <param name="neighbor">Neighbor to calculate angle</param>
/// <returns>Angle of source lines in radians</returns>
static double outline_angle(const VoronoiGraph::Node::Neighbor &neighbor, const Lines& lines);
/// <summary> /// <summary>
/// Loop over neighbor in max distance from position /// Loop over neighbor in max distance from position
/// </summary> /// </summary>

View File

@ -328,6 +328,7 @@ ExPolygons createTestIslands(double size)
ExPolygon(create_V_shape(size*4, size / 3)), ExPolygon(create_V_shape(size*4, size / 3)),
ExPolygon(create_cross_roads(size, size / 3)), ExPolygon(create_cross_roads(size, size / 3)),
create_disc(3*size, size / 4, 30), create_disc(3*size, size / 4, 30),
create_disc(2*size, size, 12), // 3 points
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 // Tiny and wide part together with holes
@ -473,8 +474,8 @@ SampleConfig create_sample_config(double size) {
cfg.min_width_for_outline_support = cfg.max_width_for_center_support_line; cfg.min_width_for_outline_support = cfg.max_width_for_center_support_line;
cfg.outline_sample_distance = cfg.max_distance; cfg.outline_sample_distance = cfg.max_distance;
cfg.minimal_move = std::max(10000., size/40); cfg.minimal_move = static_cast<coord_t>(size/30);
cfg.count_iteration = 50; cfg.count_iteration = 100;
cfg.max_align_distance = 0; cfg.max_align_distance = 0;
return cfg; return cfg;
} }
@ -590,7 +591,6 @@ TEST_CASE("Small islands should be supported in center", "[SupGen], [VoronoiSkel
double size = 3e7; double size = 3e7;
SampleConfig cfg = create_sample_config(size); SampleConfig cfg = create_sample_config(size);
ExPolygons islands = createTestIslands(size); ExPolygons islands = createTestIslands(size);
islands = { create_disc(3 * size, 2*size , 20)};
for (ExPolygon &island : islands) { for (ExPolygon &island : islands) {
// information for debug which island cause problem // information for debug which island cause problem
[[maybe_unused]] size_t debug_index = &island - &islands.front(); [[maybe_unused]] size_t debug_index = &island - &islands.front();