mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 23:45:52 +08:00
Add outline angle rule to decide when support centre line
This commit is contained in:
parent
fe5f9ac382
commit
5d2b3cfc1e
@ -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>();
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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"},
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user