mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-12 03:27:55 +00:00
feat(orient): auto-orient the largest overhang toward the cooling fan
New printer option fan_direction (undefine/left/right/both, default undefine) declares which side the auxiliary part-cooling airflow comes from. When set and the printer has an auxiliary fan, auto-orient adds a yaw rotation so the dominant overhang area faces the airflow, and newly added primitive shapes are pre-oriented the same way (except the Cube, whose axis-aligned bounding box the pressure-advance pattern calibration depends on). - FanDirection enum + fan_direction printer option (Accessory group, enabled only with auxiliary_fan) - orient engine: weighted overhang areas per candidate, yaw-direction search, vertical rotation applied on top of the primary orientation; the cooling weights are taken from the candidate actually chosen, including the flat-bottom tie-break - orient_for_cooling() for primitive placement - set fan_direction=left on H2C/H2D/H2D Pro/X1/X1E/P1S 0.4 profiles (X1C/H2S/P2S/X2D/Qidi X-Max 4 already carried the key, which now takes effect) With fan_direction unset or no auxiliary fan the vertical rotation stays identity and auto-orient results are unchanged; slicing and g-code are never affected.
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
|
||||
#include "slic3r/Utils/FixModelByCgal.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
#include "libslic3r/Orient.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
@@ -2560,6 +2561,15 @@ void ObjectList::load_shape_object(const std::string &type_name)
|
||||
// Create mesh
|
||||
BoundingBoxf3 bb;
|
||||
TriangleMesh mesh = create_mesh(type_name, bb);
|
||||
// Rotate the largest overhang area toward the part cooling fan so new shapes start in a
|
||||
// cooling friendly orientation. Skip the plain cube: the pressure advance pattern
|
||||
// calibration reuses it as an axis-aligned anchor and scales it by its bounding box,
|
||||
// so its orientation must stay fixed.
|
||||
const Slic3r::DynamicPrintConfig& full_config = wxGetApp().preset_bundle->full_config();
|
||||
if (type_name != "Cube" && full_config.has("fan_direction") && full_config.has("auxiliary_fan")) {
|
||||
FanDirection config_dir = full_config.option<ConfigOptionEnum<FanDirection>>("fan_direction")->value;
|
||||
orientation::orient_for_cooling(mesh, config_dir);
|
||||
}
|
||||
// BBS: remove "Shape" prefix
|
||||
load_mesh_object(mesh, _(type_name));
|
||||
wxGetApp().mainframe->update_title();
|
||||
|
||||
@@ -229,15 +229,32 @@ orientation::OrientMesh OrientJob::get_orient_mesh(ModelInstance* instance)
|
||||
auto obj = instance->get_object();
|
||||
om.name = obj->name;
|
||||
om.mesh = obj->mesh(); // don't know the difference to obj->raw_mesh(). Both seem OK
|
||||
const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
|
||||
if (obj->config.has("support_threshold_angle"))
|
||||
om.overhang_angle = obj->config.opt_int("support_threshold_angle");
|
||||
else {
|
||||
const Slic3r::DynamicPrintConfig& config = wxGetApp().preset_bundle->full_config();
|
||||
om.overhang_angle = config.opt_int("support_threshold_angle");
|
||||
}
|
||||
|
||||
if (config.has("fan_direction") && config.has("auxiliary_fan")) {
|
||||
FanDirection config_dir = config.option<ConfigOptionEnum<FanDirection>>("fan_direction")->value;
|
||||
if (config_dir == FanDirection::fdUndefine || !config.opt_bool("auxiliary_fan")) {
|
||||
// no part cooling airflow to face, keep the orientation around the z axis unchanged
|
||||
om.cooling_direction = {0, 0, 0};
|
||||
} else if (config_dir == FanDirection::fdRight) {
|
||||
// the part cooling airflow comes from the right side
|
||||
om.cooling_direction = {1, 0, 0};
|
||||
om.has_cooling_fan = true;
|
||||
} else {
|
||||
// the part cooling airflow comes from the left side, or from both sides
|
||||
om.cooling_direction = {-1, 0, 0};
|
||||
om.has_cooling_fan = true;
|
||||
}
|
||||
}
|
||||
|
||||
om.setter = [instance](const OrientMesh& p) {
|
||||
instance->rotate(p.rotation_matrix);
|
||||
instance->rotate(p.rotation_matrix_vertical);
|
||||
instance->get_object()->invalidate_bounding_box();
|
||||
instance->get_object()->ensure_on_bed();
|
||||
};
|
||||
|
||||
@@ -4956,6 +4956,7 @@ void TabPrinter::build_fff()
|
||||
optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type");
|
||||
optgroup->append_single_option_line("nozzle_hrc", "printer_basic_information_accessory#nozzle-hrc");
|
||||
optgroup->append_single_option_line("auxiliary_fan", "printer_basic_information_accessory#auxiliary-part-cooling-fan");
|
||||
optgroup->append_single_option_line("fan_direction");
|
||||
optgroup->append_single_option_line("support_chamber_temp_control", "printer_basic_information_accessory#support-controlling-chamber-temperature");
|
||||
optgroup->append_single_option_line("support_air_filtration", "printer_basic_information_accessory#support-air-filtration");
|
||||
|
||||
@@ -5892,6 +5893,8 @@ void TabPrinter::toggle_options()
|
||||
|
||||
const bool support_parallel_printheads = printer_cfg.opt_bool("support_parallel_printheads");
|
||||
toggle_line("parallel_printheads_count", support_parallel_printheads);
|
||||
|
||||
toggle_line("fan_direction", m_config->opt_bool("auxiliary_fan"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user