update libslic3r

This commit is contained in:
QIDI TECH
2025-05-05 19:52:57 +08:00
parent eae8e18c3a
commit 126534997a
180 changed files with 24833 additions and 5679 deletions

View File

@@ -145,10 +145,10 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
if (support_params.num_top_base_interface_layers > 0)
// Some top base interface layers will be generated.
top_inteface_z = support_params.num_top_interface_layers_only() == 0 ?
// Only base interface layers to generate.
// Only base interface layers to generate.
- std::numeric_limits<coordf_t>::max() :
intermediate_layers[std::min(num_intermediate - 1, idx_intermediate_layer + int(support_params.num_top_interface_layers_only()) - 1)]->print_z;
// Move idx_top_contact_first up until above the current print_z.
// Move idx_top_contact_first up until above the current print_z.
idx_top_contact_first = idx_higher_or_equal(top_contacts, idx_top_contact_first, [&intermediate_layer](const SupportGeneratorLayer *layer){ return layer->print_z >= intermediate_layer.print_z; }); // - EPSILON
// Collect the top contact areas above this intermediate layer, below top_z.
for (int idx_top_contact = idx_top_contact_first; idx_top_contact < int(top_contacts.size()); ++ idx_top_contact) {
@@ -208,6 +208,17 @@ std::pair<SupportGeneratorLayersPtr, SupportGeneratorLayersPtr> generate_interfa
}
});
tbb::parallel_for(tbb::blocked_range<int>(1, int(base_interface_layers.size())), [&base_interface_layers](const tbb::blocked_range<int> &range) {
for (int layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
auto &base_interface_layer = base_interface_layers[layer_id];
if (!base_interface_layer) return;
auto &lower_layer = base_interface_layers[layer_id - 1];
if (!lower_layer) return;
if (base_interface_layer->polygons == lower_layer->polygons) base_interface_layer->up = true;
}
});
// Compress contact_out, remove the nullptr items.
// The parallel_for above may not have merged all the interface and base_interface layers
// generated by the Organic supports code, do it here.
@@ -1424,6 +1435,11 @@ void generate_support_toolpaths(
if (config.support_base_pattern == smpRectilinearGrid)
angles.push_back(support_params.interface_angle);
std::vector<float> interface_angles;
if (config.support_interface_pattern == smipRectilinearInterlaced)
interface_angles.push_back(support_params.base_angle);
interface_angles.push_back(support_params.interface_angle);
BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.)));
// const coordf_t link_max_length_factor = 3.;
@@ -1542,7 +1558,7 @@ void generate_support_toolpaths(
tbb::parallel_for(tbb::blocked_range<size_t>(n_raft_layers, support_layers.size()),
[&config, &slicing_params, &support_params, &support_layers, &bottom_contacts, &top_contacts, &intermediate_layers, &interface_layers, &base_interface_layers, &layer_caches, &loop_interface_processor,
&bbox_object, &angles, n_raft_layers, link_max_length_factor]
&bbox_object, &angles, &interface_angles, n_raft_layers, link_max_length_factor]
(const tbb::blocked_range<size_t>& range) {
// Indices of the 1st layer in their respective container at the support layer height.
size_t idx_layer_bottom_contact = size_t(-1);
@@ -1577,8 +1593,6 @@ void generate_support_toolpaths(
{
SupportLayer &support_layer = *support_layers[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id];
const float support_interface_angle = (support_params.support_style == smsGrid || config.support_interface_pattern == smipRectilinear) ?
support_params.interface_angle : support_params.raft_interface_angle(support_layer.interface_id());
// Find polygons with the same print_z.
SupportGeneratorLayerExtruded &bottom_contact_layer = layer_cache.bottom_contact_layer;
@@ -1662,13 +1676,10 @@ void generate_support_toolpaths(
(raft_contact ? &support_params.raft_interface_flow :
interface_as_base ? &support_params.support_material_flow : &support_params.support_material_interface_flow)
->with_height(float(layer_ex.layer->height));
filler->angle = interface_as_base ?
// If zero interface layers are configured, use the same angle as for the base layers.
angles[support_layer_id % angles.size()] :
// Use interface angle for the interface layers.
raft_contact ?
support_params.raft_interface_angle(support_layer.interface_id()) :
support_interface_angle;
// If zero interface layers are configured, use the same angle as for the base layers.
filler->angle = interface_as_base ? angles[support_layer_id % angles.size()] :
raft_contact ? support_params.raft_interface_angle(support_layer.interface_id()) :
interface_angles[support_layer_id % interface_angles.size()]; // Use interface angle for the interface layers.
double density = raft_contact ? support_params.raft_interface_density : interface_as_base ? support_params.support_density : support_params.interface_density;
filler->spacing = raft_contact ? support_params.raft_interface_flow.spacing() :
interface_as_base ? support_params.support_material_flow.spacing() : support_params.support_material_interface_flow.spacing();
@@ -1697,7 +1708,8 @@ void generate_support_toolpaths(
// the bridging flow does not quite apply. Reduce the flow to area of an ellipse? (A = pi * a * b)
assert(! base_interface_layer.layer->bridging);
Flow interface_flow = support_params.support_material_flow.with_height(float(base_interface_layer.layer->height));
filler->angle = support_interface_angle;
filler->angle = base_interface_layer.layer->up ? interface_angles[(support_layer_id + 1) % interface_angles.size()] + M_PI_2 :
(angles[(support_layer_id - 1) % angles.size()] + M_PI_2);
filler->spacing = support_params.support_material_interface_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_params.interface_density));
fill_expolygons_generate_paths(
@@ -1709,7 +1721,7 @@ void generate_support_toolpaths(
// Filler and its parameters
filler, float(support_params.interface_density),
// Extrusion parameters
ExtrusionRole::erSupportMaterial, interface_flow);
ExtrusionRole::erSupportTransition, interface_flow);
}
// Base support or flange.
@@ -1948,5 +1960,123 @@ sub clip_with_shape {
}
}
*/
/*!
* \brief Unions two Polygons. Ensures that if the input is non empty that the output also will be non empty.
* \param first[in] The first Polygon.
* \param second[in] The second Polygon.
* \return The union of both Polygons
*/
[[nodiscard]] Polygons safe_union(const Polygons first, const Polygons second)
{
// unionPolygons can slowly remove Polygons under certain circumstances, because of rounding issues (Polygons that have a thin area).
// This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly
// workaround is needed Here is an example of a Polygons object that will loose vertices when unioning, and will be gone after a few times unionPolygons was called:
/*
Polygons example;
Polygon exampleInner;
exampleInner.add(Point(120410,83599));//A
exampleInner.add(Point(120384,83643));//B
exampleInner.add(Point(120399,83618));//C
exampleInner.add(Point(120414,83591));//D
exampleInner.add(Point(120423,83570));//E
exampleInner.add(Point(120419,83580));//F
example.add(exampleInner);
for(int i=0;i<10;i++){
log("Iteration %d Example area: %f\n",i,area(example));
example=example.unionPolygons();
}
*/
Polygons result;
if (!first.empty() || !second.empty()) {
result = union_(first, second);
if (result.empty()) {
BOOST_LOG_TRIVIAL(debug) << "Caught an area destroying union, enlarging areas a bit.";
// just take the few lines we have, and offset them a tiny bit. Needs to be offsetPolylines, as offset may aleady have problems with the area.
result = union_(offset(to_polylines(first), scaled<float>(0.002), jtMiter, 1.2), offset(to_polylines(second), scaled<float>(0.002), jtMiter, 1.2));
}
}
return result;
}
[[nodiscard]] ExPolygons safe_union(const ExPolygons first, const ExPolygons second)
{
ExPolygons result;
if (!first.empty() || !second.empty()) {
result = union_ex(first, second);
if (result.empty()) {
BOOST_LOG_TRIVIAL(debug) << "Caught an area destroying union, enlarging areas a bit.";
// just take the few lines we have, and offset them a tiny bit. Needs to be offsetPolylines, as offset may aleady have problems with the area.
Polygons result_polys = union_(offset(to_polylines(first), scaled<float>(0.002), jtMiter, 1.2), offset(to_polylines(second), scaled<float>(0.002), jtMiter, 1.2));
for (auto &poly : result_polys) result.emplace_back(ExPolygon(poly));
}
}
return result;
}
/*!
* \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle.
* \param me[in] Polygons object that has to be offset.
* \param distance[in] The distance by which me should be offset. Expects values >=0.
* \param collision[in] The area representing obstacles.
* \param last_step_offset_without_check[in] The most it is allowed to offset in one step.
* \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get
* very small. Required as arcTolerance is not exposed in offset, which should result with a similar result. \return The resulting Polygons object.
*/
[[nodiscard]] Polygons safe_offset_inc(
const Polygons &me, coord_t distance, const Polygons &collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset)
{
bool do_final_difference = last_step_offset_without_check == 0;
Polygons ret = safe_union(me); // ensure sane input
// Trim the collision polygons with the region of interest for diff() efficiency.
Polygons collision_trimmed_buffer;
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons &{
if (collision_trimmed_buffer.empty() && !collision.empty())
collision_trimmed_buffer = ClipperUtils::clip_clipper_polygons_with_subject_bbox(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON));
return collision_trimmed_buffer;
};
if (distance == 0) return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret);
if (safe_step_size < 0 || last_step_offset_without_check < 0) {
BOOST_LOG_TRIVIAL(error) << "Offset increase got invalid parameter!";
return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret);
}
coord_t step_size = safe_step_size;
int steps = distance > last_step_offset_without_check ? (distance - last_step_offset_without_check) / step_size : 0;
if (distance - steps * step_size > last_step_offset_without_check) {
if ((steps + 1) * step_size <= distance)
// This will be the case when last_step_offset_without_check >= safe_step_size
++steps;
else
do_final_difference = true;
}
if (steps + (distance < last_step_offset_without_check || (distance % step_size) != 0) < int(min_amount_offset) && min_amount_offset > 1) {
// yes one can add a bool as the standard specifies that a result from compare operators has to be 0 or 1
// reduce the stepsize to ensure it is offset the required amount of times
step_size = distance / min_amount_offset;
if (step_size >= safe_step_size) {
// effectivly reduce last_step_offset_without_check
step_size = safe_step_size;
steps = min_amount_offset;
} else
steps = distance / step_size;
}
// offset in steps
for (int i = 0; i < steps; ++i) {
ret = diff(offset(ret, step_size, ClipperLib::jtRound, scaled<float>(0.01)), collision_trimmed());
// ensure that if many offsets are done the performance does not suffer extremely by the new vertices of jtRound.
if (i % 10 == 7) ret = polygons_simplify(ret, scaled<double>(0.015));
}
// offset the remainder
float last_offset = distance - steps * step_size;
if (last_offset > SCALED_EPSILON) ret = offset(ret, distance - steps * step_size, ClipperLib::jtRound, scaled<float>(0.01));
ret = polygons_simplify(ret, scaled<double>(0.015));
if (do_final_difference) ret = diff(ret, collision_trimmed());
return union_(ret);
}
} // namespace Slic3r

