This commit is contained in:
Ian Bassi 2026-03-15 21:25:34 +08:00 committed by GitHub
commit 8e7119a1b5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 90 additions and 23 deletions

View file

@ -927,10 +927,22 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
params.fixed_angle = !region_config.solid_infill_rotate_template.value.empty();
}
params.bridge_angle = float(surface.bridge_angle);
// ORCA: Relative/Aligned bridge infill angle
float align_offset = 0.f;
if (region_config.align_infill_direction_to_model) {
auto m = layer.object()->trafo().matrix();
params.angle += atan2((float) m(1, 0), (float) m(0, 0));
align_offset = atan2((float)m(1, 0), (float)m(0, 0));
params.angle += align_offset;
}
if (params.bridge_angle >= 0.f && region_config.align_infill_direction_to_model) {
bool apply_bridge_align = false;
if (surface.is_internal_bridge())
apply_bridge_align = region_config.internal_bridge_angle.value > 0.0 && !region_config.relative_bridge_angle.value;
else if (surface.is_bridge())
apply_bridge_align = region_config.bridge_angle.value > 0.0 && !region_config.relative_bridge_angle.value;
if (apply_bridge_align)
params.bridge_angle += align_offset;
}
// Calculate the actual flow we'll be using for this infill.
@ -1013,6 +1025,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
if (fill.region_id == size_t(-1)) {
fill.region_id = region_id;
fill.surface = surface;
fill.surface.bridge_angle = params->bridge_angle;
fill.expolygons.emplace_back(std::move(fill.surface.expolygon));
//BBS
fill.region_id_group.push_back(region_id);
@ -1550,7 +1563,7 @@ void Layer::make_ironing()
if (ironing_params.extruder != -1) {
//TODO just_infill is currently not used.
ironing_params.just_infill = false;
// Get filament-specific overrides if configured, otherwise use default values
// ORCA: Get filament-specific overrides if configured, otherwise use process values
size_t extruder_idx = ironing_params.extruder - 1;
ironing_params.line_spacing = (!config.filament_ironing_spacing.is_nil(extruder_idx)
? config.filament_ironing_spacing.get_at(extruder_idx)
@ -1564,7 +1577,12 @@ void Layer::make_ironing()
ironing_params.speed = (!config.filament_ironing_speed.is_nil(extruder_idx)
? config.filament_ironing_speed.get_at(extruder_idx)
: config.ironing_speed);
ironing_params.angle = (config.ironing_angle_fixed ? 0 : calculate_infill_rotation_angle(this->object(), this->id(), config.solid_infill_direction.value, config.solid_infill_rotate_template.value)) + config.ironing_angle * M_PI / 180.;
double ironing_angle = (config.ironing_angle_fixed ? 0 : calculate_infill_rotation_angle(this->object(), this->id(), config.solid_infill_direction.value, config.solid_infill_rotate_template.value)) + config.ironing_angle * M_PI / 180.;
if (config.align_infill_direction_to_model) {
auto m = this->object()->trafo().matrix();
ironing_angle += atan2((double)m(1, 0), (double)m(0, 0));
}
ironing_params.angle = ironing_angle;
ironing_params.fixed_angle = config.ironing_angle_fixed || !config.solid_infill_rotate_template.value.empty();
ironing_params.pattern = config.ironing_pattern;
ironing_params.layerm = layerm;

View file

@ -516,10 +516,20 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
SurfaceCollection bridges;
{
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges. layer" << this->layer()->print_z;
const double custom_angle = this->region().config().bridge_angle.value;
bridges.surfaces = custom_angle > 0 ?
expand_merge_surfaces(this->fill_surfaces.surfaces, stBottomBridge, expansion_zones, closing_radius, Geometry::deg2rad(custom_angle)) :
// ORCA: Relative/Align Bridge Angle
const auto &region_config = this->region().config();
const double custom_angle_deg = region_config.bridge_angle.value;
const bool relative_angle = region_config.relative_bridge_angle.value;
const double custom_angle_rad = Geometry::deg2rad(custom_angle_deg);
bridges.surfaces = (custom_angle_deg > 0.0 && !relative_angle) ?
expand_merge_surfaces(this->fill_surfaces.surfaces, stBottomBridge, expansion_zones, closing_radius, custom_angle_rad) :
expand_bridges_detect_orientations(this->fill_surfaces.surfaces, expansion_zones, closing_radius);
if (custom_angle_deg > 0.0 && relative_angle) {
for (Surface &bridge_surface : bridges.surfaces) {
if (bridge_surface.bridge_angle >= 0)
bridge_surface.bridge_angle += custom_angle_rad;
}
}
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done";
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
@ -781,12 +791,18 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// would get merged into a single one while they need different directions
// also, supply the original expolygon instead of the grown one, because in case
// of very thin (but still working) anchors, the grown expolygon would go beyond them
double custom_angle = Geometry::deg2rad(this->region().config().bridge_angle.value);
if (custom_angle > 0.0) {
bridges[idx_last].bridge_angle = custom_angle;
// ORCA: Relative/Align Bridge Angle
const auto &region_config = this->region().config();
const double custom_angle_deg = region_config.bridge_angle.value;
const bool relative_angle = region_config.relative_bridge_angle.value;
const double custom_angle_rad = Geometry::deg2rad(custom_angle_deg);
if (custom_angle_deg > 0.0 && !relative_angle) {
bridges[idx_last].bridge_angle = custom_angle_rad;
} else {
auto [bridging_dir, unsupported_dist] = detect_bridging_direction(to_polygons(initial), to_polygons(lower_layer->lslices));
bridges[idx_last].bridge_angle = PI + std::atan2(bridging_dir.y(), bridging_dir.x());
if (custom_angle_deg > 0.0 && relative_angle)
bridges[idx_last].bridge_angle += custom_angle_rad;
}
/*

View file

@ -1729,7 +1729,11 @@ void PerimeterGenerator::process_no_bridge(Surfaces& all_surfaces, coord_t perim
BridgeDetector detector{ unsupported,
lower_island.expolygons,
perimeter_spacing };
if (detector.detect_angle(Geometry::deg2rad(this->config->bridge_angle.value)))
// ORCA: Relative/Align Bridge Angle
const double custom_angle_deg = this->config->bridge_angle.value;
const bool relative_angle = this->config->relative_bridge_angle.value;
const double detect_angle_rad = (custom_angle_deg > 0.0 && !relative_angle) ? Geometry::deg2rad(custom_angle_deg) : 0.0;
if (detector.detect_angle(detect_angle_rad))
expolygons_append(bridgeable, union_ex(detector.coverage(-1, true)));
}
if (!bridgeable.empty()) {

View file

@ -936,7 +936,7 @@ static std::vector<std::string> s_Preset_print_options {
"timelapse_type",
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "min_length_factor",
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle","internal_bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface",
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle","internal_bridge_angle", "relative_bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface",
"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk","default_junction_deviation",
"top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer", "print_flow_ratio", "seam_gap",
"set_other_flow_ratios", "first_layer_flow_ratio", "outer_wall_flow_ratio", "inner_wall_flow_ratio", "overhang_flow_ratio", "sparse_infill_flow_ratio", "internal_solid_infill_flow_ratio", "gap_fill_flow_ratio", "support_flow_ratio", "support_interface_flow_ratio",

View file

@ -1158,11 +1158,16 @@ void PrintConfigDef::init_fff_params()
def->label = L("External bridge infill direction");
def->category = L("Strength");
// xgettext:no-c-format, no-boost-format
def->tooltip = L("Bridging angle override. If left to zero, the bridging angle will be calculated "
"automatically. Otherwise the provided angle will be used for external bridges. "
"Use 180° for zero angle.");
def->tooltip = L("External Bridging angle override.\n"
"If left to zero, the bridging angle will be calculated automatically for each specific bridge.\n"
"Otherwise the provided angle will be used according to:\n"
" - The absolute coordinates \n"
" - The absolute coordinate + Model rotation: If Align infill direction to model is enabled\n"
" - The optimal automatic angle + this value: If 'Relative Bridge Angle' is enabled\n\n"
"Use 180° for zero absolute angle.");
def->sidetext = u8"°"; // degrees, don't need translation
def->min = 0;
def->max = 180;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.));
@ -1170,14 +1175,28 @@ void PrintConfigDef::init_fff_params()
def = this->add("internal_bridge_angle", coFloat);
def->label = L("Internal bridge infill direction");
def->category = L("Strength");
def->tooltip = L("Internal bridging angle override. If left to zero, the bridging angle will be calculated "
"automatically. Otherwise the provided angle will be used for internal bridges. "
"Use 180° for zero angle.\n\nIt is recommended to leave it at 0 unless there is a specific model need not to.");
def->tooltip = L("Internal Bridging angle override.\n"
"If left to zero, the bridging angle will be calculated automatically for each specific bridge.\n"
"Otherwise the provided angle will be used according to:\n"
" - The absolute coordinates \n"
" - The absolute coordinate + Model rotation: If Align infill direction to model is enabled\n"
" - The optimal automatic angle + this value: If 'Relative Bridge Angle' is enabled\n\n"
"Use 180° for zero absolute angle.");
def->sidetext = u8"°"; // degrees, don't need translation
def->min = 0;
def->max = 180;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.));
// ORCA: Relative bridge angle
def = this->add("relative_bridge_angle", coBool);
def->label = L("Relative bridge angle");
def->category = L("Strength");
def->tooltip = L("When enabled, the bridge angle values are added to the automatically calculated bridge direction instead of overriding it.\n"
"Recommended to add a small (<10°) to improve bridge covering in closed shapes.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("bridge_density", coPercent);
def->label = L("External bridge density");
def->category = L("Strength");
@ -2785,7 +2804,8 @@ void PrintConfigDef::init_fff_params()
def = this->add("align_infill_direction_to_model", coBool);
def->label = L("Align infill direction to model");
def->category = L("Strength");
def->tooltip = L("Aligns infill and surface fill directions to follow the model's orientation on the build plate. When enabled, fill directions rotate with the model to maintain optimal strength characteristics.");
def->tooltip = L("Aligns infill, bridge, ironing and surface fill directions to follow the model's orientation on the build plate.\n"
"When enabled, directions rotate with the model to maintain optimal strength characteristics.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));

View file

@ -1041,6 +1041,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, bottom_shell_thickness))
((ConfigOptionFloat, bridge_angle))
((ConfigOptionFloat, internal_bridge_angle)) // ORCA: Internal bridge angle override
((ConfigOptionBool, relative_bridge_angle)) // ORCA: Relative bridge angle flag
((ConfigOptionFloat, bridge_flow))
((ConfigOptionFloat, internal_bridge_flow))
((ConfigOptionFloat, bridge_speed))

View file

@ -1208,6 +1208,7 @@ bool PrintObject::invalidate_state_by_config_options(
|| opt_key == "ensure_vertical_shell_thickness"
|| opt_key == "bridge_angle"
|| opt_key == "internal_bridge_angle" // ORCA: Internal bridge angle override
|| opt_key == "relative_bridge_angle" // ORCA: Relative bridge angle
//BBS
|| opt_key == "bridge_density"
|| opt_key == "internal_bridge_density") {
@ -3017,8 +3018,14 @@ void PrintObject::bridge_over_infill()
}
// ORCA: Internal bridge angle override
if (candidate.region->region().config().internal_bridge_angle > 0)
bridging_angle = candidate.region->region().config().internal_bridge_angle.value * PI / 180.0; // Convert degrees to radians
if (candidate.region->region().config().internal_bridge_angle.value > 0) {
const auto &region_config = candidate.region->region().config();
const double custom_angle_rad = Geometry::deg2rad(region_config.internal_bridge_angle.value);
if (region_config.relative_bridge_angle.value)
bridging_angle += custom_angle_rad;
else
bridging_angle = custom_angle_rad;
}
boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
if (!lightning_area.empty() && !intersection(area_to_be_bridge, lightning_area).empty()) {

View file

@ -653,7 +653,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_field("bottom_surface_density", has_bottom_shell);
for (auto el : { "infill_direction", "sparse_infill_line_width", "gap_fill_target","filter_out_gap_fill","infill_wall_overlap",
"sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle", "internal_bridge_angle",
"sparse_infill_speed", "bridge_speed", "internal_bridge_speed", "bridge_angle", "internal_bridge_angle", "relative_bridge_angle",
"solid_infill_direction", "solid_infill_rotate_template", "internal_solid_infill_pattern", "solid_infill_filament",
})
toggle_field(el, have_infill || has_solid_infill);

View file

@ -109,7 +109,7 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::PART_CAT
{"sparse_infill_density", "",1},{"sparse_infill_pattern", "",1},{"lateral_lattice_angle_1", "",1},{"lateral_lattice_angle_2", "",1},{"infill_overhang_angle", "",1},{"infill_anchor", "",1},{"infill_anchor_max", "",1},{"top_surface_pattern", "",1},{"bottom_surface_pattern", "",1}, {"internal_solid_infill_pattern", "",1},
{"align_infill_direction_to_model", "", 1},
{"extra_solid_infills", "", 1},
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
{"infill_combination", "",1}, {"infill_combination_max_layer_height", "",1}, {"infill_wall_overlap", "",1},{"top_bottom_infill_wall_overlap", "",1}, {"solid_infill_direction", "",1}, {"infill_direction", "",1}, {"bridge_angle", "",1}, {"internal_bridge_angle", "",1}, {"relative_bridge_angle", "",1}, {"minimum_sparse_infill_area", "",1}
}},
{ L("Speed"), {{"outer_wall_speed", "",1},{"inner_wall_speed", "",2},{"sparse_infill_speed", "",3},{"top_surface_speed", "",4}, {"internal_solid_infill_speed", "",5},
{"enable_overhang_speed", "",6}, {"overhang_1_4_speed", "",7}, {"overhang_2_4_speed", "",8}, {"overhang_3_4_speed", "",9}, {"overhang_4_4_speed", "",10},

View file

@ -2451,6 +2451,7 @@ void TabPrint::build()
optgroup->append_single_option_line("extra_solid_infills", "strength_settings_infill#extra-solid-infill");
optgroup->append_single_option_line("bridge_angle", "strength_settings_advanced#bridge-infill-direction");
optgroup->append_single_option_line("internal_bridge_angle", "strength_settings_advanced#bridge-infill-direction"); // ORCA: Internal bridge angle override
optgroup->append_single_option_line("relative_bridge_angle", "strength_settings_advanced#bridge-infill-direction");
optgroup->append_single_option_line("minimum_sparse_infill_area", "strength_settings_advanced#minimum-sparse-infill-threshold");
optgroup->append_single_option_line("infill_combination", "strength_settings_advanced#infill-combination");
optgroup->append_single_option_line("infill_combination_max_layer_height", "strength_settings_advanced#max-layer-height");