mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-20 23:34:26 +08:00
Add support for peninsulas
This commit is contained in:
parent
fdc9985e50
commit
e9011e100d
@ -6,6 +6,25 @@
|
|||||||
#define OPTION_TO_STORE_ISLAND
|
#define OPTION_TO_STORE_ISLAND
|
||||||
|
|
||||||
namespace Slic3r::sla {
|
namespace Slic3r::sla {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure how to prepare data for SupportPointGenerator
|
||||||
|
/// </summary>
|
||||||
|
struct PrepareSupportConfig
|
||||||
|
{
|
||||||
|
// Size of the steps between discretized samples on the overhanging part of layer
|
||||||
|
// Smaller value means more point to investigate in support process,
|
||||||
|
// but smaller divergence of support distances
|
||||||
|
double discretize_overhang_step = 2.; // [in mm]
|
||||||
|
|
||||||
|
// Detection of peninsula(half island)
|
||||||
|
// Peninsula contain wider one layer overhang than this value
|
||||||
|
float peninsula_min_width = scale_(2); // [in scaled mm]
|
||||||
|
|
||||||
|
// Distance from previous layer part to still supported
|
||||||
|
float peninsula_self_supported_width = scale_(1.5); // [in scaled mm]
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration DTO
|
/// Configuration DTO
|
||||||
/// Define where is neccessary to put support point on island
|
/// Define where is neccessary to put support point on island
|
||||||
@ -83,8 +102,8 @@ struct SampleConfig
|
|||||||
std::string path = ""; // when set to empty string, no debug output is generated
|
std::string path = ""; // when set to empty string, no debug output is generated
|
||||||
#endif // OPTION_TO_STORE_ISLAND
|
#endif // OPTION_TO_STORE_ISLAND
|
||||||
|
|
||||||
// Only for debug it should not be here !!
|
// Configuration for data preparation
|
||||||
double discretize_overhang_sample_in_mm = 2.;
|
PrepareSupportConfig prepare_config;
|
||||||
};
|
};
|
||||||
} // namespace Slic3r::sla
|
} // namespace Slic3r::sla
|
||||||
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_
|
#endif // slic3r_SLA_SuppotstIslands_SampleConfig_hpp_
|
||||||
|
@ -447,7 +447,8 @@ coord_t align_once(
|
|||||||
cell_svg.draw(island_cell_center, "black", config.head_radius);}
|
cell_svg.draw(island_cell_center, "black", config.head_radius);}
|
||||||
#endif //SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH
|
#endif //SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH
|
||||||
// Check that still points do not have bigger distance from each other
|
// Check that still points do not have bigger distance from each other
|
||||||
assert(is_points_in_distance(island_cell_center, island_cell->points, config.max_distance));
|
assert(is_points_in_distance(island_cell_center, island_cell->points,
|
||||||
|
std::max(std::max(config.thick_inner_max_distance, config.thick_outline_max_distance), config.thin_max_distance)));
|
||||||
|
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH
|
||||||
svg.draw(cell_polygon, color_point_cell);
|
svg.draw(cell_polygon, color_point_cell);
|
||||||
@ -874,12 +875,9 @@ struct Field
|
|||||||
// border of field created by source lines and closing of tiny island
|
// border of field created by source lines and closing of tiny island
|
||||||
ExPolygon border;
|
ExPolygon border;
|
||||||
|
|
||||||
// same size as polygon.points.size()
|
// Flag for each line in border whether this line needs to support
|
||||||
// indexes to source island lines
|
// same size as to_points(border).size()
|
||||||
// in case (index > lines.size()) it means fill the gap from tiny part of island
|
std::vector<bool> is_outline;
|
||||||
std::vector<size_t> source_indices;
|
|
||||||
// value for source index of change from wide to tiny part of island
|
|
||||||
size_t source_index_for_change;
|
|
||||||
|
|
||||||
// inner part of field
|
// inner part of field
|
||||||
ExPolygon inner;
|
ExPolygon inner;
|
||||||
@ -900,10 +898,10 @@ void draw(SVG &svg, const Field &field, bool draw_border_line_indexes = false, b
|
|||||||
for (auto &line : border_lines) {
|
for (auto &line : border_lines) {
|
||||||
size_t index = &line - &border_lines.front();
|
size_t index = &line - &border_lines.front();
|
||||||
// start of holes
|
// start of holes
|
||||||
if (index >= field.source_indices.size())
|
if (index >= field.is_outline.size())
|
||||||
break;
|
break;
|
||||||
Point middle_point = LineUtils::middle(line);
|
Point middle_point = LineUtils::middle(line);
|
||||||
std::string text = std::to_string(field.source_indices[index]);
|
std::string text = std::to_string(field.is_outline[index]);
|
||||||
auto item = field.field_2_inner.find(index);
|
auto item = field.field_2_inner.find(index);
|
||||||
if (item != field.field_2_inner.end()) {
|
if (item != field.field_2_inner.end()) {
|
||||||
text += " inner " + std::to_string(item->second);
|
text += " inner " + std::to_string(item->second);
|
||||||
@ -1100,8 +1098,9 @@ Field create_thick_field(const ThickPart& part, const Lines &lines, const Sample
|
|||||||
// Set largest polygon as contour
|
// Set largest polygon as contour
|
||||||
set_biggest_hole_as_contour(field.border, source_indices);
|
set_biggest_hole_as_contour(field.border, source_indices);
|
||||||
}
|
}
|
||||||
field.source_index_for_change = source_index_for_change;
|
field.is_outline.reserve(source_indices.size());
|
||||||
field.source_indices = std::move(source_indices);
|
for (size_t source_index : source_indices)
|
||||||
|
field.is_outline.push_back(source_index != source_index_for_change);
|
||||||
std::tie(field.inner, field.field_2_inner) =
|
std::tie(field.inner, field.field_2_inner) =
|
||||||
outline_offset(field.border, (float)config.minimal_distance_from_outline);
|
outline_offset(field.border, (float)config.minimal_distance_from_outline);
|
||||||
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH
|
#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG_PATH
|
||||||
@ -1245,7 +1244,7 @@ Slic3r::Points sample_expolygon_with_centering(const ExPolygon &expoly, coord_t
|
|||||||
SupportIslandPoints sample_outline(const Field &field, const SampleConfig &config){
|
SupportIslandPoints sample_outline(const Field &field, const SampleConfig &config){
|
||||||
const ExPolygon &border = field.border;
|
const ExPolygon &border = field.border;
|
||||||
const Polygon &contour = border.contour;
|
const Polygon &contour = border.contour;
|
||||||
assert(field.source_indices.size() >= contour.size());
|
assert(field.is_outline.size() >= contour.size());
|
||||||
coord_t max_align_distance = config.max_align_distance;
|
coord_t max_align_distance = config.max_align_distance;
|
||||||
coord_t sample_distance = config.thick_outline_max_distance;
|
coord_t sample_distance = config.thick_outline_max_distance;
|
||||||
SupportIslandPoints result;
|
SupportIslandPoints result;
|
||||||
@ -1330,8 +1329,7 @@ SupportIslandPoints sample_outline(const Field &field, const SampleConfig &confi
|
|||||||
// convert map from field index to inner(line index)
|
// convert map from field index to inner(line index)
|
||||||
auto sample_polygon = [&add_circle_sample, &add_lines_samples, &field]
|
auto sample_polygon = [&add_circle_sample, &add_lines_samples, &field]
|
||||||
(const Polygon &polygon, const Polygon &inner_polygon, size_t index_offset) {
|
(const Polygon &polygon, const Polygon &inner_polygon, size_t index_offset) {
|
||||||
const std::vector<size_t> &source_indices = field.source_indices;
|
const std::vector<bool> &is_outline = field.is_outline;
|
||||||
const size_t& change_index = field.source_index_for_change;
|
|
||||||
const std::map<size_t, size_t> &field_2_inner = field.field_2_inner;
|
const std::map<size_t, size_t> &field_2_inner = field.field_2_inner;
|
||||||
if (inner_polygon.empty())
|
if (inner_polygon.empty())
|
||||||
return; // nothing to sample
|
return; // nothing to sample
|
||||||
@ -1340,9 +1338,8 @@ SupportIslandPoints sample_outline(const Field &field, const SampleConfig &confi
|
|||||||
size_t first_change_index = polygon.size();
|
size_t first_change_index = polygon.size();
|
||||||
for (size_t polygon_index = 0; polygon_index < polygon.size(); ++polygon_index) {
|
for (size_t polygon_index = 0; polygon_index < polygon.size(); ++polygon_index) {
|
||||||
size_t index = polygon_index + index_offset;
|
size_t index = polygon_index + index_offset;
|
||||||
assert(index < source_indices.size());
|
assert(index < is_outline.size());
|
||||||
size_t source_index = source_indices[index];
|
if (!is_outline[index]) {
|
||||||
if (source_index == change_index) {
|
|
||||||
// found change from wide to tiny part
|
// found change from wide to tiny part
|
||||||
first_change_index = polygon_index;
|
first_change_index = polygon_index;
|
||||||
break;
|
break;
|
||||||
@ -1350,9 +1347,10 @@ SupportIslandPoints sample_outline(const Field &field, const SampleConfig &confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// is polygon without change
|
// is polygon without change
|
||||||
if (first_change_index == polygon.size()) {
|
if (first_change_index == polygon.size())
|
||||||
add_circle_sample(inner_polygon);
|
return add_circle_sample(inner_polygon);
|
||||||
} else { // exist change create line sequences
|
|
||||||
|
// exist change create line sequences
|
||||||
// initialize with non valid values
|
// initialize with non valid values
|
||||||
Lines inner_lines = to_lines(inner_polygon);
|
Lines inner_lines = to_lines(inner_polygon);
|
||||||
size_t inner_invalid = inner_lines.size();
|
size_t inner_invalid = inner_lines.size();
|
||||||
@ -1362,13 +1360,21 @@ SupportIslandPoints sample_outline(const Field &field, const SampleConfig &confi
|
|||||||
size_t stop_index = first_change_index;
|
size_t stop_index = first_change_index;
|
||||||
if (stop_index == 0)
|
if (stop_index == 0)
|
||||||
stop_index = polygon.size();
|
stop_index = polygon.size();
|
||||||
for (size_t polygon_index = first_change_index + 1;
|
size_t polygon_index = first_change_index;
|
||||||
polygon_index != stop_index; ++polygon_index) {
|
do { // search for first outline index after change
|
||||||
|
++polygon_index;
|
||||||
|
if (polygon_index == polygon.size()) {
|
||||||
|
polygon_index = 0;
|
||||||
|
// Detect that whole polygon is not peninsula outline(coast)
|
||||||
|
if (first_change_index == 0)
|
||||||
|
return; // Polygon do not contain edge to support.
|
||||||
|
}
|
||||||
|
} while (!is_outline[polygon_index + index_offset]);
|
||||||
|
for (;polygon_index != stop_index; ++polygon_index) {
|
||||||
if (polygon_index == polygon.size()) polygon_index = 0;
|
if (polygon_index == polygon.size()) polygon_index = 0;
|
||||||
size_t index = polygon_index + index_offset;
|
size_t index = polygon_index + index_offset;
|
||||||
assert(index < source_indices.size());
|
assert(index < is_outline.size());
|
||||||
size_t source_index = source_indices[index];
|
if (!is_outline[index]) {
|
||||||
if (source_index == change_index) {
|
|
||||||
if (inner_first == inner_invalid) continue;
|
if (inner_first == inner_invalid) continue;
|
||||||
// create Restriction object
|
// create Restriction object
|
||||||
add_lines_samples(inner_lines, inner_first, inner_last);
|
add_lines_samples(inner_lines, inner_first, inner_last);
|
||||||
@ -1383,8 +1389,8 @@ SupportIslandPoints sample_outline(const Field &field, const SampleConfig &confi
|
|||||||
// initialize first index
|
// initialize first index
|
||||||
if (inner_first == inner_invalid) inner_first = inner_last;
|
if (inner_first == inner_invalid) inner_first = inner_last;
|
||||||
}
|
}
|
||||||
|
if (inner_first != inner_invalid)
|
||||||
add_lines_samples(inner_lines, inner_first, inner_last);
|
add_lines_samples(inner_lines, inner_first, inner_last);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// No inner space to sample
|
// No inner space to sample
|
||||||
@ -2219,7 +2225,6 @@ void draw(SVG &svg, const SupportIslandPoints &supportIslandPoints, coord_t radi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@ -2348,6 +2353,29 @@ SupportIslandPoints uniform_support_island(const ExPolygon &island, const Sample
|
|||||||
return supports;
|
return supports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Follow implementation "create_supports_for_thick_part("
|
||||||
|
SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config){
|
||||||
|
// create_peninsula_field
|
||||||
|
Field field;
|
||||||
|
field.border = peninsula.unsuported_area;
|
||||||
|
field.is_outline = peninsula.is_outline;
|
||||||
|
std::tie(field.inner, field.field_2_inner) =
|
||||||
|
outline_offset(field.border, (float) config.minimal_distance_from_outline);
|
||||||
|
assert(!field.inner.empty());
|
||||||
|
if (field.inner.empty())
|
||||||
|
return {}; // no inner part
|
||||||
|
|
||||||
|
SupportIslandPoints results = sample_outline(field, config);
|
||||||
|
// Inner must survive after sample field for aligning supports(move along outline)
|
||||||
|
auto inner = std::make_shared<ExPolygon>(field.inner);
|
||||||
|
Points inner_points = sample_expolygon_with_centering(*inner, config.thick_inner_max_distance);
|
||||||
|
std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(results),
|
||||||
|
[&inner](const Point &point) { return std::make_unique<SupportIslandInnerPoint>(
|
||||||
|
point, inner, SupportIslandPoint::Type::thick_part_inner);});
|
||||||
|
align_samples(results, peninsula.unsuported_area, config);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_uniform_support_island_visualization_disabled() {
|
bool is_uniform_support_island_visualization_disabled() {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
return false;
|
return false;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <libslic3r/ExPolygon.hpp>
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
#include "SampleConfig.hpp"
|
#include "SampleConfig.hpp"
|
||||||
#include "SupportIslandPoint.hpp"
|
#include "SupportIslandPoint.hpp"
|
||||||
|
#include "libslic3r/SLA/SupportPointGenerator.hpp" // Peninsula
|
||||||
|
|
||||||
namespace Slic3r::sla {
|
namespace Slic3r::sla {
|
||||||
|
|
||||||
@ -15,6 +16,14 @@ namespace Slic3r::sla {
|
|||||||
/// <returns>Support points laying inside of island</returns>
|
/// <returns>Support points laying inside of island</returns>
|
||||||
SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config);
|
SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Distribute support points across peninsula
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="peninsula">half island with anotation of the coast and land outline</param>
|
||||||
|
/// <param name="config">Density distribution parameters</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check for tests that developer do not forget disable visualization after debuging.
|
/// Check for tests that developer do not forget disable visualization after debuging.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -277,7 +277,6 @@ void support_part_overhangs(
|
|||||||
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
||||||
const SupportPointGeneratorConfig &cfg) {
|
const SupportPointGeneratorConfig &cfg) {
|
||||||
SupportIslandPoints samples = uniform_support_island(*part.shape, cfg.island_configuration);
|
SupportIslandPoints samples = uniform_support_island(*part.shape, cfg.island_configuration);
|
||||||
//samples = {std::make_unique<SupportIslandPoint>(island.contour.centroid())};
|
|
||||||
for (const SupportIslandPointPtr &sample : samples)
|
for (const SupportIslandPointPtr &sample : samples)
|
||||||
near_points.add(LayerSupportPoint{
|
near_points.add(LayerSupportPoint{
|
||||||
SupportPoint{
|
SupportPoint{
|
||||||
@ -296,6 +295,30 @@ void support_island(const LayerPart &part, NearPoints& near_points, float part_z
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void support_peninsulas(const Peninsulas& peninsulas, NearPoints& near_points, float part_z,
|
||||||
|
const SupportPointGeneratorConfig &cfg) {
|
||||||
|
for (const Peninsula& peninsula: peninsulas) {
|
||||||
|
SupportIslandPoints peninsula_supports =
|
||||||
|
uniform_support_peninsula(peninsula, cfg.island_configuration);
|
||||||
|
for (const SupportIslandPointPtr &support : peninsula_supports)
|
||||||
|
near_points.add(LayerSupportPoint{
|
||||||
|
SupportPoint{
|
||||||
|
Vec3f{
|
||||||
|
unscale<float>(support->point.x()),
|
||||||
|
unscale<float>(support->point.y()),
|
||||||
|
part_z
|
||||||
|
},
|
||||||
|
/* head_front_radius */ cfg.head_diameter / 2,
|
||||||
|
SupportPointType::island
|
||||||
|
},
|
||||||
|
/* position_on_layer */ support->point,
|
||||||
|
/* direction_to_mass */ Point(0, 0), // direction from bottom
|
||||||
|
/* radius_curve_index */ 0,
|
||||||
|
/* current_radius */ static_cast<coord_t>(scale_(cfg.support_curve.front().x()))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy parts from link to output
|
/// Copy parts from link to output
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -503,19 +526,22 @@ void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part,
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="part">IN/OUT island part containing peninsulas</param>
|
/// <param name="part">IN/OUT island part containing peninsulas</param>
|
||||||
/// <param name="min_peninsula_width">minimal width of overhang to become peninsula</param>
|
/// <param name="min_peninsula_width">minimal width of overhang to become peninsula</param>
|
||||||
void create_peninsulas(LayerPart &part, float min_peninsula_width) {
|
/// <param name="self_supported_width">supported distance from mainland</param>
|
||||||
|
void create_peninsulas(LayerPart &part, const PrepareSupportConfig &config) {
|
||||||
|
assert(config.peninsula_min_width > config.peninsula_self_supported_width);
|
||||||
const Polygons below_polygons = get_polygons(part.prev_parts);
|
const Polygons below_polygons = get_polygons(part.prev_parts);
|
||||||
const Polygons below_expanded = expand(below_polygons, min_peninsula_width, ClipperLib::jtSquare);
|
const Polygons below_expanded = expand(below_polygons, config.peninsula_min_width, ClipperLib::jtSquare);
|
||||||
const ExPolygon &part_shape = *part.shape;
|
const ExPolygon &part_shape = *part.shape;
|
||||||
ExPolygons over_peninsula = diff_ex(part_shape, below_expanded);
|
ExPolygons over_peninsula = diff_ex(part_shape, below_expanded);
|
||||||
if (over_peninsula.empty())
|
if (over_peninsula.empty())
|
||||||
return; // only tiny overhangs
|
return; // only tiny overhangs
|
||||||
|
|
||||||
|
Polygons below_self_supported = expand(below_polygons, config.peninsula_self_supported_width, ClipperLib::jtSquare);
|
||||||
// exist layer part over peninsula limit
|
// exist layer part over peninsula limit
|
||||||
ExPolygons peninsulas_shape = diff_ex(part_shape, below_polygons);
|
ExPolygons peninsulas_shape = diff_ex(part_shape, below_self_supported);
|
||||||
|
|
||||||
// IMPROVE: Anotate source of diff by ClipperLib_Z
|
// IMPROVE: Anotate source of diff by ClipperLib_Z
|
||||||
Lines below_lines = to_lines(below_polygons);
|
Lines below_lines = to_lines(below_self_supported);
|
||||||
auto get_angle = [](const Line &l) {
|
auto get_angle = [](const Line &l) {
|
||||||
Point diff = l.b - l.a;
|
Point diff = l.b - l.a;
|
||||||
if (diff.x() < 0) // Only positive direction X
|
if (diff.x() < 0) // Only positive direction X
|
||||||
@ -532,11 +558,14 @@ void create_peninsulas(LayerPart &part, float min_peninsula_width) {
|
|||||||
return belowe_line_angle[i1] < belowe_line_angle[i2]; };
|
return belowe_line_angle[i1] < belowe_line_angle[i2]; };
|
||||||
std::sort(idx.begin(), idx.end(), is_lower);
|
std::sort(idx.begin(), idx.end(), is_lower);
|
||||||
|
|
||||||
auto is_overlap = [&get_angle, &idx, &is_lower, &below_lines, &belowe_line_angle]
|
// Check, wheather line exist in set of belowe lines
|
||||||
|
// True .. line exist in previous layer (or partialy overlap previous line), connection to land
|
||||||
|
// False .. line is made by border of current layer part(peninsula coast)
|
||||||
|
auto exist_belowe = [&get_angle, &idx, &is_lower, &below_lines, &belowe_line_angle]
|
||||||
(const Line &l) {
|
(const Line &l) {
|
||||||
// allowed angle epsilon
|
// allowed angle epsilon
|
||||||
const double angle_epsilon = 1e-3;
|
const double angle_epsilon = 1e-3; // < 0.06 DEG
|
||||||
const double paralel_epsilon = scale_(1e-2);
|
const double paralel_epsilon = scale_(1e-2); // 10 um
|
||||||
double angle = get_angle(l);
|
double angle = get_angle(l);
|
||||||
double low_angle = angle - angle_epsilon;
|
double low_angle = angle - angle_epsilon;
|
||||||
bool is_over = false;
|
bool is_over = false;
|
||||||
@ -559,24 +588,35 @@ void create_peninsulas(LayerPart &part, float min_peninsula_width) {
|
|||||||
if (low > high)
|
if (low > high)
|
||||||
std::swap(low, high);
|
std::swap(low, high);
|
||||||
|
|
||||||
auto it_idx = std::lower_bound(idx.begin(), idx.end(), low_angle, is_lower);
|
auto is_lower_angle = [&belowe_line_angle](size_t index, double angle) {
|
||||||
if (is_over && it_idx == idx.end()) {
|
return belowe_line_angle[index] < angle; };
|
||||||
|
auto it_idx = std::lower_bound(idx.begin(), idx.end(), low_angle, is_lower_angle);
|
||||||
|
if (it_idx == idx.end()) {
|
||||||
|
if (is_over) {
|
||||||
it_idx = idx.begin();
|
it_idx = idx.begin();
|
||||||
is_over = false;
|
is_over = false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
while (is_over || it_idx != idx.end() || belowe_line_angle[*it_idx] < hi_angle) {
|
}
|
||||||
|
while (is_over || belowe_line_angle[*it_idx] < hi_angle) {
|
||||||
const Line &l2 = below_lines[*it_idx];
|
const Line &l2 = below_lines[*it_idx];
|
||||||
coord_t l2_low = l2.a[mayorit_idx];
|
coord_t l2_low = l2.a[mayorit_idx];
|
||||||
coord_t l2_high = l2.b[mayorit_idx];
|
coord_t l2_high = l2.b[mayorit_idx];
|
||||||
if (low > high)
|
if (low > high)
|
||||||
std::swap(low, high);
|
std::swap(low, high);
|
||||||
if ((l2_high >= low && l2_low <= high) &&
|
if ((l2_high >= low && l2_low <= high) && (
|
||||||
l.distance_to(l2.a) < paralel_epsilon)
|
((l2.a == l.a && l2.b == l.b) ||(l2.a == l.b && l2.b == l.a)) || // speed up - same line
|
||||||
|
l.perp_distance_to(l2.a) < paralel_epsilon)) // check distance of parallel lines
|
||||||
return true;
|
return true;
|
||||||
++it_idx;
|
++it_idx;
|
||||||
if (is_over && it_idx == idx.end()) {
|
if (it_idx == idx.end()){
|
||||||
|
if (is_over) {
|
||||||
it_idx = idx.begin();
|
it_idx = idx.begin();
|
||||||
is_over = false;
|
is_over = false;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -584,23 +624,26 @@ void create_peninsulas(LayerPart &part, float min_peninsula_width) {
|
|||||||
|
|
||||||
// anotate source of peninsula: overhang VS previous layer
|
// anotate source of peninsula: overhang VS previous layer
|
||||||
for (const ExPolygon &peninsula : peninsulas_shape) {
|
for (const ExPolygon &peninsula : peninsulas_shape) {
|
||||||
|
// Check that peninsula is wide enough(min_peninsula_width)
|
||||||
|
if (intersection_ex(ExPolygons{peninsula}, over_peninsula).empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
// need to know shape and edges of peninsula
|
// need to know shape and edges of peninsula
|
||||||
Lines lines = to_lines(peninsula);
|
Lines lines = to_lines(peninsula);
|
||||||
std::vector<bool> is_outline(lines.size());
|
std::vector<bool> is_outline(lines.size());
|
||||||
// when line overlap with belowe lines it is not outline
|
// when line overlap with belowe lines it is not outline
|
||||||
for (size_t i = 0; i < lines.size(); i++)
|
for (size_t i = 0; i < lines.size(); i++)
|
||||||
is_outline[i] = is_overlap(lines[i]);
|
is_outline[i] = !exist_belowe(lines[i]);
|
||||||
part.peninsulas.push_back(Peninsula{peninsula, is_outline});
|
part.peninsulas.push_back(Peninsula{peninsula, is_outline});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
#include "libslic3r/Execution/ExecutionSeq.hpp"
|
||||||
SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
||||||
std::vector<ExPolygons> &&slices,
|
std::vector<ExPolygons> &&slices,
|
||||||
const std::vector<float> &heights,
|
const std::vector<float> &heights,
|
||||||
double discretize_overhang_sample_in_mm,
|
const PrepareSupportConfig &config,
|
||||||
ThrowOnCancel throw_on_cancel,
|
ThrowOnCancel throw_on_cancel,
|
||||||
StatusFunction statusfn
|
StatusFunction statusfn
|
||||||
) {
|
) {
|
||||||
@ -638,7 +681,7 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
|||||||
}
|
}
|
||||||
}, 32 /*gransize*/);
|
}, 32 /*gransize*/);
|
||||||
|
|
||||||
double sample_distance_in_um = scale_(discretize_overhang_sample_in_mm);
|
double sample_distance_in_um = scale_(config.discretize_overhang_step);
|
||||||
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
|
||||||
@ -678,15 +721,17 @@ SupportPointGeneratorData Slic3r::sla::prepare_generator_data(
|
|||||||
}, 8 /* gransize */);
|
}, 8 /* gransize */);
|
||||||
|
|
||||||
// Detect peninsula
|
// Detect peninsula
|
||||||
float min_peninsula_width = scale_(2); // [in scaled mm]
|
execution::for_each(ex_tbb, size_t(1), result.slices.size(),
|
||||||
execution::for_each(ex_seq, size_t(1), result.slices.size(),
|
[&layers = result.layers, &config, throw_on_cancel](size_t layer_id) {
|
||||||
[&layers = result.layers, &min_peninsula_width, throw_on_cancel](size_t layer_id) {
|
if ((layer_id % 16) == 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.
|
||||||
throw_on_cancel();
|
throw_on_cancel();
|
||||||
LayerParts &parts = layers[layer_id].parts;
|
LayerParts &parts = layers[layer_id].parts;
|
||||||
for (auto it_part = parts.begin(); it_part < parts.end(); ++it_part)
|
for (auto it_part = parts.begin(); it_part < parts.end(); ++it_part) {
|
||||||
create_peninsulas(*it_part, min_peninsula_width);
|
if (it_part->prev_parts.empty())
|
||||||
|
continue; // island
|
||||||
|
create_peninsulas(*it_part, config);
|
||||||
|
}
|
||||||
}, 8 /* gransize */);
|
}, 8 /* gransize */);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -766,21 +811,24 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
|||||||
grids.reserve(layer.parts.size());
|
grids.reserve(layer.parts.size());
|
||||||
|
|
||||||
for (const LayerPart &part : layer.parts) {
|
for (const LayerPart &part : layer.parts) {
|
||||||
if (part.prev_parts.empty()) {
|
if (part.prev_parts.empty()) { // Island ?
|
||||||
// only island add new grid
|
// only island add new grid
|
||||||
grids.emplace_back(&result);
|
grids.emplace_back(&result);
|
||||||
// new island - needs support no doubt
|
// new island - needs support no doubt
|
||||||
support_island(part, grids.back(), layer.print_z, config);
|
support_island(part, grids.back(), layer.print_z, config);
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// first layer should have empty prev_part
|
// first layer should have empty prev_part
|
||||||
assert(layer_id != 0);
|
assert(layer_id != 0);
|
||||||
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
||||||
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
||||||
remove_supports_out_of_part(near_points, part, config);
|
remove_supports_out_of_part(near_points, part, config);
|
||||||
|
if (!part.peninsulas.empty())
|
||||||
|
support_peninsulas(part.peninsulas, near_points, layer.print_z, config);
|
||||||
support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius);
|
support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius);
|
||||||
grids.push_back(std::move(near_points));
|
grids.push_back(std::move(near_points));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
prev_grids = std::move(grids);
|
prev_grids = std::move(grids);
|
||||||
|
|
||||||
throw_on_cancel();
|
throw_on_cancel();
|
||||||
|
@ -80,11 +80,15 @@ using PartLinks = std::vector<PartLink>;
|
|||||||
|
|
||||||
// Large one layer overhang that needs to be supported on the overhanging side
|
// Large one layer overhang that needs to be supported on the overhanging side
|
||||||
struct Peninsula{
|
struct Peninsula{
|
||||||
// shape of peninsula some of edges are overhang
|
// shape of peninsula
|
||||||
ExPolygon shape;
|
//ExPolygon shape;
|
||||||
|
|
||||||
// same size as shape lines count
|
// Prev layer is extended by self support const and subtracted from current one.
|
||||||
// convert shape to lines by to_lines(shape)
|
// This part of layer is supported as island
|
||||||
|
ExPolygon unsuported_area;
|
||||||
|
|
||||||
|
// Flag for unsuported_area line about source
|
||||||
|
// Same size as Slic3r::to_lines(unsuported_area)
|
||||||
// True .. peninsula outline(coast)
|
// True .. peninsula outline(coast)
|
||||||
// False .. connection to land(already supported by previous layer)
|
// False .. connection to land(already supported by previous layer)
|
||||||
std::vector<bool> is_outline;
|
std::vector<bool> is_outline;
|
||||||
@ -191,17 +195,16 @@ struct PrepareGeneratorDataConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slices">Countour cut from mesh</param>
|
/// <param name="slices">Countour cut from mesh</param>
|
||||||
/// <param name="heights">Heights of the slices - Same size as slices</param>
|
/// <param name="heights">Heights of the slices - Same size as slices</param>
|
||||||
/// <param name="discretize_overhang_sample_in_mm">Discretization of overhangs outline,
|
/// <param name="config">Preparation parameters</param>
|
||||||
/// smaller will slow down the process but will be more precise</param>
|
|
||||||
/// <param name="throw_on_cancel">Call in meanwhile to check cancel event</param>
|
/// <param name="throw_on_cancel">Call in meanwhile to check cancel event</param>
|
||||||
/// <param name="statusfn">Say progress of generation into gui</param>
|
/// <param name="statusfn">Say progress of generation into gui</param>
|
||||||
/// <returns>Data prepared for generate support points</returns>
|
/// <returns>Data prepared for generate support points</returns>
|
||||||
SupportPointGeneratorData prepare_generator_data(
|
SupportPointGeneratorData prepare_generator_data(
|
||||||
std::vector<ExPolygons> &&slices,
|
std::vector<ExPolygons> &&slices,
|
||||||
const std::vector<float> &heights,
|
const std::vector<float> &heights,
|
||||||
double discretize_overhang_sample_in_mm,
|
const PrepareSupportConfig &config = {},
|
||||||
ThrowOnCancel throw_on_cancel,
|
ThrowOnCancel throw_on_cancel = []() {},
|
||||||
StatusFunction statusfn
|
StatusFunction statusfn = [](int) {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -215,8 +218,8 @@ SupportPointGeneratorData prepare_generator_data(
|
|||||||
LayerSupportPoints generate_support_points(
|
LayerSupportPoints generate_support_points(
|
||||||
const SupportPointGeneratorData &data,
|
const SupportPointGeneratorData &data,
|
||||||
const SupportPointGeneratorConfig &config,
|
const SupportPointGeneratorConfig &config,
|
||||||
ThrowOnCancel throw_on_cancel,
|
ThrowOnCancel throw_on_cancel = []() {},
|
||||||
StatusFunction statusfn
|
StatusFunction statusfn = [](int) {}
|
||||||
);
|
);
|
||||||
} // namespace Slic3r::sla
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
@ -235,7 +238,7 @@ SupportPoints move_on_mesh_surface(
|
|||||||
const LayerSupportPoints &points,
|
const LayerSupportPoints &points,
|
||||||
const AABBMesh &mesh,
|
const AABBMesh &mesh,
|
||||||
double allowed_move,
|
double allowed_move,
|
||||||
ThrowOnCancel throw_on_cancel
|
ThrowOnCancel throw_on_cancel = []() {}
|
||||||
);
|
);
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
@ -610,6 +610,7 @@ static void filter_support_points_by_modifiers(sla::SupportPoints &pts,
|
|||||||
// support points. Then we sprinkle the rest of the mesh.
|
// support points. Then we sprinkle the rest of the mesh.
|
||||||
void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||||
{
|
{
|
||||||
|
using namespace sla;
|
||||||
// If supports are disabled, we can skip the model scan.
|
// If supports are disabled, we can skip the model scan.
|
||||||
if(!po.m_config.supports_enable.getBool()) return;
|
if(!po.m_config.supports_enable.getBool()) return;
|
||||||
|
|
||||||
@ -628,7 +629,7 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
|||||||
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
||||||
<< mo.sla_support_points.size();
|
<< mo.sla_support_points.size();
|
||||||
|
|
||||||
if (mo.sla_points_status == sla::PointsStatus::UserModified) {
|
if (mo.sla_points_status == PointsStatus::UserModified) {
|
||||||
// There are either some points on the front-end, or the user
|
// There are either some points on the front-end, or the user
|
||||||
// removed them on purpose. No calculation will be done.
|
// removed them on purpose. No calculation will be done.
|
||||||
po.m_supportdata->input.pts = po.transformed_support_points();
|
po.m_supportdata->input.pts = po.transformed_support_points();
|
||||||
@ -637,27 +638,27 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
|||||||
// Unless the user modified the points or we already did the calculation,
|
// Unless the user modified the points or we already did the calculation,
|
||||||
// we will do the autoplacement. Otherwise we will just blindly copy the
|
// we will do the autoplacement. Otherwise we will just blindly copy the
|
||||||
// frontend data into the backend cache.
|
// frontend data into the backend cache.
|
||||||
// if (mo.sla_points_status != sla::PointsStatus::UserModified)
|
// if (mo.sla_points_status != PointsStatus::UserModified)
|
||||||
|
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
const SLAPrintObjectConfig& cfg = po.config();
|
const SLAPrintObjectConfig& cfg = po.config();
|
||||||
|
|
||||||
// the density config value is in percents:
|
// the density config value is in percents:
|
||||||
sla::SupportPointGeneratorConfig config;
|
SupportPointGeneratorConfig config;
|
||||||
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
||||||
|
|
||||||
switch (cfg.support_tree_type) {
|
switch (cfg.support_tree_type) {
|
||||||
case sla::SupportTreeType::Default:
|
case SupportTreeType::Default:
|
||||||
case sla::SupportTreeType::Organic:
|
case SupportTreeType::Organic:
|
||||||
config.head_diameter = float(cfg.support_head_front_diameter);
|
config.head_diameter = float(cfg.support_head_front_diameter);
|
||||||
break;
|
break;
|
||||||
case sla::SupportTreeType::Branching:
|
case SupportTreeType::Branching:
|
||||||
config.head_diameter = float(cfg.branchingsupport_head_front_diameter);
|
config.head_diameter = float(cfg.branchingsupport_head_front_diameter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy current configuration for sampling islands
|
// copy current configuration for sampling islands
|
||||||
config.island_configuration = sla::SampleConfigFactory::get_sample_config(); // copy
|
config.island_configuration = SampleConfigFactory::get_sample_config(); // copy
|
||||||
|
|
||||||
// scaling for the sub operations
|
// scaling for the sub operations
|
||||||
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
|
double d = objectstep_scale * OBJ_STEP_LEVELS[slaposSupportPoints] / 100.0;
|
||||||
@ -678,14 +679,15 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
|||||||
|
|
||||||
std::vector<ExPolygons> slices = po.get_model_slices(); // copy
|
std::vector<ExPolygons> slices = po.get_model_slices(); // copy
|
||||||
const std::vector<float>& heights = po.m_model_height_levels;
|
const std::vector<float>& heights = po.m_model_height_levels;
|
||||||
sla::ThrowOnCancel cancel = [this]() { throw_if_canceled(); };
|
ThrowOnCancel cancel = [this]() { throw_if_canceled(); };
|
||||||
sla::StatusFunction status = statuscb;
|
StatusFunction status = statuscb;
|
||||||
double discretize = config.island_configuration.discretize_overhang_sample_in_mm;
|
|
||||||
sla::SupportPointGeneratorData data =
|
|
||||||
sla::prepare_generator_data(std::move(slices), heights, discretize, cancel, status);
|
|
||||||
|
|
||||||
sla::LayerSupportPoints layer_support_points =
|
const PrepareSupportConfig &prepare_cfg = config.island_configuration.prepare_config;
|
||||||
sla::generate_support_points(data, config, cancel, status);
|
SupportPointGeneratorData data =
|
||||||
|
prepare_generator_data(std::move(slices), heights, prepare_cfg, cancel, status);
|
||||||
|
|
||||||
|
LayerSupportPoints layer_support_points =
|
||||||
|
generate_support_points(data, config, cancel, status);
|
||||||
|
|
||||||
const AABBMesh& emesh = po.m_supportdata->input.emesh;
|
const AABBMesh& emesh = po.m_supportdata->input.emesh;
|
||||||
// Maximal move of support point to mesh surface,
|
// Maximal move of support point to mesh surface,
|
||||||
@ -693,8 +695,8 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
|||||||
assert(po.m_model_height_levels.size() > 1);
|
assert(po.m_model_height_levels.size() > 1);
|
||||||
double allowed_move = (po.m_model_height_levels[1] - po.m_model_height_levels[0]) +
|
double allowed_move = (po.m_model_height_levels[1] - po.m_model_height_levels[0]) +
|
||||||
std::numeric_limits<float>::epsilon();
|
std::numeric_limits<float>::epsilon();
|
||||||
sla::SupportPoints support_points =
|
SupportPoints support_points =
|
||||||
sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel);
|
move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel);
|
||||||
|
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
|
|
||||||
|
@ -687,9 +687,9 @@ RENDER_AGAIN:
|
|||||||
}
|
}
|
||||||
|
|
||||||
sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config();
|
sla::SampleConfig &sample_config = sla::SampleConfigFactory::get_sample_config();
|
||||||
if (float overhang_sample_distance = sample_config.discretize_overhang_sample_in_mm;
|
if (float overhang_sample_distance = sample_config.prepare_config.discretize_overhang_step;
|
||||||
m_imgui->slider_float("overhang discretization", &overhang_sample_distance, 2e-5f, 10.f, "%.2f mm")){
|
m_imgui->slider_float("overhang discretization", &overhang_sample_distance, 2e-5f, 10.f, "%.2f mm")){
|
||||||
sample_config.discretize_overhang_sample_in_mm = overhang_sample_distance;
|
sample_config.prepare_config.discretize_overhang_step = overhang_sample_distance;
|
||||||
} else if (ImGui::IsItemHovered())
|
} else if (ImGui::IsItemHovered())
|
||||||
ImGui::SetTooltip("Smaller will slow down. Step for discretization overhang outline for test of support need");
|
ImGui::SetTooltip("Smaller will slow down. Step for discretization overhang outline for test of support need");
|
||||||
|
|
||||||
|
@ -129,14 +129,11 @@ void test_supports(const std::string &obj_filename,
|
|||||||
|
|
||||||
// Create the support point generator
|
// Create the support point generator
|
||||||
sla::SupportPointGeneratorConfig autogencfg;
|
sla::SupportPointGeneratorConfig autogencfg;
|
||||||
autogencfg.head_diameter = 2 * supportcfg.head_front_radius_mm;
|
sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(out.model_slices), out.slicegrid);
|
||||||
sla::ThrowOnCancel cancel = []() {};
|
sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, autogencfg);
|
||||||
sla::StatusFunction status = [](int) {};
|
|
||||||
sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(out.model_slices), out.slicegrid, 2., cancel, status);
|
|
||||||
sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, autogencfg, cancel, status);
|
|
||||||
double allowed_move = (out.slicegrid[1] - out.slicegrid[0]) + std::numeric_limits<float>::epsilon();
|
double allowed_move = (out.slicegrid[1] - out.slicegrid[0]) + std::numeric_limits<float>::epsilon();
|
||||||
// Get the calculated support points.
|
// Get the calculated support points.
|
||||||
sm.pts = sla::move_on_mesh_surface(layer_support_points, sm.emesh, allowed_move, cancel);
|
sm.pts = sla::move_on_mesh_surface(layer_support_points, sm.emesh, allowed_move);
|
||||||
out.model_slices = std::move(gen_data.slices); // return ownership
|
out.model_slices = std::move(gen_data.slices); // return ownership
|
||||||
|
|
||||||
int validityflags = ASSUME_NO_REPAIR;
|
int validityflags = ASSUME_NO_REPAIR;
|
||||||
@ -474,14 +471,11 @@ sla::SupportPoints calc_support_pts(
|
|||||||
std::vector<ExPolygons> slices = slice_mesh_ex(mesh.its, heights, CLOSING_RADIUS);
|
std::vector<ExPolygons> slices = slice_mesh_ex(mesh.its, heights, CLOSING_RADIUS);
|
||||||
|
|
||||||
// Prepare the support point calculator
|
// Prepare the support point calculator
|
||||||
|
sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(slices), heights);
|
||||||
sla::ThrowOnCancel cancel = []() {};
|
sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, cfg);
|
||||||
sla::StatusFunction status = [](int) {};
|
|
||||||
sla::SupportPointGeneratorData gen_data = sla::prepare_generator_data(std::move(slices), heights, 2., cancel, status);
|
|
||||||
sla::LayerSupportPoints layer_support_points = sla::generate_support_points(gen_data, cfg, cancel, status);
|
|
||||||
|
|
||||||
AABBMesh emesh{mesh};
|
AABBMesh emesh{mesh};
|
||||||
double allowed_move = (heights[1] - heights[0]) + std::numeric_limits<float>::epsilon();
|
double allowed_move = (heights[1] - heights[0]) + std::numeric_limits<float>::epsilon();
|
||||||
// Get the calculated support points.
|
// Get the calculated support points.
|
||||||
return sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move, cancel);
|
return sla::move_on_mesh_surface(layer_support_points, emesh, allowed_move);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user