View File

@@ -148,6 +148,80 @@ int idx_lower_or_equal(const std::vector<T*> &vec, int idx, FN_LOWER_EQUAL fn_lo
return idx_lower_or_equal(vec.begin(), vec.end(), idx, fn_lower_equal);
}
[[nodiscard]] Polygons safe_union(const Polygons first, const Polygons second = {});
[[nodiscard]] ExPolygons safe_union(const ExPolygons first, const ExPolygons second = {});
[[nodiscard]] Polygons safe_offset_inc(
const Polygons &me, coord_t distance, const Polygons &collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset);
/*!
* \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle.
* \param me[in] Polygons object that has to be offset.
* \param distance[in] The distance by which me should be offset. Expects values >=0.
* \param CollisionPolyType collision[in] The area representing obstacles. CollisionPolyType may be ExPolygons or Polygons.
* \param last_step_offset_without_check[in] The most it is allowed to offset in one step.
* \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get
* very small. Required as arcTolerance is not exposed in offset, which should result with a similar result. \return The resulting Polygons object.
*/
template<typename CollisionPolyType>
[[nodiscard]] ExPolygons safe_offset_inc(
const ExPolygons &me, coord_t distance, const CollisionPolyType &collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset)
{
bool do_final_difference = last_step_offset_without_check == 0;
ExPolygons ret = safe_union(me); // ensure sane input
// Trim the collision polygons with the region of interest for diff() efficiency.
Polygons collision_trimmed_buffer;
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons &{
if (collision_trimmed_buffer.empty() && !collision.empty())
collision_trimmed_buffer = ClipperUtils::clip_clipper_polygons_with_subject_bbox(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON));
return collision_trimmed_buffer;
};
if (distance == 0) return do_final_difference ? diff_ex(ret, collision_trimmed()) : union_ex(ret);
if (safe_step_size < 0 || last_step_offset_without_check < 0) {
BOOST_LOG_TRIVIAL(error) << "Offset increase got invalid parameter!";
return do_final_difference ? diff_ex(ret, collision_trimmed()) : union_ex(ret);
}
coord_t step_size = safe_step_size;
int steps = distance > last_step_offset_without_check ? (distance - last_step_offset_without_check) / step_size : 0;
if (distance - steps * step_size > last_step_offset_without_check) {
if ((steps + 1) * step_size <= distance)
// This will be the case when last_step_offset_without_check >= safe_step_size
++steps;
else
do_final_difference = true;
}
if (steps + (distance < last_step_offset_without_check || (distance % step_size) != 0) < int(min_amount_offset) && min_amount_offset > 1) {
// yes one can add a bool as the standard specifies that a result from compare operators has to be 0 or 1
// reduce the stepsize to ensure it is offset the required amount of times
step_size = distance / min_amount_offset;
if (step_size >= safe_step_size) {
// effectivly reduce last_step_offset_without_check
step_size = safe_step_size;
steps = min_amount_offset;
} else
steps = distance / step_size;
}
// offset in steps
for (int i = 0; i < steps; ++i) {
ret = diff_ex(offset_ex(ret, step_size, ClipperLib::jtRound, scaled<float>(0.01)), collision_trimmed());
// ensure that if many offsets are done the performance does not suffer extremely by the new vertices of jtRound.
if (i % 10 == 7) ret = expolygons_simplify(ret, scaled<double>(0.015));
}
// offset the remainder
float last_offset = distance - steps * step_size;
if (last_offset > SCALED_EPSILON) ret = offset_ex(ret, distance - steps * step_size, ClipperLib::jtRound, scaled<float>(0.01));
ret = expolygons_simplify(ret, scaled<double>(0.015));
if (do_final_difference) ret = diff_ex(ret, collision_trimmed());
return union_ex(ret);
}
} // namespace Slic3r
#endif /* slic3r_SupportCommon_hpp_ */

