Revert "Raft, support interface fix and overhaul (#10947)"

This reverts commit 4692661631.
This commit is contained in:
SoftFever
2026-02-13 15:22:03 +08:00
parent 4692661631
commit dfbdcad766
4 changed files with 88 additions and 147 deletions

View File

@@ -1330,82 +1330,72 @@ SupportGeneratorLayersPtr generate_support_layers(
// Install support layers into the object.
// A support layer installed on a PrintObject has a unique print_z.
SupportGeneratorLayersPtr layers_sorted;
layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size()
+ intermediate_layers.size() + interface_layers.size() + base_interface_layers.size());
layers_sorted.reserve(raft_layers.size() + bottom_contacts.size() + top_contacts.size() + intermediate_layers.size() + interface_layers.size() + base_interface_layers.size());
append(layers_sorted, raft_layers);
append(layers_sorted, bottom_contacts);
append(layers_sorted, top_contacts);
append(layers_sorted, intermediate_layers);
append(layers_sorted, interface_layers);
append(layers_sorted, base_interface_layers);
// remove duplicated layers
// remove dupliated layers
std::sort(layers_sorted.begin(), layers_sorted.end());
layers_sorted.erase(std::unique(layers_sorted.begin(), layers_sorted.end()), layers_sorted.end());
// Sort the layers lexicographically by a raising print_z and a decreasing height.
std::sort(layers_sorted.begin(), layers_sorted.end(), [](auto *l1, auto *l2) { return *l1 < *l2; });
int layer_id = 0;
int interface_id = 0;
int layer_id_interface = 0;
assert(object.support_layers().empty());
for (size_t i = 0; i < layers_sorted.size();) {
// Group layers with nearly the same print_z (floating point fuzz).
// Find the last layer with roughly the same print_z, find the minimum layer height of all.
// Due to the floating point inaccuracies, the print_z may not be the same even if in theory they should.
size_t j = i + 1;
coordf_t zmax = layers_sorted[i]->print_z + EPSILON;
for (; j < layers_sorted.size() && layers_sorted[j]->print_z <= zmax; ++j) ;
// Assign an average print_z to the set of layers with nearly equal print_z.
coordf_t zavg = 0.5 * (layers_sorted[i]->print_z + layers_sorted[j - 1]->print_z);
coordf_t zavg = 0.5 * (layers_sorted[i]->print_z + layers_sorted[j - 1]->print_z);
coordf_t height_min = layers_sorted[i]->height;
bool empty_layer = true;
bool has_interface_layer = false;
bool empty = true;
// For snug supports, layers where the direction of the support interface shall change are accounted for.
size_t num_interfaces = 0;
size_t num_top_contacts = 0;
double top_contact_bottom_z = 0;
for (size_t u = i; u < j; ++u) {
SupportGeneratorLayer &layer = *layers_sorted[u];
if (!layer.polygons.empty()) {
empty_layer = false;
if (one_of(layer.layer_type, support_types_interface))
has_interface_layer = true;
if (! layer.polygons.empty()) {
empty = false;
num_interfaces += one_of(layer.layer_type, support_types_interface);
if (layer.layer_type == SupporLayerType::TopContact) {
++ num_top_contacts;
assert(num_top_contacts <= 1);
// All top contact layers sharing this print_z shall also share bottom_z.
//assert(num_top_contacts == 1 || (top_contact_bottom_z - layer.bottom_z) < EPSILON);
top_contact_bottom_z = layer.bottom_z;
}
}
layer.print_z = zavg;
height_min = std::min(height_min, layer.height);
height_min = std::min(height_min, layer.height);
}
if (!empty_layer) {
// Default: keep the global interface_id counter.
int this_iface_id = interface_id;
// Special case: TreeOrganic raft-interface layers.
// Interface IDs may be unstable here, leading to inconsistent angles.
// Use deterministic IDs: alternate 0/1 by distance from the base raft.
bool is_tree_organic = (object.config().support_style == SupportMaterialStyle::smsTreeOrganic ||
(object.config().support_style == SupportMaterialStyle::smsDefault && is_tree(object.config().support_type)));
if (is_tree_organic &&
layer_id >= object.slicing_parameters().base_raft_layers &&
layer_id < object.slicing_parameters().raft_layers())
{
// Alternate IDs 0,1,0,1... based on distance from base raft.
this_iface_id = (layer_id - object.slicing_parameters().base_raft_layers) & 1;
if (! empty) {
// Here the upper_layer and lower_layer pointers are left to null at the support layers,
// as they are never used. These pointers are candidates for removal.
bool this_layer_contacts_only = num_top_contacts > 0 && num_top_contacts == num_interfaces;
size_t this_layer_id_interface = layer_id_interface;
if (this_layer_contacts_only) {
// Find a supporting layer for its interface ID.
for (auto it = object.support_layers().rbegin(); it != object.support_layers().rend(); ++ it)
if (const SupportLayer &other_layer = **it; std::abs(other_layer.print_z - top_contact_bottom_z) < EPSILON) {
// other_layer supports this top contact layer. Assign a different support interface direction to this layer
// from the layer that supports it.
this_layer_id_interface = other_layer.interface_id() + 1;
}
}
// END special case
object.add_support_layer(layer_id++, this_iface_id, height_min, zavg);
// Only increment the global counter if this set actually contains interface/contact layers.
if (has_interface_layer)
interface_id++;
object.add_support_layer(layer_id ++, this_layer_id_interface, height_min, zavg);
if (num_interfaces && ! this_layer_contacts_only)
++ layer_id_interface;
}
i = j;
}
return layers_sorted;
}
@@ -1581,12 +1571,12 @@ void generate_support_toolpaths(
if (filler_base_interface)
filler_base_interface->set_bounding_box(bbox_object);
filler_support->set_bounding_box(bbox_object);
for (size_t support_layer_id = range.begin(); support_layer_id < range.end(); ++ support_layer_id)
{
SupportLayer &support_layer = *support_layers[support_layer_id];
LayerCache &layer_cache = layer_caches[support_layer_id];
const float support_interface_angle = support_params.support_interface_angle(support_layer.interface_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;
@@ -1679,9 +1669,10 @@ void generate_support_toolpaths(
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; // Use interface angle for the interface layers.
support_interface_angle;
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();

View File

@@ -111,8 +111,6 @@ struct SupportParameters {
SupportMaterialPattern support_pattern = object_config.support_base_pattern;
this->with_sheath = object_config.tree_support_wall_count > 0;
// Cache Rectilinear Interlaced flag once
this->interlaced_interface = (object_config.support_interface_pattern == smipRectilinearInterlaced);
this->base_fill_pattern =
support_pattern == smpHoneycomb ? ipHoneycomb :
this->support_density > 0.95 || this->with_sheath ? ipRectilinear : ipSupportBase;
@@ -129,10 +127,37 @@ struct SupportParameters {
ipConcentric :
(this->interface_density > 0.95 ? ipRectilinear : ipSupportBase);
this->raft_angle_1st_layer = float(M_PI_2);
this->raft_angle_base = 0.0f;
this->raft_angle_interface = slicing_params.base_raft_layers == 1 ? 0.0f : float(M_PI_2); // make it perpendicular to the layer beneath it
this->raft_angle_1st_layer = 0.f;
this->raft_angle_base = 0.f;
this->raft_angle_interface = 0.f;
if (slicing_params.base_raft_layers > 1) {
assert(slicing_params.raft_layers() >= 4);
// There are all raft layer types (1st layer, base, interface & contact layers) available.
this->raft_angle_1st_layer = this->interface_angle;
this->raft_angle_base = this->base_angle;
this->raft_angle_interface = this->interface_angle;
if ((slicing_params.interface_raft_layers & 1) == 0)
// Allign the 1st raft interface layer so that the object 1st layer is hatched perpendicularly to the raft contact interface.
this->raft_angle_interface += float(0.5 * M_PI);
} else if (slicing_params.base_raft_layers == 1 || slicing_params.interface_raft_layers > 1) {
assert(slicing_params.raft_layers() == 2 || slicing_params.raft_layers() == 3);
// 1st layer, interface & contact layers available.
this->raft_angle_1st_layer = this->base_angle;
this->raft_angle_interface = this->interface_angle + 0.5 * M_PI;
} else if (slicing_params.interface_raft_layers == 1) {
// Only the contact raft layer is non-empty, which will be printed as the 1st layer.
assert(slicing_params.base_raft_layers == 0);
assert(slicing_params.interface_raft_layers == 1);
assert(slicing_params.raft_layers() == 1);
this->raft_angle_1st_layer = float(0.5 * M_PI);
this->raft_angle_interface = this->raft_angle_1st_layer;
} else {
// No raft.
assert(slicing_params.base_raft_layers == 0);
assert(slicing_params.interface_raft_layers == 0);
assert(slicing_params.raft_layers() == 0);
}
const auto nozzle_diameter = print_config.nozzle_diameter.get_at(object_config.support_interface_filament - 1);
const coordf_t extrusion_width = object_config.line_width.get_abs_value(nozzle_diameter);
support_extrusion_width = object_config.support_line_width.get_abs_value(nozzle_diameter);
@@ -229,8 +254,6 @@ struct SupportParameters {
InfillPattern contact_fill_pattern;
// Shall the sparse (base) layers be printed with a single perimeter line (sheath) for robustness?
bool with_sheath;
// True if support interface pattern is Rectilinear Interlaced
bool interlaced_interface = false;
// Branches of organic supports with area larger than this threshold will be extruded with double lines.
double tree_branch_diameter_double_wall_area_scaled = 0.25 * sqr(scaled<double>(5.0)) * M_PI;;
@@ -239,30 +262,8 @@ 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
{
// Raft interfaces → always alternate 0°/90°
return this->raft_angle_interface +
((interface_id & 1) ? float(M_PI_2) : 0.0f);
}
float support_interface_angle(size_t interface_id) const
{
if (this->support_style == smsSnug) {
// Snug → ±45°
return this->interface_angle +
((interface_id & 1) ? -float(M_PI_4) : +float(M_PI_4));
}
if (this->interlaced_interface) {
// Interlaced → 0°/90°
return this->interface_angle +
((interface_id & 1) ? float(M_PI_2) : 0.0f);
}
// Default → fixed
return this->interface_angle;
}
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));

View File

@@ -618,7 +618,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
if(support_pattern == smpLightning)
m_support_params.base_fill_pattern = ipLightning;
diameter_angle_scale_factor = std::clamp<double>(m_object_config->tree_support_branch_diameter_angle * M_PI / 180., 0., M_PI_2 - EPSILON);
diameter_angle_scale_factor = std::clamp<double>(m_object_config->tree_support_branch_diameter_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
is_slim = is_tree_slim(support_type, m_support_params.support_style);
is_strong = is_tree(support_type) && m_support_params.support_style == smsTreeStrong;
base_radius = std::max(MIN_BRANCH_RADIUS, m_object_config->tree_support_branch_diameter.value / 2);
@@ -1369,7 +1369,7 @@ void TreeSupport::generate_toolpaths()
Flow support_flow = Flow(support_extrusion_width, ts_layer->height, nozzle_diameter);
Fill* filler_raft = Fill::new_from_type(ipRectilinear);
filler_raft->angle = layer_nr == 0 ? M_PI_2 : 0;
filler_raft->angle = layer_nr == 0 ? PI/2 : 0;
filler_raft->spacing = support_flow.spacing();
FillParams fill_params;
@@ -1404,24 +1404,14 @@ void TreeSupport::generate_toolpaths()
// raft interfaces
for (layer_nr = m_slicing_params.base_raft_layers;
layer_nr < m_raft_layers;
layer_nr < m_slicing_params.base_raft_layers + m_slicing_params.interface_raft_layers;
layer_nr++)
{
SupportLayer *ts_layer = m_object->get_support_layer(layer_nr);
Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter);
Fill* filler_interface = Fill::new_from_type(ipRectilinear);
const size_t iface_idx = layer_nr - m_slicing_params.base_raft_layers;
const bool single_raft_base_layer = (m_slicing_params.base_raft_layers == 1);
// Make interface lines alternate 0°/90° between layers, to improve bonding.
// If only 1 base layer → start at 0°; otherwise (0 or ≥2 base layers) → start at 90°.
filler_interface->angle =
(iface_idx & 1)
? (single_raft_base_layer ? float(M_PI_2) : 0.0f)
: (single_raft_base_layer ? 0.0f : float(M_PI_2));
filler_interface->angle = PI / 2; // interface should be perpendicular to base
filler_interface->spacing = support_flow.spacing();
FillParams fill_params;
@@ -1441,7 +1431,7 @@ void TreeSupport::generate_toolpaths()
SupportLayer *ts_layer = m_object->get_support_layer(layer_nr);
Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter);
Fill* filler_raft = Fill::new_from_type(ipRectilinear);
filler_raft->angle = M_PI_2;
filler_raft->angle = PI / 2;
filler_raft->spacing = support_flow.spacing();
for (auto& poly : first_non_raft_base)
make_perimeter_and_infill(ts_layer->support_fills.entities, poly, std::min(size_t(1), wall_count), support_flow, erSupportMaterial, filler_raft, interface_density, false);
@@ -1502,10 +1492,6 @@ void TreeSupport::generate_toolpaths()
fill_params.density = interface_density;
// Note: spacing means the separation between two lines as if they are tightly extruded
filler_Roof1stLayer->spacing = interface_flow.spacing();
if (m_object_config->support_interface_pattern == smipRectilinearInterlaced)
filler_Roof1stLayer->layer_id = area_group.interface_id;
// generate a perimeter first to support interface better
ExtrusionEntityCollection* temp_support_fills = new ExtrusionEntityCollection();
make_perimeter_and_infill(temp_support_fills->entities, poly, 1, interface_flow, erSupportMaterial,
@@ -1519,10 +1505,6 @@ void TreeSupport::generate_toolpaths()
// floor_areas
fill_params.density = bottom_interface_density;
filler_interface->spacing = interface_flow.spacing();
if (m_object_config->support_interface_pattern == smipRectilinearInterlaced)
filler_interface->layer_id = area_group.interface_id;
fill_expolygons_generate_paths(ts_layer->support_fills.entities, polys,
filler_interface.get(), fill_params, erSupportMaterialInterface, interface_flow);
} else if (area_group.type == SupportLayer::RoofType) {
@@ -1719,7 +1701,7 @@ void TreeSupport::generate()
draw_circles();
profiler.stage_finish(STAGE_DRAW_CIRCLES);
normalize_interface_ids();
profiler.stage_start(STAGE_GENERATE_TOOLPATHS);
m_object->print()->set_status(70, _u8L("Generating support"));
@@ -1948,7 +1930,7 @@ void TreeSupport::draw_circles()
{
double angle;
if (SQUARE_SUPPORT)
angle = (double) i / CIRCLE_RESOLUTION * TAU + M_PI_4 + nodes_angle;
angle = (double) i / CIRCLE_RESOLUTION * TAU + PI / 4.0 + nodes_angle;
else
angle = (double) i / CIRCLE_RESOLUTION * TAU;
branch_circle.append(Point(cos(angle) * branch_radius_scaled, sin(angle) * branch_radius_scaled));
@@ -2012,6 +1994,7 @@ void TreeSupport::draw_circles()
coordf_t max_layers_above_base = 0;
coordf_t max_layers_above_roof = 0;
coordf_t max_layers_above_roof1 = 0;
int interface_id = 0;
bool has_circle_node = false;
bool need_extra_wall = false;
ExPolygons collision_sharp_tails;
@@ -2106,17 +2089,18 @@ void TreeSupport::draw_circles()
}
}
if (obj_layer_nr > 0 && node.distance_to_top < 0)
if (obj_layer_nr>0 && node.distance_to_top < 0)
append(roof_gap_areas, area);
else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 && node.is_sharp_tail==false)
{
append(roof_1st_layer, area);
max_layers_above_roof1 = std::max(max_layers_above_roof1, node.dist_mm_to_top);
}
else if (obj_layer_nr > 0 && node.support_roof_layers_below > 1 && node.is_sharp_tail == false)
else if (obj_layer_nr > 0 && node.support_roof_layers_below > 0 && node.is_sharp_tail == false)
{
append(roof_areas, area);
max_layers_above_roof = std::max(max_layers_above_roof, node.dist_mm_to_top);
interface_id = node.obj_layer_nr % top_interface_layers;
}
else
{
@@ -2187,6 +2171,7 @@ void TreeSupport::draw_circles()
for (auto& expoly : ts_layer->roof_areas) {
//if (area(expoly) < SQ(scale_(1))) continue;
area_groups.emplace_back(&expoly, SupportLayer::RoofType, max_layers_above_roof);
area_groups.back().interface_id = interface_id;
}
for (auto &expoly : ts_layer->floor_areas) {
//if (area(expoly) < SQ(scale_(1))) continue;
@@ -2427,27 +2412,6 @@ void TreeSupport::draw_circles()
}
}
/*!
* Reassigns sequential interface IDs to enforce A/B alternation
* for RectilinearInterlaced support patterns.
*/
void TreeSupport::normalize_interface_ids()
{
if (m_object_config->support_interface_pattern != smipRectilinearInterlaced)
return;
size_t iface_parity = 0;
for (int lid = m_raft_layers; lid < m_object->support_layer_count(); ++lid) {
SupportLayer* ts_layer = m_object->get_support_layer(lid);
if (!ts_layer) continue;
for (auto &ag : ts_layer->area_groups)
ag.interface_id = iface_parity;
iface_parity ^= 1;
}
}
double SupportNode::diameter_angle_scale_factor;
void TreeSupport::drop_nodes()
@@ -2459,7 +2423,7 @@ void TreeSupport::drop_nodes()
const double angle = config.tree_support_branch_angle.value * M_PI / 180.;
const int wall_count = std::max(1, config.tree_support_wall_count.value);
double tan_angle = tan(angle); // when nodes are thick, they can move further. this is the max angle
const coordf_t max_move_distance = (angle < M_PI_2) ? (coordf_t)(tan_angle * layer_height)*wall_count : std::numeric_limits<coordf_t>::max();
const coordf_t max_move_distance = (angle < M_PI / 2) ? (coordf_t)(tan_angle * layer_height)*wall_count : std::numeric_limits<coordf_t>::max();
const double max_move_distance2 = max_move_distance * max_move_distance;
const size_t tip_layers = base_radius / layer_height; //The number of layers to be shrinking the circle to create a tip. This produces a 45 degree angle.
const coordf_t radius_sample_resolution = m_ts_data->m_radius_sample_resolution;

View File

@@ -459,21 +459,6 @@ private:
* \param contact_nodes The nodes to draw as support.
*/
void draw_circles();
/*!
* \brief Normalize interface IDs for interlaced supports.
*
* Reassigns sequential IDs to support layers when using
* RectilinearInterlaced, alternating (0,1,0,1,…) so consecutive
* interface layers never share orientation. Applies to all support
* area groups, including transition layers (e.g. TreeStrong
* body-to-interface), as well as top and bottom interfaces, so
* FillRectilinearInterlaced computes correct extrusion angles.
*
* \note Call after support layers are built and before toolpaths,
* so fillers use the normalized IDs.
*/
void normalize_interface_ids();
/*!
* \brief Drops down the nodes of the tree support towards the build plate.