mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-21 11:34:27 +08:00
Add detection and creation of peninsula
with anotation of outline.
This commit is contained in:
parent
08ee5524d5
commit
fdc9985e50
@ -498,6 +498,102 @@ void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part,
|
|||||||
near_points.remove_out_of(extend_shape);
|
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
|
} // namespace
|
||||||
|
|
||||||
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
#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;
|
double sample_distance_in_um2 = sample_distance_in_um * sample_distance_in_um;
|
||||||
|
|
||||||
// Link parts by intersections
|
// 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) {
|
[&result, sample_distance_in_um2, throw_on_cancel](size_t layer_id) {
|
||||||
if ((layer_id % 2) == 0)
|
if ((layer_id % 2) == 0)
|
||||||
// Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
|
// 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);
|
it_above->samples = sample_overhangs(*it_above, sample_distance_in_um2);
|
||||||
}
|
}
|
||||||
}, 8 /* gransize */);
|
}, 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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,19 @@ using PartLinks = boost::container::small_vector<PartLink, 4>;
|
|||||||
using PartLinks = std::vector<PartLink>;
|
using PartLinks = std::vector<PartLink>;
|
||||||
#endif
|
#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
|
// Part on layer is defined by its shape
|
||||||
struct LayerPart {
|
struct LayerPart {
|
||||||
// Pointer to expolygon stored in input
|
// Pointer to expolygon stored in input
|
||||||
@ -93,6 +106,9 @@ struct LayerPart {
|
|||||||
// Parts from previous printed layer, which is connected to current part
|
// Parts from previous printed layer, which is connected to current part
|
||||||
PartLinks prev_parts;
|
PartLinks prev_parts;
|
||||||
PartLinks next_parts;
|
PartLinks next_parts;
|
||||||
|
|
||||||
|
// half island is supported as special case
|
||||||
|
Peninsulas peninsulas;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <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
|
// call to say progress of generation into gui in range from 0 to 100
|
||||||
using StatusFunction= std::function<void(int)>;
|
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>
|
/// <summary>
|
||||||
/// Prepare data for generate support points
|
/// Prepare data for generate support points
|
||||||
/// Used for interactive resampling to store permanent data between configuration changes.,
|
/// Used for interactive resampling to store permanent data between configuration changes.,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user