Add detection and creation of peninsula

with anotation of outline.
This commit is contained in:
Filip Sykala - NTB T15p 2024-12-04 16:56:09 +01:00 committed by Lukas Matena
parent 08ee5524d5
commit fdc9985e50
2 changed files with 136 additions and 1 deletions

View File

@ -498,6 +498,102 @@ void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part,
near_points.remove_out_of(extend_shape);
}
/// <summary>
/// Detect existence of peninsula on current layer part
/// </summary>
/// <param name="part">IN/OUT island part containing peninsulas</param>
/// <param name="min_peninsula_width">minimal width of overhang to become peninsula</param>
void create_peninsulas(LayerPart &part, float min_peninsula_width) {
const Polygons below_polygons = get_polygons(part.prev_parts);
const Polygons below_expanded = expand(below_polygons, min_peninsula_width, ClipperLib::jtSquare);
const ExPolygon &part_shape = *part.shape;
ExPolygons over_peninsula = diff_ex(part_shape, below_expanded);
if (over_peninsula.empty())
return; // only tiny overhangs
// exist layer part over peninsula limit
ExPolygons peninsulas_shape = diff_ex(part_shape, below_polygons);
// IMPROVE: Anotate source of diff by ClipperLib_Z
Lines below_lines = to_lines(below_polygons);
auto get_angle = [](const Line &l) {
Point diff = l.b - l.a;
if (diff.x() < 0) // Only positive direction X
diff = -diff;
return atan2(diff.y(), diff.x());
};
std::vector<double> belowe_line_angle; // define direction of line with positive X
belowe_line_angle.reserve(below_lines.size());
for (const Line& l : below_lines)
belowe_line_angle.push_back(get_angle(l));
std::vector<size_t> idx(below_lines.size());
std::iota(idx.begin(), idx.end(), 0);
auto is_lower = [&belowe_line_angle](size_t i1, size_t i2) {
return belowe_line_angle[i1] < belowe_line_angle[i2]; };
std::sort(idx.begin(), idx.end(), is_lower);
auto is_overlap = [&get_angle, &idx, &is_lower, &below_lines, &belowe_line_angle]
(const Line &l) {
// allowed angle epsilon
const double angle_epsilon = 1e-3;
const double paralel_epsilon = scale_(1e-2);
double angle = get_angle(l);
double low_angle = angle - angle_epsilon;
bool is_over = false;
if (low_angle <= -M_PI_2) {
low_angle += M_PI;
is_over = true;
}
double hi_angle = angle + angle_epsilon;
if (hi_angle >= M_PI_2) {
hi_angle -= M_PI;
is_over = true;
}
int mayorit_idx = 0;
if (Point d = l.a - l.b;
abs(d.x()) < abs(d.y()))
mayorit_idx = 1;
coord_t low = l.a[mayorit_idx];
coord_t high = l.b[mayorit_idx];
if (low > high)
std::swap(low, high);
auto it_idx = std::lower_bound(idx.begin(), idx.end(), low_angle, is_lower);
if (is_over && it_idx == idx.end()) {
it_idx = idx.begin();
is_over = false;
}
while (is_over || it_idx != idx.end() || belowe_line_angle[*it_idx] < hi_angle) {
const Line &l2 = below_lines[*it_idx];
coord_t l2_low = l2.a[mayorit_idx];
coord_t l2_high = l2.b[mayorit_idx];
if (low > high)
std::swap(low, high);
if ((l2_high >= low && l2_low <= high) &&
l.distance_to(l2.a) < paralel_epsilon)
return true;
++it_idx;
if (is_over && it_idx == idx.end()) {
it_idx = idx.begin();
is_over = false;
}
}
return false;
};
// anotate source of peninsula: overhang VS previous layer
for (const ExPolygon &peninsula : peninsulas_shape) {
// need to know shape and edges of peninsula
Lines lines = to_lines(peninsula);
std::vector<bool> is_outline(lines.size());
// when line overlap with belowe lines it is not outline
for (size_t i = 0; i < lines.size(); i++)
is_outline[i] = is_overlap(lines[i]);
part.peninsulas.push_back(Peninsula{peninsula, is_outline});
}
}
} // namespace
#include "libslic3r/Execution/ExecutionSeq.hpp"
@ -546,7 +642,7 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
double sample_distance_in_um2 = sample_distance_in_um * sample_distance_in_um;
// Link parts by intersections
execution::for_each(ex_seq, size_t(1), result.slices.size(),
execution::for_each(ex_tbb, size_t(1), result.slices.size(),
[&result, sample_distance_in_um2, throw_on_cancel](size_t layer_id) {
if ((layer_id % 2) == 0)
// Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
@ -580,6 +676,18 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
it_above->samples = sample_overhangs(*it_above, sample_distance_in_um2);
}
}, 8 /* gransize */);
// Detect peninsula
float min_peninsula_width = scale_(2); // [in scaled mm]
execution::for_each(ex_seq, size_t(1), result.slices.size(),
[&layers = result.layers, &min_peninsula_width, throw_on_cancel](size_t layer_id) {
if ((layer_id % 2) == 0)
// Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
throw_on_cancel();
LayerParts &parts = layers[layer_id].parts;
for (auto it_part = parts.begin(); it_part < parts.end(); ++it_part)
create_peninsulas(*it_part, min_peninsula_width);
}, 8 /* gransize */);
return result;
}

View File

@ -78,6 +78,19 @@ using PartLinks = boost::container::small_vector<PartLink, 4>;
using PartLinks = std::vector<PartLink>;
#endif
// Large one layer overhang that needs to be supported on the overhanging side
struct Peninsula{
// shape of peninsula some of edges are overhang
ExPolygon shape;
// same size as shape lines count
// convert shape to lines by to_lines(shape)
// True .. peninsula outline(coast)
// False .. connection to land(already supported by previous layer)
std::vector<bool> is_outline;
};
using Peninsulas = std::vector<Peninsula>;
// Part on layer is defined by its shape
struct LayerPart {
// Pointer to expolygon stored in input
@ -93,6 +106,9 @@ struct LayerPart {
// Parts from previous printed layer, which is connected to current part
PartLinks prev_parts;
PartLinks next_parts;
// half island is supported as special case
Peninsulas peninsulas;
};
/// <summary>
@ -156,6 +172,17 @@ using ThrowOnCancel = std::function<void(void)>;
// call to say progress of generation into gui in range from 0 to 100
using StatusFunction= std::function<void(int)>;
struct PrepareGeneratorDataConfig
{
// Discretization of overhangs outline,
// smaller will slow down the process but will be more precise
double discretize_overhang_sample_in_mm = 2.; // [in mm]
// Define minimal width of overhang to be considered as peninsula
// (partialy island - sampled not on edge)
coord_t peninsula_width = scale_(2.); // [in scaled mm]
};
/// <summary>
/// Prepare data for generate support points
/// Used for interactive resampling to store permanent data between configuration changes.,