@@ -3935,146 +3935,159 @@ void PrintObject::combine_infill()
39353935
39363936void 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