Skip to content

Commit 34e902b

Browse files
Copilotcochcoder
andcommitted
Fall back to standard support generator when Rust tree supports produce no output
Co-authored-by: cochcoder <103969142+cochcoder@users.noreply.github.com>
1 parent 6bc04ce commit 34e902b

File tree

1 file changed

+139
-126
lines changed

1 file changed

+139
-126
lines changed

src/libslic3r/PrintObject.cpp

Lines changed: 139 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,146 +3935,159 @@ void PrintObject::combine_infill()
39353935

39363936
void PrintObject::_generate_support_material()
39373937
{
3938+
bool use_fallback_support = false;
3939+
39383940
if (is_tree(m_config.support_type.value)) {
39393941
#ifdef HAS_RUST_TREE_SUPPORTS
3940-
// Use Rust tree support generation via FFI
3941-
if (m_model_object->volumes.empty()) {
3942-
BOOST_LOG_TRIVIAL(error) << "Tree support generation: model object has no volumes";
3943-
return;
3944-
}
3945-
3946-
// Default values for tree support parameters not exposed in OrcaSlicer UI
3947-
constexpr double TREE_SUPPORT_RESOLUTION_MM = 0.025;
3948-
constexpr double TREE_SUPPORT_MIN_FEATURE_SIZE_MM = 0.1;
3949-
constexpr double TREE_SUPPORT_XY_OVERHANGS_MM = 0.2;
3950-
constexpr double TREE_SUPPORT_INTERFACE_SKIP_HEIGHT_MM = 0.3;
3951-
constexpr double TREE_SUPPORT_BP_DIAMETER_MM = 7.5; // buildplate contact diameter
3952-
constexpr double TREE_SUPPORT_MIN_BOTTOM_AREA_MM = 1.0;
3953-
constexpr double TREE_SUPPORT_MAX_DIAMETER_INCREASE_MM = 1.0; // max diameter increase per merge
3954-
constexpr double TREE_SUPPORT_MIN_HEIGHT_TO_MODEL_MM = 1.0;
3955-
3956-
// Populate tree support config from OrcaSlicer print settings
3957-
TreeSupportConfig cfg = {};
3958-
cfg.layer_height = scaled<int64_t>(m_slicing_params.layer_height);
3959-
cfg.resolution = scaled<int64_t>(TREE_SUPPORT_RESOLUTION_MM);
3960-
cfg.min_feature_size = scaled<int64_t>(TREE_SUPPORT_MIN_FEATURE_SIZE_MM);
3961-
cfg.support_angle = m_config.support_angle.value * M_PI / 180.0;
3962-
cfg.support_line_width = scaled<int64_t>(m_config.support_line_width.get_abs_value(m_config.line_width.value));
3963-
cfg.support_roof_line_width = scaled<int64_t>(m_config.support_line_width.get_abs_value(m_config.line_width.value));
3964-
cfg.support_bottom_enable = m_config.support_interface_bottom_layers.value > 0;
3965-
cfg.support_bottom_height = scaled<int64_t>(m_config.support_bottom_z_distance.value);
3966-
cfg.support_material_buildplate_only = m_config.support_on_build_plate_only.value;
3967-
cfg.support_xy_distance = scaled<int64_t>(m_config.support_object_xy_distance.value);
3968-
cfg.support_xy_distance_first_layer = scaled<int64_t>(m_config.support_object_xy_distance.value);
3969-
cfg.support_xy_distance_overhang = scaled<int64_t>(TREE_SUPPORT_XY_OVERHANGS_MM);
3970-
cfg.support_top_distance = scaled<int64_t>(m_config.support_top_z_distance.value);
3971-
cfg.support_bottom_distance = scaled<int64_t>(m_config.support_bottom_z_distance.value);
3972-
cfg.support_interface_skip_height = scaled<int64_t>(TREE_SUPPORT_INTERFACE_SKIP_HEIGHT_MM);
3973-
cfg.support_roof_enable = m_config.support_interface_top_layers.value > 0;
3974-
cfg.support_roof_layers = static_cast<int32_t>(m_config.support_interface_top_layers.value);
3975-
cfg.support_floor_enable = m_config.support_interface_bottom_layers.value > 0;
3976-
cfg.support_floor_layers = static_cast<int32_t>(m_config.support_interface_bottom_layers.value);
3977-
cfg.minimum_roof_area = 0.0; // no minimum, generate roof for all contact areas
3978-
cfg.support_line_spacing = scaled<int64_t>(m_config.support_base_pattern_spacing.value);
3979-
cfg.support_bottom_offset = 0; // no offset for bottom support layers
3980-
cfg.support_wall_count = static_cast<int32_t>(m_config.tree_support_wall_count.value);
3981-
cfg.support_roof_line_distance = cfg.support_line_width;
3982-
cfg.minimum_support_area = 0; // no minimum, generate support for all detected overhangs
3983-
cfg.minimum_bottom_area = scaled<int64_t>(TREE_SUPPORT_MIN_BOTTOM_AREA_MM);
3984-
cfg.support_offset = 0; // no additional polygon offset
3985-
cfg.support_tree_angle = m_config.tree_support_branch_angle.value * M_PI / 180.0;
3986-
cfg.support_tree_angle_slow = m_config.tree_support_angle_slow.value * M_PI / 180.0;
3987-
cfg.support_tree_branch_diameter = scaled<int64_t>(m_config.tree_support_branch_diameter.value);
3988-
cfg.support_tree_branch_diameter_angle = m_config.tree_support_branch_diameter_angle.value * M_PI / 180.0;
3989-
cfg.support_tree_branch_distance = scaled<int64_t>(m_config.tree_support_branch_distance.value);
3990-
cfg.support_tree_bp_diameter = scaled<int64_t>(TREE_SUPPORT_BP_DIAMETER_MM);
3991-
cfg.support_tree_top_rate = m_config.tree_support_top_rate.value;
3992-
cfg.support_tree_tip_diameter = scaled<int64_t>(m_config.tree_support_tip_diameter.value);
3993-
cfg.support_tree_max_diameter_increase_by_merges_when_support_to_model = scaled<int64_t>(TREE_SUPPORT_MAX_DIAMETER_INCREASE_MM);
3994-
cfg.support_tree_min_height_to_model = scaled<int64_t>(TREE_SUPPORT_MIN_HEIGHT_TO_MODEL_MM);
3995-
cfg.support_rests_on_model = !m_config.support_on_build_plate_only.value;
3996-
3997-
// Convert mesh to flat arrays for FFI
3998-
const indexed_triangle_set &its = m_model_object->volumes.front()->mesh().its;
3999-
std::vector<float> vertices;
4000-
vertices.reserve(its.vertices.size() * 3);
4001-
for (const auto &v : its.vertices) {
4002-
vertices.push_back(v.x());
4003-
vertices.push_back(v.y());
4004-
vertices.push_back(v.z());
4005-
}
4006-
std::vector<uint32_t> indices;
4007-
indices.reserve(its.indices.size() * 3);
4008-
for (const auto &f : its.indices) {
4009-
indices.push_back(static_cast<uint32_t>(f[0]));
4010-
indices.push_back(static_cast<uint32_t>(f[1]));
4011-
indices.push_back(static_cast<uint32_t>(f[2]));
4012-
}
3942+
// Try Rust tree support generation via FFI
3943+
bool rust_succeeded = false;
3944+
3945+
if (!m_model_object->volumes.empty()) {
3946+
// Default values for tree support parameters not exposed in OrcaSlicer UI
3947+
constexpr double TREE_SUPPORT_RESOLUTION_MM = 0.025;
3948+
constexpr double TREE_SUPPORT_MIN_FEATURE_SIZE_MM = 0.1;
3949+
constexpr double TREE_SUPPORT_XY_OVERHANGS_MM = 0.2;
3950+
constexpr double TREE_SUPPORT_INTERFACE_SKIP_HEIGHT_MM = 0.3;
3951+
constexpr double TREE_SUPPORT_BP_DIAMETER_MM = 7.5; // buildplate contact diameter
3952+
constexpr double TREE_SUPPORT_MIN_BOTTOM_AREA_MM = 1.0;
3953+
constexpr double TREE_SUPPORT_MAX_DIAMETER_INCREASE_MM = 1.0; // max diameter increase per merge
3954+
constexpr double TREE_SUPPORT_MIN_HEIGHT_TO_MODEL_MM = 1.0;
3955+
3956+
// Populate tree support config from OrcaSlicer print settings
3957+
TreeSupportConfig cfg = {};
3958+
cfg.layer_height = scaled<int64_t>(m_slicing_params.layer_height);
3959+
cfg.resolution = scaled<int64_t>(TREE_SUPPORT_RESOLUTION_MM);
3960+
cfg.min_feature_size = scaled<int64_t>(TREE_SUPPORT_MIN_FEATURE_SIZE_MM);
3961+
cfg.support_angle = m_config.support_angle.value * M_PI / 180.0;
3962+
cfg.support_line_width = scaled<int64_t>(m_config.support_line_width.get_abs_value(m_config.line_width.value));
3963+
cfg.support_roof_line_width = scaled<int64_t>(m_config.support_line_width.get_abs_value(m_config.line_width.value));
3964+
cfg.support_bottom_enable = m_config.support_interface_bottom_layers.value > 0;
3965+
cfg.support_bottom_height = scaled<int64_t>(m_config.support_bottom_z_distance.value);
3966+
cfg.support_material_buildplate_only = m_config.support_on_build_plate_only.value;
3967+
cfg.support_xy_distance = scaled<int64_t>(m_config.support_object_xy_distance.value);
3968+
cfg.support_xy_distance_first_layer = scaled<int64_t>(m_config.support_object_xy_distance.value);
3969+
cfg.support_xy_distance_overhang = scaled<int64_t>(TREE_SUPPORT_XY_OVERHANGS_MM);
3970+
cfg.support_top_distance = scaled<int64_t>(m_config.support_top_z_distance.value);
3971+
cfg.support_bottom_distance = scaled<int64_t>(m_config.support_bottom_z_distance.value);
3972+
cfg.support_interface_skip_height = scaled<int64_t>(TREE_SUPPORT_INTERFACE_SKIP_HEIGHT_MM);
3973+
cfg.support_roof_enable = m_config.support_interface_top_layers.value > 0;
3974+
cfg.support_roof_layers = static_cast<int32_t>(m_config.support_interface_top_layers.value);
3975+
cfg.support_floor_enable = m_config.support_interface_bottom_layers.value > 0;
3976+
cfg.support_floor_layers = static_cast<int32_t>(m_config.support_interface_bottom_layers.value);
3977+
cfg.minimum_roof_area = 0.0; // no minimum, generate roof for all contact areas
3978+
cfg.support_line_spacing = scaled<int64_t>(m_config.support_base_pattern_spacing.value);
3979+
cfg.support_bottom_offset = 0; // no offset for bottom support layers
3980+
cfg.support_wall_count = static_cast<int32_t>(m_config.tree_support_wall_count.value);
3981+
cfg.support_roof_line_distance = cfg.support_line_width;
3982+
cfg.minimum_support_area = 0; // no minimum, generate support for all detected overhangs
3983+
cfg.minimum_bottom_area = scaled<int64_t>(TREE_SUPPORT_MIN_BOTTOM_AREA_MM);
3984+
cfg.support_offset = 0; // no additional polygon offset
3985+
cfg.support_tree_angle = m_config.tree_support_branch_angle.value * M_PI / 180.0;
3986+
cfg.support_tree_angle_slow = m_config.tree_support_angle_slow.value * M_PI / 180.0;
3987+
cfg.support_tree_branch_diameter = scaled<int64_t>(m_config.tree_support_branch_diameter.value);
3988+
cfg.support_tree_branch_diameter_angle = m_config.tree_support_branch_diameter_angle.value * M_PI / 180.0;
3989+
cfg.support_tree_branch_distance = scaled<int64_t>(m_config.tree_support_branch_distance.value);
3990+
cfg.support_tree_bp_diameter = scaled<int64_t>(TREE_SUPPORT_BP_DIAMETER_MM);
3991+
cfg.support_tree_top_rate = m_config.tree_support_top_rate.value;
3992+
cfg.support_tree_tip_diameter = scaled<int64_t>(m_config.tree_support_tip_diameter.value);
3993+
cfg.support_tree_max_diameter_increase_by_merges_when_support_to_model = scaled<int64_t>(TREE_SUPPORT_MAX_DIAMETER_INCREASE_MM);
3994+
cfg.support_tree_min_height_to_model = scaled<int64_t>(TREE_SUPPORT_MIN_HEIGHT_TO_MODEL_MM);
3995+
cfg.support_rests_on_model = !m_config.support_on_build_plate_only.value;
3996+
3997+
// Convert mesh to flat arrays for FFI
3998+
const indexed_triangle_set &its = m_model_object->volumes.front()->mesh().its;
3999+
std::vector<float> vertices;
4000+
vertices.reserve(its.vertices.size() * 3);
4001+
for (const auto &v : its.vertices) {
4002+
vertices.push_back(v.x());
4003+
vertices.push_back(v.y());
4004+
vertices.push_back(v.z());
4005+
}
4006+
std::vector<uint32_t> indices;
4007+
indices.reserve(its.indices.size() * 3);
4008+
for (const auto &f : its.indices) {
4009+
indices.push_back(static_cast<uint32_t>(f[0]));
4010+
indices.push_back(static_cast<uint32_t>(f[1]));
4011+
indices.push_back(static_cast<uint32_t>(f[2]));
4012+
}
40134013

4014-
MeshData mesh_data;
4015-
mesh_data.vertices = vertices.data();
4016-
mesh_data.vertex_count = static_cast<uint32_t>(its.vertices.size());
4017-
mesh_data.indices = indices.data();
4018-
mesh_data.triangle_count = static_cast<uint32_t>(its.indices.size());
4019-
4020-
TreeSupportHandle *handle = orca_tree_support_create(&cfg, &mesh_data);
4021-
if (handle) {
4022-
SupportOutput *output = orca_tree_support_generate(handle);
4023-
if (output && output->success && output->layer_count > 0) {
4024-
// Set up support parameters and flow for extrusion generation
4025-
SupportParameters support_params(*this);
4026-
Flow support_flow = Slic3r::support_material_flow(this, float(m_slicing_params.layer_height));
4027-
4028-
// Convert Rust output to SupportLayer objects with polygon data
4029-
for (uint32_t i = 0; i < output->layer_count; i++) {
4030-
const auto &layer = output->layers[i];
4031-
coordf_t print_z = layer.z;
4032-
coordf_t height = (i > 0) ? print_z - output->layers[i - 1].z : print_z;
4033-
SupportLayer *support_layer = add_tree_support_layer(static_cast<int>(i), height, print_z, print_z - 0.5 * height);
4034-
4035-
// Convert Rust polygon data to Slic3r Polygons
4036-
Polygons polygons;
4037-
if (layer.polygon_count > 0 && layer.polygon_points != nullptr && layer.polygon_sizes != nullptr) {
4038-
uint32_t point_offset = 0;
4039-
for (uint32_t p = 0; p < layer.polygon_count; p++) {
4040-
uint32_t poly_size = layer.polygon_sizes[p];
4041-
Polygon polygon;
4042-
polygon.points.reserve(poly_size);
4043-
for (uint32_t j = 0; j < poly_size; j++) {
4044-
const auto &pt = layer.polygon_points[point_offset + j];
4045-
polygon.points.emplace_back(static_cast<coord_t>(pt.x), static_cast<coord_t>(pt.y));
4014+
MeshData mesh_data;
4015+
mesh_data.vertices = vertices.data();
4016+
mesh_data.vertex_count = static_cast<uint32_t>(its.vertices.size());
4017+
mesh_data.indices = indices.data();
4018+
mesh_data.triangle_count = static_cast<uint32_t>(its.indices.size());
4019+
4020+
TreeSupportHandle *handle = orca_tree_support_create(&cfg, &mesh_data);
4021+
if (handle) {
4022+
SupportOutput *output = orca_tree_support_generate(handle);
4023+
if (output && output->success && output->layer_count > 0) {
4024+
// Set up support parameters and flow for extrusion generation
4025+
SupportParameters support_params(*this);
4026+
Flow support_flow = Slic3r::support_material_flow(this, float(m_slicing_params.layer_height));
4027+
4028+
// Convert Rust output to SupportLayer objects with polygon data
4029+
bool has_any_fills = false;
4030+
for (uint32_t i = 0; i < output->layer_count; i++) {
4031+
const auto &layer = output->layers[i];
4032+
coordf_t print_z = layer.z;
4033+
coordf_t height = (i > 0) ? print_z - output->layers[i - 1].z : print_z;
4034+
SupportLayer *support_layer = add_tree_support_layer(static_cast<int>(i), height, print_z, print_z - 0.5 * height);
4035+
4036+
// Convert Rust polygon data to Slic3r Polygons
4037+
Polygons polygons;
4038+
if (layer.polygon_count > 0 && layer.polygon_points != nullptr && layer.polygon_sizes != nullptr) {
4039+
uint32_t point_offset = 0;
4040+
for (uint32_t p = 0; p < layer.polygon_count; p++) {
4041+
uint32_t poly_size = layer.polygon_sizes[p];
4042+
Polygon polygon;
4043+
polygon.points.reserve(poly_size);
4044+
for (uint32_t j = 0; j < poly_size; j++) {
4045+
const auto &pt = layer.polygon_points[point_offset + j];
4046+
polygon.points.emplace_back(static_cast<coord_t>(pt.x), static_cast<coord_t>(pt.y));
4047+
}
4048+
point_offset += poly_size;
4049+
if (!polygon.points.empty())
4050+
polygons.push_back(std::move(polygon));
40464051
}
4047-
point_offset += poly_size;
4048-
if (!polygon.points.empty())
4049-
polygons.push_back(std::move(polygon));
4052+
}
4053+
4054+
if (!polygons.empty()) {
4055+
// Store as base_areas for retraction suppression
4056+
support_layer->base_areas = union_ex(polygons);
4057+
// Generate extrusion fills for G-code output
4058+
tree_supports_generate_paths(support_layer->support_fills.entities, polygons, support_flow, support_params);
4059+
if (!support_layer->support_fills.entities.empty())
4060+
has_any_fills = true;
40504061
}
40514062
}
40524063

4053-
if (!polygons.empty()) {
4054-
// Store as base_areas for retraction suppression
4055-
support_layer->base_areas = union_ex(polygons);
4056-
// Generate extrusion fills for G-code output
4057-
tree_supports_generate_paths(support_layer->support_fills.entities, polygons, support_flow, support_params);
4064+
if (has_any_fills) {
4065+
rust_succeeded = true;
4066+
BOOST_LOG_TRIVIAL(info) << "Rust tree support generated " << output->layer_count << " layers, " << output->branch_count << " branches";
4067+
} else {
4068+
// Rust tree support produced layers but no actual extrusion fills — clear and fall back
4069+
this->clear_support_layers();
4070+
BOOST_LOG_TRIVIAL(warning) << "Rust tree support produced no extrusion fills, falling back to standard support generator";
40584071
}
40594072
}
4060-
BOOST_LOG_TRIVIAL(info) << "Rust tree support generated " << output->layer_count << " layers, " << output->branch_count << " branches";
4061-
} else if (output && !output->success) {
4062-
BOOST_LOG_TRIVIAL(error) << "Rust tree support generation failed";
4063-
} else {
4064-
BOOST_LOG_TRIVIAL(error) << "Rust tree support generation returned null output";
4073+
if (output)
4074+
orca_tree_support_destroy_output(output);
4075+
orca_tree_support_destroy_handle(handle);
40654076
}
4066-
if (output)
4067-
orca_tree_support_destroy_output(output);
4068-
orca_tree_support_destroy_handle(handle);
4069-
} else {
4070-
BOOST_LOG_TRIVIAL(error) << "Failed to create Rust tree support handle";
4077+
}
4078+
4079+
if (!rust_succeeded) {
4080+
BOOST_LOG_TRIVIAL(info) << "Rust tree support did not produce output, using standard support generator as fallback";
4081+
use_fallback_support = true;
40714082
}
40724083
#else
4073-
// Rust tree supports not available — no tree support generation
4074-
BOOST_LOG_TRIVIAL(warning) << "Tree support generation requires Rust toolchain (HAS_RUST_TREE_SUPPORTS not defined)";
4084+
// Rust tree supports not available — fall back to standard support generator
4085+
BOOST_LOG_TRIVIAL(info) << "Tree support: Rust toolchain not available, using standard support generator as fallback";
4086+
use_fallback_support = true;
40754087
#endif
40764088
}
4077-
else {
4089+
4090+
if (!is_tree(m_config.support_type.value) || use_fallback_support) {
40784091
PrintObjectSupportMaterial support_material(this, m_slicing_params);
40794092
support_material.generate(*this);
40804093
}

0 commit comments

Comments
 (0)