View File

@@ -110,6 +110,8 @@ namespace Slic3r {
size_t idx_object_layer_below{ size_t(-1) };
// Use a bridging flow when printing this support layer.
bool bridging{ false };
//order of the transition layers
bool up{false};
// Polygons to be filled by the support pattern.
Polygons polygons;

View File

@@ -29,13 +29,13 @@ struct SupportParameters {
{
this->num_top_interface_layers = std::max(0, object_config.support_interface_top_layers.value);
this->num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
this->num_bottom_interface_layers = object_config.support_interface_bottom_layers < 0 ?
num_top_interface_layers : object_config.support_interface_bottom_layers;
this->has_top_contacts = num_top_interface_layers > 0;
this->has_bottom_contacts = num_bottom_interface_layers > 0;
if (this->soluble_interface_non_soluble_base) {
// Try to support soluble dense interfaces with non-soluble dense interfaces.
this->num_top_base_interface_layers = size_t(std::min(int(num_top_interface_layers) / 2, 2));
this->num_top_base_interface_layers = num_top_interface_layers > 0 ? 2 : 0;
this->num_bottom_base_interface_layers = size_t(std::min(int(num_bottom_interface_layers) / 2, 2));
} else {
// QDS: if support interface and support base do not use the same filament, add a base layer to improve their adhesion
@@ -43,7 +43,7 @@ struct SupportParameters {
// support_filament==0
bool differnt_support_interface_filament = object_config.support_interface_filament != 0 &&
object_config.support_interface_filament != object_config.support_filament;
this->num_top_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
this->num_top_base_interface_layers = differnt_support_interface_filament && num_top_interface_layers > 0 ? 2 : 0;
this->num_bottom_base_interface_layers = differnt_support_interface_filament ? 1 : 0;
}
}
@@ -107,21 +107,49 @@ struct SupportParameters {
this->interface_density = this->support_density;
}
SupportMaterialPattern support_pattern = object_config.support_base_pattern;
support_style = object_config.support_style;
if (support_style != smsDefault) {
if ((support_style == smsSnug || support_style == smsGrid) && is_tree(object_config.support_type)) support_style = smsDefault;
if ((support_style == smsTreeSlim || support_style == smsTreeStrong || support_style == smsTreeHybrid || support_style == smsTreeOrganic) &&
!is_tree(object_config.support_type))
support_style = smsDefault;
}
if (support_style == smsDefault) {
if (is_tree(object_config.support_type)) {
// organic support doesn't work with variable layer heights (including adaptive layer height and height range modifier, see #4313)
if (!object.has_variable_layer_heights && !slicing_params.soluble_interface) {
BOOST_LOG_TRIVIAL(warning) << "tree support default to organic support";
support_style = smsTreeOrganic;
} else {
BOOST_LOG_TRIVIAL(warning) << "tree support default to hybrid tree due to adaptive layer height";
support_style = smsTreeHybrid;
}
} else {
support_style = smsGrid;
}
}
support_base_pattern = object_config.support_base_pattern;
if (support_base_pattern == smpDefault) {
if (is_tree(object_config.support_type))
support_base_pattern = support_style == smsTreeHybrid ? smpRectilinear : smpNone;
else
support_base_pattern = smpRectilinear;
}
this->with_sheath = object_config.tree_support_wall_count > 0;
this->base_fill_pattern =
support_pattern == smpHoneycomb ? ipHoneycomb :
this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase;
this->base_fill_pattern = support_base_pattern == smpLightning ? ipLightning :
support_base_pattern == smpHoneycomb ? ipHoneycomb :
this->support_density > 0.95 || this->with_sheath ? ipRectilinear :
ipSupportBase;
this->interface_fill_pattern = (this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
this->raft_interface_fill_pattern = this->raft_interface_density > 0.95 ? ipRectilinear : ipSupportBase;
if (object_config.support_interface_pattern == smipGrid)
this->contact_fill_pattern = ipGrid;
else if (object_config.support_interface_pattern == smipRectilinearInterlaced)
else if (object_config.support_interface_pattern == smipRectilinearInterlaced || object_config.support_interface_pattern == smipAuto)
this->contact_fill_pattern = ipRectilinear;
else
this->contact_fill_pattern =
(object_config.support_interface_pattern == smipAuto && slicing_params.soluble_interface) ||
object_config.support_interface_pattern == smipConcentric ?
this->contact_fill_pattern = object_config.support_interface_pattern == smipConcentric ?
ipConcentric :
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
@@ -163,34 +191,27 @@ struct SupportParameters {
support_extrusion_width = Flow::auto_extrusion_width(FlowRole::frSupportMaterial, (float) nozzle_diameter);
}
independent_layer_height = print_config.independent_support_layer_height;
// force double walls everywhere if wall count is larger than 1
tree_branch_diameter_double_wall_area_scaled = object_config.tree_support_wall_count.value > 1 ? 0.1 :
object_config.tree_support_wall_count.value == 0 ? 0.25 * sqr(scaled<double>(5.0)) * M_PI :
std::numeric_limits<double>::max();
support_style = object_config.support_style;
if (support_style != smsDefault) {
if ((support_style == smsSnug || support_style == smsGrid) && is_tree(object_config.support_type)) support_style = smsDefault;
if ((support_style == smsTreeSlim || support_style == smsTreeStrong || support_style == smsTreeHybrid || support_style == smsTreeOrganic) &&
!is_tree(object_config.support_type))
support_style = smsDefault;
}
if (support_style == smsDefault) {
if (is_tree(object_config.support_type)) {
// organic support doesn't work with variable layer heights (including adaptive layer height and height range modifier, see #4313)
if (!object.has_variable_layer_heights) {
BOOST_LOG_TRIVIAL(warning) << "tree support default to organic support";
support_style = smsTreeOrganic;
} else {
BOOST_LOG_TRIVIAL(warning) << "tree support default to hybrid tree due to adaptive layer height";
support_style = smsTreeHybrid;
}
} else {
support_style = smsGrid;
double tree_support_branch_diameter_double_wall = 3.0;
// get support filament strength and decide the thresh of double wall area
float support_filament_strength = print_config.impact_strength_z.get_at(object_config.support_filament-1);
if(object_config.support_filament==0){
// find the weakest filament
support_filament_strength = std::numeric_limits<float>::max();
for(auto extruder:object.object_extruders()){
float strength = print_config.impact_strength_z.get_at(extruder);
if(strength<support_filament_strength) support_filament_strength = strength;
}
}
if(object_config.tree_support_wall_count.value==0){
tree_support_branch_diameter_double_wall = support_filament_strength;
this->tree_branch_diameter_double_wall_area_scaled = 0.25*sqr(scaled<double>(tree_support_branch_diameter_double_wall))*M_PI;
}else{
// force double walls everywhere if wall count is larger than 1
this->tree_branch_diameter_double_wall_area_scaled = object_config.tree_support_wall_count.value>1? 0.1: std::numeric_limits<double>::max();
}
independent_layer_height = print_config.independent_support_layer_height;
}
// Both top / bottom contacts and interfaces are soluble.
bool soluble_interface;
@@ -214,7 +235,7 @@ struct SupportParameters {
bool has_contacts() const { return this->has_top_contacts || this->has_bottom_contacts; }
bool has_interfaces() const { return this->num_top_interface_layers + this->num_bottom_interface_layers > 0; }
bool has_base_interfaces() const { return this->num_top_base_interface_layers + this->num_bottom_base_interface_layers > 0; }
size_t num_top_interface_layers_only() const { return this->num_top_interface_layers - this->num_top_base_interface_layers; }
size_t num_top_interface_layers_only() const { return std::max(0, int(this->num_top_interface_layers) - int(this->num_top_base_interface_layers)); }
size_t num_bottom_interface_layers_only() const { return this->num_bottom_interface_layers - this->num_bottom_base_interface_layers; }
Flow first_layer_flow;
Flow support_material_flow;
@@ -242,6 +263,7 @@ struct SupportParameters {
coordf_t support_spacing;
coordf_t support_density;
SupportMaterialStyle support_style = smsDefault;
SupportMaterialPattern support_base_pattern = smpDefault;
InfillPattern base_fill_pattern;
InfillPattern interface_fill_pattern;
@@ -257,10 +279,10 @@ struct SupportParameters {
float raft_angle_interface;
// Produce a raft interface angle for a given SupportLayer::interface_id()
float raft_interface_angle(size_t interface_id) const
float raft_interface_angle(size_t interface_id) const
{ return this->raft_angle_interface + ((interface_id & 1) ? float(- M_PI / 4.) : float(+ M_PI / 4.)); }
bool independent_layer_height = false;
const double thresh_big_overhang = Slic3r::sqr(scale_(10));
const double thresh_big_overhang = /*Slic3r::sqr(scale_(10))*/scale_(10);
};
} // namespace Slic3r

View File

@@ -67,6 +67,14 @@ TreeModelVolumes::TreeModelVolumes(
m_machine_border{ calculateMachineBorderCollision(build_volume.polygon()) }
{
m_bed_area = build_volume.polygon();
Polygons machine_borders;
if (!m_bed_area.empty()) {
Polygon hole(m_bed_area);
hole.reverse();
ExPolygon machine_outline(offset(m_bed_area, scale_(1000))[0], hole);
ExPolygons outlines = machine_outline.split_expoly_with_holes(scale_(1.), {});
for (const auto &outline : outlines) machine_borders.emplace_back(outline.contour);
}
#if 0
std::unordered_map<size_t, size_t> mesh_to_layeroutline_idx;
for (size_t mesh_idx = 0; mesh_idx < storage.meshes.size(); ++ mesh_idx) {
@@ -110,8 +118,10 @@ TreeModelVolumes::TreeModelVolumes(
outlines.assign(num_layers, Polygons{});
tbb::parallel_for(tbb::blocked_range<size_t>(num_raft_layers, num_layers, std::min<size_t>(1, std::max<size_t>(16, num_layers / (8 * tbb::this_task_arena::max_concurrency())))),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
outlines[layer_idx] = polygons_simplify(to_polygons(print_object.get_layer(layer_idx - num_raft_layers)->lslices), mesh_settings.resolution);
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) {
outlines[layer_idx] = polygons_simplify(to_polygons(print_object.get_layer(layer_idx - num_raft_layers)->lslices), mesh_settings.resolution);
outlines[layer_idx].insert(outlines[layer_idx].end(), machine_borders.begin(), machine_borders.end());
}
});
}
#endif
@@ -662,6 +672,7 @@ void TreeModelVolumes::calculateAvoidance(const std::vector<RadiusLayerPair> &ke
// Limiting the offset step so that unioning the shrunk latest_avoidance with the current layer collisions
// will not create gaps in the resulting avoidance region letting a tree support branch tunneling through an object wall.
float move_step = 1.9 * std::max(task.radius, m_current_min_xy_dist);
if (move_step < EPSILON) return;
int move_steps = round_up_divide<int>(max_move, move_step);
assert(move_steps > 0);
float last_move_step = max_move - (move_steps - 1) * move_step;

File diff suppressed because it is too large Load Diff

View File

@@ -124,7 +124,9 @@ struct SupportNode
bool need_extra_wall = false;
bool is_sharp_tail = false;
bool valid = true;
bool fading = false;
ExPolygon overhang; // when type==ePolygon, set this value to get original overhang area
coordf_t origin_area;
/*!
* \brief The direction of the skin lines above the tip of the branch.
@@ -411,7 +413,7 @@ public:
*/
ExPolygon m_machine_border;
enum OverhangType { Detected = 0, Enforced, SharpTail };
enum OverhangType : uint8_t { Normal = 0, SharpTail = 1, Cantilever = 1 << 1, Small = 1 << 2, BigFlat = 1 << 3, ThinPlate = 1 << 4, SharpTailLowesst = 1 << 5 };
std::map<const ExPolygon*, OverhangType> overhang_types;
std::vector<std::pair<Vec3f, Vec3f>> m_vertical_enforcer_points;

View File

@@ -565,7 +565,7 @@ static std::optional<std::pair<Point, size_t>> polyline_sample_next_point_at_dis
if (part.front() == part.back()) {
size_t optimal_start_index = 0;
// If the polyline was a polygon, there is a high chance it was an overhang. Overhangs that are <60<36> tend to be very thin areas, so lets get the beginning and end of them and ensure that they are supported.
// If the polyline was a polygon, there is a high chance it was an overhang. Overhangs that are <60<36><EFBFBD>?tend to be very thin areas, so lets get the beginning and end of them and ensure that they are supported.
// The first point of the line will always be supported, so rotate the order of points in this polyline that one of the two corresponding points that are furthest from each other is in the beginning.
// The other will be manually added (optimal_end_index)
coord_t max_dist2_between_vertecies = 0;
@@ -727,114 +727,6 @@ static std::optional<std::pair<Point, size_t>> polyline_sample_next_point_at_dis
#endif
}
/*!
* \brief Unions two Polygons. Ensures that if the input is non empty that the output also will be non empty.
* \param first[in] The first Polygon.
* \param second[in] The second Polygon.
* \return The union of both Polygons
*/
[[nodiscard]] static Polygons safe_union(const Polygons first, const Polygons second = {})
{
// unionPolygons can slowly remove Polygons under certain circumstances, because of rounding issues (Polygons that have a thin area).
// This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly workaround is needed
// Here is an example of a Polygons object that will loose vertices when unioning, and will be gone after a few times unionPolygons was called:
/*
Polygons example;
Polygon exampleInner;
exampleInner.add(Point(120410,83599));//A
exampleInner.add(Point(120384,83643));//B
exampleInner.add(Point(120399,83618));//C
exampleInner.add(Point(120414,83591));//D
exampleInner.add(Point(120423,83570));//E
exampleInner.add(Point(120419,83580));//F
example.add(exampleInner);
for(int i=0;i<10;i++){
log("Iteration %d Example area: %f\n",i,area(example));
example=example.unionPolygons();
}
*/
Polygons result;
if (! first.empty() || ! second.empty()) {
result = union_(first, second);
if (result.empty()) {
BOOST_LOG_TRIVIAL(debug) << "Caught an area destroying union, enlarging areas a bit.";
// just take the few lines we have, and offset them a tiny bit. Needs to be offsetPolylines, as offset may aleady have problems with the area.
result = union_(offset(to_polylines(first), scaled<float>(0.002), jtMiter, 1.2), offset(to_polylines(second), scaled<float>(0.002), jtMiter, 1.2));
}
}
return result;
}
/*!
* \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle.
* \param me[in] Polygons object that has to be offset.
* \param distance[in] The distance by which me should be offset. Expects values >=0.
* \param collision[in] The area representing obstacles.
* \param last_step_offset_without_check[in] The most it is allowed to offset in one step.
* \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get very small. Required as arcTolerance is not exposed in offset, which should result with a similar result.
* \return The resulting Polygons object.
*/
[[nodiscard]] static Polygons safe_offset_inc(const Polygons& me, coord_t distance, const Polygons& collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset)
{
bool do_final_difference = last_step_offset_without_check == 0;
Polygons ret = safe_union(me); // ensure sane input
// Trim the collision polygons with the region of interest for diff() efficiency.
Polygons collision_trimmed_buffer;
auto collision_trimmed = [&collision_trimmed_buffer, &collision, &ret, distance]() -> const Polygons& {
if (collision_trimmed_buffer.empty() && ! collision.empty())
collision_trimmed_buffer = ClipperUtils::clip_clipper_polygons_with_subject_bbox(collision, get_extents(ret).inflated(std::max(0, distance) + SCALED_EPSILON));
return collision_trimmed_buffer;
};
if (distance == 0)
return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret);
if (safe_step_size < 0 || last_step_offset_without_check < 0) {
BOOST_LOG_TRIVIAL(warning) << "Offset increase got invalid parameter!";
tree_supports_show_error("Negative offset distance... How did you manage this ?"sv, true);
return do_final_difference ? diff(ret, collision_trimmed()) : union_(ret);
}
coord_t step_size = safe_step_size;
int steps = distance > last_step_offset_without_check ? (distance - last_step_offset_without_check) / step_size : 0;
if (distance - steps * step_size > last_step_offset_without_check) {
if ((steps + 1) * step_size <= distance)
// This will be the case when last_step_offset_without_check >= safe_step_size
++ steps;
else
do_final_difference = true;
}
if (steps + (distance < last_step_offset_without_check || (distance % step_size) != 0) < int(min_amount_offset) && min_amount_offset > 1) {
// yes one can add a bool as the standard specifies that a result from compare operators has to be 0 or 1
// reduce the stepsize to ensure it is offset the required amount of times
step_size = distance / min_amount_offset;
if (step_size >= safe_step_size) {
// effectivly reduce last_step_offset_without_check
step_size = safe_step_size;
steps = min_amount_offset;
} else
steps = distance / step_size;
}
// offset in steps
for (int i = 0; i < steps; ++ i) {
ret = diff(offset(ret, step_size, ClipperLib::jtRound, scaled<float>(0.01)), collision_trimmed());
// ensure that if many offsets are done the performance does not suffer extremely by the new vertices of jtRound.
if (i % 10 == 7)
ret = polygons_simplify(ret, scaled<double>(0.015));
}
// offset the remainder
float last_offset = distance - steps * step_size;
if (last_offset > SCALED_EPSILON)
ret = offset(ret, distance - steps * step_size, ClipperLib::jtRound, scaled<float>(0.01));
ret = polygons_simplify(ret, scaled<double>(0.015));
if (do_final_difference)
ret = diff(ret, collision_trimmed());
return union_(ret);
}
class RichInterfacePlacer : public InterfacePlacer {
public:
RichInterfacePlacer(
@@ -4173,9 +4065,9 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
const int num_layers = int(print_object.layer_count()) + num_raft_layers;
overhangs.resize(num_layers);
for (size_t i = 0; i < print_object.layer_count(); i++) {
for (ExPolygon& expoly : print_object.get_layer(i)->loverhangs) {
Polygons polys = to_polygons(expoly);
if (tree_support->overhang_types[&expoly] == TreeSupport::SharpTail) { polys = offset(polys, scale_(0.2));
for (auto& expoly_type : print_object.get_layer(i)->loverhangs_with_type) {
Polygons polys = to_polygons(expoly_type.first);
if (expoly_type.second & TreeSupport::SharpTail) { polys = offset(polys, scale_(0.2));
}
append(overhangs[i + num_raft_layers], polys);
}
@@ -4341,7 +4233,7 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
print.set_status(69, _L("Generating support"));
generate_support_toolpaths(print_object.support_layers(), print_object.config(), support_params, print_object.slicing_parameters(),
raft_layers, bottom_contacts, top_contacts, intermediate_layers, interface_layers, base_interface_layers);
auto t_end = std::chrono::high_resolution_clock::now();
BOOST_LOG_TRIVIAL(info) << "Total time of organic tree support: " << 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_end - t_start).count() << " ms";
#if 0
@@ -4817,7 +4709,7 @@ void generate_tree_support_3D(PrintObject &print_object, TreeSupport* tree_suppo
Points bedpts = tree_support->m_machine_border.contour.points;
Pointfs bedptsf;
std::transform(bedpts.begin(), bedpts.end(), std::back_inserter(bedptsf), [](const Point &p) { return unscale(p); });
BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height };
BuildVolume build_volume{ bedptsf, tree_support->m_print_config->printable_height, {}, {} };
TreeSupport3D::generate_support_areas(*print_object.print(), tree_support, build_volume, { idx }, throw_on_cancel);
}

View File

@@ -61,7 +61,7 @@ struct TreeSupportMeshGroupSettings {
config.support_interface_top_layers.value) * this->layer_height :
0;
this->support_material_buildplate_only = config.support_on_build_plate_only;
this->support_xy_distance = scaled<coord_t>(config.support_object_xy_distance.value);
this->support_xy_distance = scaled<coord_t>(config.support_object_xy_distance.value);
this->support_xy_distance_1st_layer = scaled<coord_t>(config.support_object_first_layer_gap.value);
// Separation of interfaces, it is likely smaller than support_xy_distance.
this->support_xy_distance_overhang = std::min(this->support_xy_distance, scaled<coord_t>(0.5 * external_perimeter_width));
@@ -72,7 +72,6 @@ struct TreeSupportMeshGroupSettings {
this->support_floor_enable = config.support_interface_bottom_layers.value > 0;
this->support_floor_layers = config.support_interface_bottom_layers.value;
this->support_roof_pattern = config.support_interface_pattern;
this->support_pattern = config.support_base_pattern;
this->support_line_spacing = scaled<coord_t>(config.support_base_pattern_spacing.value);
this->support_wall_count = std::max(1, config.tree_support_wall_count.value); // at least 1 wall for organic tree support
this->support_roof_line_distance = scaled<coord_t>(config.support_interface_spacing.value) + this->support_roof_line_width;
@@ -165,9 +164,6 @@ struct TreeSupportMeshGroupSettings {
// Support Roof Pattern (aka top interface)
// The pattern with which the roofs of the support are printed.
SupportMaterialInterfacePattern support_roof_pattern { smipAuto };
// Support Pattern
// The pattern of the support structures of the print. The different options available result in sturdy or easy to remove support.
SupportMaterialPattern support_pattern { smpRectilinear };
// Support Line Distance
// Distance between the printed support structure lines. This setting is calculated by the support density.
coord_t support_line_spacing { scaled<coord_t>(2.66 - 0.4) };
@@ -283,7 +279,6 @@ struct TreeSupportSettings
// support_infill_angles(mesh_group_settings.support_infill_angles),
support_roof_angles(mesh_group_settings.support_roof_angles),
roof_pattern(mesh_group_settings.support_roof_pattern),
support_pattern(mesh_group_settings.support_pattern),
support_roof_line_width(mesh_group_settings.support_roof_line_width),
support_line_spacing(mesh_group_settings.support_line_spacing),
support_bottom_offset(mesh_group_settings.support_bottom_offset),