mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-11 19:17:33 +00:00
stage in changes from off-plate-gravity and remove stuff I didn't need
This commit is contained in:
committed by
Joseph Robertson
parent
0a762dfede
commit
08aa277974
@@ -26,6 +26,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -71,8 +72,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// z component of normal vector in world coordinate used for slope shading
|
// dot product of world normal with up direction, used for slope shading
|
||||||
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ void main()
|
|||||||
color = LightBlue;
|
color = LightBlue;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
}
|
}
|
||||||
else if( transformed_normal.z < slope.normal_z - EPSILON)
|
else if( dot(transformed_normal, slope.up_direction) < slope.normal_z - EPSILON)
|
||||||
{
|
{
|
||||||
color = color * 0.5 + LightRed * 0.5;
|
color = color * 0.5 + LightRed * 0.5;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform vec4 uniform_color;
|
uniform vec4 uniform_color;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform mat4 view_model_matrix;
|
uniform mat4 view_model_matrix;
|
||||||
@@ -71,8 +72,8 @@ void main()
|
|||||||
// Point in homogenous coordinates.
|
// Point in homogenous coordinates.
|
||||||
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
world_pos = volume_world_matrix * vec4(v_position, 1.0);
|
||||||
|
|
||||||
// z component of normal vector in world coordinate used for slope shading
|
// dot product of world normal with up direction, used for slope shading
|
||||||
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * v_normal)).z : 0.0;
|
world_normal_z = slope.actived ? dot(normalize(slope.volume_world_normal_matrix * v_normal), slope.up_direction) : 0.0;
|
||||||
|
|
||||||
gl_Position = projection_matrix * position;
|
gl_Position = projection_matrix * position;
|
||||||
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ void main()
|
|||||||
color = LightBlue;
|
color = LightBlue;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
}
|
}
|
||||||
else if( transformed_normal.z < slope.normal_z - EPSILON)
|
else if( dot(transformed_normal, slope.up_direction) < slope.normal_z - EPSILON)
|
||||||
{
|
{
|
||||||
color = color * 0.5 + LightRed * 0.5;
|
color = color * 0.5 + LightRed * 0.5;
|
||||||
alpha = 1.0;
|
alpha = 1.0;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct SlopeDetection
|
|||||||
bool actived;
|
bool actived;
|
||||||
float normal_z;
|
float normal_z;
|
||||||
mat3 volume_world_normal_matrix;
|
mat3 volume_world_normal_matrix;
|
||||||
|
vec3 up_direction;
|
||||||
};
|
};
|
||||||
uniform SlopeDetection slope;
|
uniform SlopeDetection slope;
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
@@ -377,6 +377,11 @@ inline void translate(ExPolygons &expolys, const Point &p) {
|
|||||||
expoly.translate(p);
|
expoly.translate(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void translate(Polygons &polys, const Point &p) {
|
||||||
|
for (Polygon &poly : polys)
|
||||||
|
poly.translate(p);
|
||||||
|
}
|
||||||
|
|
||||||
inline void polygons_append(Polygons &dst, const ExPolygon &src)
|
inline void polygons_append(Polygons &dst, const ExPolygon &src)
|
||||||
{
|
{
|
||||||
dst.reserve(dst.size() + src.holes.size() + 1);
|
dst.reserve(dst.size() + src.holes.size() + 1);
|
||||||
|
|||||||
@@ -1010,7 +1010,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
|
|||||||
|
|
||||||
static std::vector<std::string> s_Preset_printer_options {
|
static std::vector<std::string> s_Preset_printer_options {
|
||||||
"printer_technology",
|
"printer_technology",
|
||||||
"printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
|
"printable_area", "extruder_printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "build_plate_tilt_x", "build_plate_tilt_y", "gcode_flavor",
|
||||||
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
|
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
|
||||||
"single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
|
"single_extruder_multi_material", "manual_filament_change", "file_start_gcode", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "printing_by_object_gcode", "layer_change_gcode", "time_lapse_gcode", "wrapping_detection_gcode", "change_filament_gcode", "change_extrusion_role_gcode",
|
||||||
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
|
"printer_model", "printer_variant", "printer_extruder_id", "printer_extruder_variant", "extruder_variant_list", "default_nozzle_volume_type",
|
||||||
|
|||||||
@@ -5918,6 +5918,30 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comSimple;
|
def->mode = comSimple;
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(50., true));
|
def->set_default_value(new ConfigOptionFloatOrPercent(50., true));
|
||||||
|
|
||||||
|
def = this->add("build_plate_tilt_x", coFloat);
|
||||||
|
def->label = L("Build plate tilt X");
|
||||||
|
def->category = L("Support");
|
||||||
|
def->tooltip = L("Tilt angle of the build plate along the X axis. "
|
||||||
|
"A positive value tilts the plate so the +X side is higher, shifting gravity toward -X and increasing overhangs on the +X side. "
|
||||||
|
"A negative value tilts the -X side higher. Set to 0 for no X-axis tilt.");
|
||||||
|
def->sidetext = u8"\u00B0";
|
||||||
|
def->min = -45;
|
||||||
|
def->max = 45;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.));
|
||||||
|
|
||||||
|
def = this->add("build_plate_tilt_y", coFloat);
|
||||||
|
def->label = L("Build plate tilt Y");
|
||||||
|
def->category = L("Support");
|
||||||
|
def->tooltip = L("Tilt angle of the build plate along the Y axis. "
|
||||||
|
"A positive value tilts the plate so the +Y side is higher, shifting gravity toward -Y and increasing overhangs on the +Y side. "
|
||||||
|
"A negative value tilts the -Y side higher. Set to 0 for no Y-axis tilt.");
|
||||||
|
def->sidetext = u8"\u00B0";
|
||||||
|
def->min = -45;
|
||||||
|
def->max = 45;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloat(0.));
|
||||||
|
|
||||||
def = this->add("tree_support_branch_angle", coFloat);
|
def = this->add("tree_support_branch_angle", coFloat);
|
||||||
def->label = L("Tree support branch angle");
|
def->label = L("Tree support branch angle");
|
||||||
def->category = L("Support");
|
def->category = L("Support");
|
||||||
|
|||||||
@@ -1410,6 +1410,9 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
|||||||
PrintConfig,
|
PrintConfig,
|
||||||
(MachineEnvelopeConfig, GCodeConfig),
|
(MachineEnvelopeConfig, GCodeConfig),
|
||||||
|
|
||||||
|
// Build plate tilt for off-axis gravity support generation (printer-level setting).
|
||||||
|
((ConfigOptionFloat, build_plate_tilt_x))
|
||||||
|
((ConfigOptionFloat, build_plate_tilt_y))
|
||||||
//BBS
|
//BBS
|
||||||
((ConfigOptionInts, additional_cooling_fan_speed))
|
((ConfigOptionInts, additional_cooling_fan_speed))
|
||||||
((ConfigOptionBool, reduce_crossing_wall))
|
((ConfigOptionBool, reduce_crossing_wall))
|
||||||
|
|||||||
@@ -1392,6 +1392,10 @@ static inline ExPolygons detect_overhangs(
|
|||||||
const double threshold_rad = Geometry::deg2rad(thresh_angle);
|
const double threshold_rad = Geometry::deg2rad(thresh_angle);
|
||||||
const bool bridge_no_support = object_config.bridge_no_support.value;
|
const bool bridge_no_support = object_config.bridge_no_support.value;
|
||||||
const coordf_t xy_expansion = scale_(object_config.support_expansion.value);
|
const coordf_t xy_expansion = scale_(object_config.support_expansion.value);
|
||||||
|
// Build plate tilt: compute per-layer XY shift for tilted gravity direction
|
||||||
|
const double tilt_x_rad = Geometry::deg2rad(print_config.build_plate_tilt_x.value);
|
||||||
|
const double tilt_y_rad = Geometry::deg2rad(print_config.build_plate_tilt_y.value);
|
||||||
|
const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON;
|
||||||
float lower_layer_offset = 0;
|
float lower_layer_offset = 0;
|
||||||
|
|
||||||
if (layer_id == 0)
|
if (layer_id == 0)
|
||||||
@@ -1441,9 +1445,17 @@ static inline ExPolygons detect_overhangs(
|
|||||||
// Overhang polygons for this layer and region.
|
// Overhang polygons for this layer and region.
|
||||||
Polygons diff_polygons;
|
Polygons diff_polygons;
|
||||||
Polygons layerm_polygons = to_polygons(layerm->slices.surfaces);
|
Polygons layerm_polygons = to_polygons(layerm->slices.surfaces);
|
||||||
|
// Apply build plate tilt: shift lower layer polygons to simulate tilted gravity
|
||||||
|
Polygons effective_lower = lower_layer_polygons;
|
||||||
|
if (has_tilt) {
|
||||||
|
const double lh = lower_layer.height;
|
||||||
|
Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))),
|
||||||
|
coord_t(scale_(lh * tan(tilt_x_rad))));
|
||||||
|
translate(effective_lower, tilt_shift);
|
||||||
|
}
|
||||||
if (lower_layer_offset == 0.f) {
|
if (lower_layer_offset == 0.f) {
|
||||||
// Support everything.
|
// Support everything.
|
||||||
diff_polygons = diff(layerm_polygons, lower_layer_polygons);
|
diff_polygons = diff(layerm_polygons, effective_lower);
|
||||||
if (buildplate_only) {
|
if (buildplate_only) {
|
||||||
// Don't support overhangs above the top surfaces.
|
// Don't support overhangs above the top surfaces.
|
||||||
// This step is done before the contact surface is calculated by growing the overhang region.
|
// This step is done before the contact surface is calculated by growing the overhang region.
|
||||||
@@ -1452,9 +1464,9 @@ static inline ExPolygons detect_overhangs(
|
|||||||
} else if (auto_normal_support) {
|
} else if (auto_normal_support) {
|
||||||
// Get the regions needing a suport, collapse very tiny spots.
|
// Get the regions needing a suport, collapse very tiny spots.
|
||||||
//FIXME cache the lower layer offset if this layer has multiple regions.
|
//FIXME cache the lower layer offset if this layer has multiple regions.
|
||||||
diff_polygons =
|
diff_polygons =
|
||||||
diff(layerm_polygons,
|
diff(layerm_polygons,
|
||||||
expand(lower_layer_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
expand(effective_lower, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
|
||||||
if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) {
|
if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) {
|
||||||
// Don't support overhangs above the top surfaces.
|
// Don't support overhangs above the top surfaces.
|
||||||
// This step is done before the contact surface is calculated by growing the overhang region.
|
// This step is done before the contact surface is calculated by growing the overhang region.
|
||||||
@@ -1462,9 +1474,9 @@ static inline ExPolygons detect_overhangs(
|
|||||||
}
|
}
|
||||||
if (! diff_polygons.empty()) {
|
if (! diff_polygons.empty()) {
|
||||||
// Offset the support regions back to a full overhang, restrict them to the full overhang.
|
// Offset the support regions back to a full overhang, restrict them to the full overhang.
|
||||||
// This is done to increase size of the supporting columns below, as they are calculated by
|
// This is done to increase size of the supporting columns below, as they are calculated by
|
||||||
// propagating these contact surfaces downwards.
|
// propagating these contact surfaces downwards.
|
||||||
diff_polygons = diff(intersection(expand(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), lower_layer_polygons);
|
diff_polygons = diff(intersection(expand(diff_polygons, lower_layer_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS), layerm_polygons), effective_lower);
|
||||||
}
|
}
|
||||||
//FIXME add user defined filtering here based on minimal area or minimum radius or whatever.
|
//FIXME add user defined filtering here based on minimal area or minimum radius or whatever.
|
||||||
|
|
||||||
|
|||||||
@@ -671,6 +671,11 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||||||
double thresh_angle = config.support_threshold_angle.value > EPSILON ? config.support_threshold_angle.value + 1 : 30;
|
double thresh_angle = config.support_threshold_angle.value > EPSILON ? config.support_threshold_angle.value + 1 : 30;
|
||||||
thresh_angle = std::min(thresh_angle, 89.); // should be smaller than 90
|
thresh_angle = std::min(thresh_angle, 89.); // should be smaller than 90
|
||||||
const double threshold_rad = Geometry::deg2rad(thresh_angle);
|
const double threshold_rad = Geometry::deg2rad(thresh_angle);
|
||||||
|
// Build plate tilt: compute per-layer XY shift for tilted gravity direction
|
||||||
|
const PrintConfig& print_cfg = m_object->print()->config();
|
||||||
|
const double tilt_x_rad = Geometry::deg2rad(print_cfg.build_plate_tilt_x.value);
|
||||||
|
const double tilt_y_rad = Geometry::deg2rad(print_cfg.build_plate_tilt_y.value);
|
||||||
|
const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON;
|
||||||
// FIXME this is a fudge constant!
|
// FIXME this is a fudge constant!
|
||||||
double support_tree_tip_diameter = 0.8;
|
double support_tree_tip_diameter = 0.8;
|
||||||
auto enforcer_overhang_offset = scaled<double>(support_tree_tip_diameter);
|
auto enforcer_overhang_offset = scaled<double>(support_tree_tip_diameter);
|
||||||
@@ -813,8 +818,19 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||||||
ExPolygons& curr_polys = layer->lslices_extrudable;
|
ExPolygons& curr_polys = layer->lslices_extrudable;
|
||||||
ExPolygons& lower_polys = lower_layer->lslices_extrudable;
|
ExPolygons& lower_polys = lower_layer->lslices_extrudable;
|
||||||
|
|
||||||
|
// Apply build plate tilt: shift lower layer polygons to simulate tilted gravity
|
||||||
|
ExPolygons shifted_lower;
|
||||||
|
if (has_tilt) {
|
||||||
|
shifted_lower = lower_polys; // copy
|
||||||
|
const double lh = lower_layer->height;
|
||||||
|
Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))),
|
||||||
|
coord_t(scale_(lh * tan(tilt_x_rad))));
|
||||||
|
translate(shifted_lower, tilt_shift);
|
||||||
|
}
|
||||||
|
const ExPolygons &effective_lower = has_tilt ? shifted_lower : lower_polys;
|
||||||
|
|
||||||
// normal overhang
|
// normal overhang
|
||||||
ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
ExPolygons lower_layer_offseted = offset_ex(effective_lower, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS);
|
||||||
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
|
overhangs_all_layers[layer_nr] = std::move(diff_ex(curr_polys, lower_layer_offseted));
|
||||||
|
|
||||||
double duration{ std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
|
double duration{ std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
|
||||||
|
|||||||
@@ -208,6 +208,10 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||||||
const bool support_threshold_auto = support_threshold == 0;
|
const bool support_threshold_auto = support_threshold == 0;
|
||||||
// +1 makes the threshold inclusive
|
// +1 makes the threshold inclusive
|
||||||
double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.);
|
double tan_threshold = support_threshold_auto ? 0. : tan(M_PI * double(support_threshold + 1) / 180.);
|
||||||
|
// Build plate tilt: compute per-layer XY shift for tilted gravity direction
|
||||||
|
const double tilt_x_rad = Geometry::deg2rad(print_config.build_plate_tilt_x.value);
|
||||||
|
const double tilt_y_rad = Geometry::deg2rad(print_config.build_plate_tilt_y.value);
|
||||||
|
const bool has_tilt = std::abs(tilt_x_rad) > EPSILON || std::abs(tilt_y_rad) > EPSILON;
|
||||||
//FIXME this is a fudge constant!
|
//FIXME this is a fudge constant!
|
||||||
auto enforcer_overhang_offset = scaled<double>(config.tree_support_tip_diameter.value);
|
auto enforcer_overhang_offset = scaled<double>(config.tree_support_tip_diameter.value);
|
||||||
const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution;
|
const coordf_t radius_sample_resolution = g_config_tree_support_collision_resolution;
|
||||||
@@ -229,7 +233,7 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||||||
size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size()));
|
size_t num_overhang_layers = support_auto ? num_object_layers : std::min(num_object_layers, std::max(size_t(support_enforce_layers), enforcers_layers.size()));
|
||||||
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
|
tbb::parallel_for(tbb::blocked_range<LayerIndex>(1, num_overhang_layers),
|
||||||
[&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
|
[&print_object, &config, &print_config, &enforcers_layers, &blockers_layers,
|
||||||
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, radius_sample_resolution, &throw_on_cancel, &out]
|
support_auto, support_enforce_layers, support_threshold_auto, tan_threshold, enforcer_overhang_offset, num_raft_layers, radius_sample_resolution, has_tilt, tilt_x_rad, tilt_y_rad, &throw_on_cancel, &out]
|
||||||
(const tbb::blocked_range<LayerIndex> &range) {
|
(const tbb::blocked_range<LayerIndex> &range) {
|
||||||
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
for (LayerIndex layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||||
const Layer ¤t_layer = *print_object.get_layer(layer_id);
|
const Layer ¤t_layer = *print_object.get_layer(layer_id);
|
||||||
@@ -253,7 +257,15 @@ static std::vector<std::pair<TreeSupportSettings, std::vector<size_t>>> group_me
|
|||||||
lower_layer_offset = external_perimeter_width - float(scale_(config.support_threshold_overlap.get_abs_value(unscale_(external_perimeter_width))));
|
lower_layer_offset = external_perimeter_width - float(scale_(config.support_threshold_overlap.get_abs_value(unscale_(external_perimeter_width))));
|
||||||
} else
|
} else
|
||||||
lower_layer_offset = scaled<float>(lower_layer.height / tan_threshold);
|
lower_layer_offset = scaled<float>(lower_layer.height / tan_threshold);
|
||||||
Polygons lower_layer_offseted = offset(lower_layer.lslices_extrudable, lower_layer_offset);
|
// Apply build plate tilt: shift lower layer polygons to simulate tilted gravity
|
||||||
|
Polygons lower_src = to_polygons(lower_layer.lslices_extrudable);
|
||||||
|
if (has_tilt) {
|
||||||
|
const double lh = lower_layer.height;
|
||||||
|
Point tilt_shift(coord_t(scale_(lh * tan(tilt_y_rad))),
|
||||||
|
coord_t(scale_(lh * tan(tilt_x_rad))));
|
||||||
|
translate(lower_src, tilt_shift);
|
||||||
|
}
|
||||||
|
Polygons lower_layer_offseted = offset(lower_src, lower_layer_offset);
|
||||||
overhangs = diff(current_layer.lslices_extrudable, lower_layer_offseted);
|
overhangs = diff(current_layer.lslices_extrudable, lower_layer_offseted);
|
||||||
if (lower_layer_offset == 0) {
|
if (lower_layer_offset == 0) {
|
||||||
raw_overhangs = overhangs;
|
raw_overhangs = overhangs;
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ int TriangleSelector::select_unsplit_triangle(const Vec3f &hit, int facet_idx) c
|
|||||||
return this->select_unsplit_triangle(hit, facet_idx, neighbors);
|
return this->select_unsplit_triangle(hit, facet_idx, neighbors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleSelector::select_patch(int facet_start, std::unique_ptr<Cursor> &&cursor, EnforcerBlockerType new_state, const Transform3d& trafo_no_translate, bool triangle_splitting, float highlight_by_angle_deg)
|
void TriangleSelector::select_patch(int facet_start, std::unique_ptr<Cursor> &&cursor, EnforcerBlockerType new_state, const Transform3d& trafo_no_translate, bool triangle_splitting, float highlight_by_angle_deg, const Vec3f &up_direction)
|
||||||
{
|
{
|
||||||
assert(facet_start < m_orig_size_indices);
|
assert(facet_start < m_orig_size_indices);
|
||||||
|
|
||||||
@@ -294,8 +294,8 @@ void TriangleSelector::select_patch(int facet_start, std::unique_ptr<Cursor> &&c
|
|||||||
int facet = facets_to_check[facet_idx];
|
int facet = facets_to_check[facet_idx];
|
||||||
const Vec3f& facet_normal = m_face_normals[m_triangles[facet].source_triangle];
|
const Vec3f& facet_normal = m_face_normals[m_triangles[facet].source_triangle];
|
||||||
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
||||||
float world_normal_z = (normal_matrix* facet_normal).normalized().z();
|
float world_normal_dot = (normal_matrix * facet_normal).normalized().dot(up_direction);
|
||||||
if (!visited[facet] && (highlight_by_angle_deg == 0.f || world_normal_z < highlight_angle_limit)) {
|
if (!visited[facet] && (highlight_by_angle_deg == 0.f || world_normal_dot < highlight_angle_limit)) {
|
||||||
if (select_triangle(facet, new_state, triangle_splitting)) {
|
if (select_triangle(facet, new_state, triangle_splitting)) {
|
||||||
// add neighboring facets to list to be processed later
|
// add neighboring facets to list to be processed later
|
||||||
for (int neighbor_idx : m_neighbors[facet])
|
for (int neighbor_idx : m_neighbors[facet])
|
||||||
@@ -320,7 +320,7 @@ bool TriangleSelector::is_facet_clipped(int facet_idx, const ClippingPlane &clp)
|
|||||||
|
|
||||||
void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, const Transform3d& trafo_no_translate,
|
void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_start, const Transform3d& trafo_no_translate,
|
||||||
const ClippingPlane &clp, float seed_fill_angle, float highlight_by_angle_deg,
|
const ClippingPlane &clp, float seed_fill_angle, float highlight_by_angle_deg,
|
||||||
bool force_reselection)
|
bool force_reselection, const Vec3f &up_direction)
|
||||||
{
|
{
|
||||||
assert(facet_start < m_orig_size_indices);
|
assert(facet_start < m_orig_size_indices);
|
||||||
|
|
||||||
@@ -344,8 +344,8 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st
|
|||||||
|
|
||||||
const Vec3f &facet_normal = m_face_normals[m_triangles[current_facet].source_triangle];
|
const Vec3f &facet_normal = m_face_normals[m_triangles[current_facet].source_triangle];
|
||||||
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
||||||
float world_normal_z = (normal_matrix * facet_normal).normalized().z();
|
float world_normal_dot = (normal_matrix * facet_normal).normalized().dot(up_direction);
|
||||||
if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || world_normal_z < highlight_angle_limit)) {
|
if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || world_normal_dot < highlight_angle_limit)) {
|
||||||
if (m_triangles[current_facet].is_split()) {
|
if (m_triangles[current_facet].is_split()) {
|
||||||
for (int split_triangle_idx = 0; split_triangle_idx <= m_triangles[current_facet].number_of_split_sides(); ++split_triangle_idx) {
|
for (int split_triangle_idx = 0; split_triangle_idx <= m_triangles[current_facet].number_of_split_sides(); ++split_triangle_idx) {
|
||||||
assert(split_triangle_idx < int(m_triangles[current_facet].children.size()));
|
assert(split_triangle_idx < int(m_triangles[current_facet].children.size()));
|
||||||
|
|||||||
@@ -308,7 +308,8 @@ public:
|
|||||||
EnforcerBlockerType new_state, // enforcer or blocker?
|
EnforcerBlockerType new_state, // enforcer or blocker?
|
||||||
const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation
|
const Transform3d &trafo_no_translate, // matrix to get from mesh to world without translation
|
||||||
bool triangle_splitting, // If triangles will be split base on the cursor or not
|
bool triangle_splitting, // If triangles will be split base on the cursor or not
|
||||||
float highlight_by_angle_deg = 0.f); // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees.
|
float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees.
|
||||||
|
const Vec3f &up_direction = Vec3f::UnitZ()); // Up direction for overhang detection (accounts for build plate tilt)
|
||||||
|
|
||||||
void seed_fill_select_triangles(const Vec3f &hit, // point where to start
|
void seed_fill_select_triangles(const Vec3f &hit, // point where to start
|
||||||
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
|
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
|
||||||
@@ -316,7 +317,8 @@ public:
|
|||||||
const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only
|
const ClippingPlane &clp, // Clipping plane to limit painting to not clipped facets only
|
||||||
float seed_fill_angle, // the maximal angle between two facets to be painted by the same color
|
float seed_fill_angle, // the maximal angle between two facets to be painted by the same color
|
||||||
float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees.
|
float highlight_by_angle_deg = 0.f, // The maximal angle of overhang. If it is set to a non-zero value, it is possible to paint only the triangles of overhang defined by this angle in degrees.
|
||||||
bool force_reselection = false); // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle
|
bool force_reselection = false, // force reselection of the triangle mesh even in cases that mouse is pointing on the selected triangle
|
||||||
|
const Vec3f &up_direction = Vec3f::UnitZ()); // Up direction for overhang detection (accounts for build plate tilt)
|
||||||
|
|
||||||
void bucket_fill_select_triangles(const Vec3f &hit, // point where to start
|
void bucket_fill_select_triangles(const Vec3f &hit, // point where to start
|
||||||
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
|
int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to
|
||||||
|
|||||||
@@ -394,6 +394,8 @@ void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix,
|
|||||||
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom); break; }
|
case Type::Custom: { render_custom(canvas, view_matrix, projection_matrix, bottom); break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render_gravity_arrow(view_matrix, projection_matrix);
|
||||||
|
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,6 +733,63 @@ void Bed3D::render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, co
|
|||||||
render_texture(bottom, canvas);*/
|
render_texture(bottom, canvas);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bed3D::render_gravity_arrow(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
double tilt_x_deg = cfg.opt_float("build_plate_tilt_x");
|
||||||
|
double tilt_y_deg = cfg.opt_float("build_plate_tilt_y");
|
||||||
|
if (tilt_x_deg == 0. && tilt_y_deg == 0.) {
|
||||||
|
m_gravity_arrow.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gravity direction (matching the slicer's tilt convention)
|
||||||
|
double tilt_x_rad = Geometry::deg2rad(tilt_x_deg);
|
||||||
|
double tilt_y_rad = Geometry::deg2rad(tilt_y_deg);
|
||||||
|
Vec3d gravity_dir = Vec3d(-tan(tilt_y_rad), -tan(tilt_x_rad), -1.0).normalized();
|
||||||
|
|
||||||
|
// Build the arrow model (same dimensions as the axis arrows)
|
||||||
|
if (!m_gravity_arrow.is_initialized()) {
|
||||||
|
const float stem_length = Axes::DefaultStemLength;
|
||||||
|
const float tip_radius = Axes::DefaultTipRadius;
|
||||||
|
const float tip_length = Axes::DefaultTipLength;
|
||||||
|
const float stem_radius = stem_length / 75.f; // same ratio as axis cylinders
|
||||||
|
m_gravity_arrow.init_from(stilized_arrow(16, tip_radius, tip_length, stem_radius, stem_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The arrow model points along +Z by default. Compute rotation to align with gravity_dir.
|
||||||
|
// Rotation axis = cross(+Z, gravity_dir), angle = acos(dot(+Z, gravity_dir))
|
||||||
|
Vec3d from = Vec3d::UnitZ();
|
||||||
|
Vec3d to = gravity_dir;
|
||||||
|
double dot = from.dot(to);
|
||||||
|
Transform3d rot = Transform3d::Identity();
|
||||||
|
if (dot < -0.9999) {
|
||||||
|
// Nearly opposite — rotate 180° around X
|
||||||
|
rot = Eigen::AngleAxisd(M_PI, Vec3d::UnitX()) * rot;
|
||||||
|
} else if (dot < 0.9999) {
|
||||||
|
Vec3d axis = from.cross(to).normalized();
|
||||||
|
double angle = std::acos(std::clamp(dot, -1.0, 1.0));
|
||||||
|
rot = Eigen::AngleAxisd(angle, axis) * rot;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||||
|
if (shader == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
shader->start_using();
|
||||||
|
|
||||||
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
|
Transform3d model_matrix = rot;
|
||||||
|
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * model_matrix);
|
||||||
|
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||||
|
|
||||||
|
m_gravity_arrow.set_color({ 1.0f, 0.85f, 0.0f, 1.0f }); // yellow
|
||||||
|
m_gravity_arrow.render();
|
||||||
|
|
||||||
|
shader->stop_using();
|
||||||
|
}
|
||||||
|
|
||||||
void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
void Bed3D::render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||||
{
|
{
|
||||||
// m_texture.reset();
|
// m_texture.reset();
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ private:
|
|||||||
//GLTexture m_temp_texture;
|
//GLTexture m_temp_texture;
|
||||||
GLModel m_model;
|
GLModel m_model;
|
||||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||||
|
GLModel m_gravity_arrow;
|
||||||
Axes m_axes;
|
Axes m_axes;
|
||||||
|
|
||||||
float m_scale_factor{ 1.0f };
|
float m_scale_factor{ 1.0f };
|
||||||
@@ -177,7 +178,8 @@ private:
|
|||||||
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||||
void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
|
void render_custom(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
|
||||||
void render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
void render_default(bool bottom, const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||||
|
void render_gravity_arrow(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||||
|
|
||||||
// BBS: remove the bed picking logic
|
// BBS: remove the bed picking logic
|
||||||
// void register_raycasters_for_picking(const GLModel::Geometry& geometry, const Transform3d& trafo);
|
// void register_raycasters_for_picking(const GLModel::Geometry& geometry, const Transform3d& trafo);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1078,13 +1078,27 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
|||||||
|
|
||||||
bool enable_support;
|
bool enable_support;
|
||||||
int support_threshold_angle = get_selection_support_threshold_angle(enable_support);
|
int support_threshold_angle = get_selection_support_threshold_angle(enable_support);
|
||||||
|
|
||||||
float normal_z = -::cos(Geometry::deg2rad((float) support_threshold_angle));
|
float normal_z = -::cos(Geometry::deg2rad((float) support_threshold_angle));
|
||||||
|
|
||||||
|
// Compute up direction accounting for build plate tilt
|
||||||
|
Vec3f up_direction = Vec3f::UnitZ();
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& prt_cfg = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
double tilt_x_deg = prt_cfg.opt_float("build_plate_tilt_x");
|
||||||
|
double tilt_y_deg = prt_cfg.opt_float("build_plate_tilt_y");
|
||||||
|
if (tilt_x_deg != 0. || tilt_y_deg != 0.) {
|
||||||
|
double tilt_x_rad = Geometry::deg2rad(tilt_x_deg);
|
||||||
|
double tilt_y_rad = Geometry::deg2rad(tilt_y_deg);
|
||||||
|
up_direction = Vec3f(float(tan(tilt_y_rad)), float(tan(tilt_x_rad)), 1.f).normalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
|
shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
|
||||||
shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
||||||
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
||||||
shader->set_uniform("slope.normal_z", normal_z);
|
shader->set_uniform("slope.normal_z", normal_z);
|
||||||
|
shader->set_uniform("slope.up_direction", up_direction);
|
||||||
|
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
|
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF =
|
|||||||
{ L("Support") , { "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap",
|
{ L("Support") , { "enable_support", "support_type", "support_threshold_angle", "support_threshold_overlap",
|
||||||
"support_base_pattern", "support_on_build_plate_only","support_critical_regions_only",
|
"support_base_pattern", "support_on_build_plate_only","support_critical_regions_only",
|
||||||
"support_remove_small_overhang",
|
"support_remove_small_overhang",
|
||||||
|
"build_plate_tilt_x", "build_plate_tilt_y",
|
||||||
"support_base_pattern_spacing", "support_expansion"}},
|
"support_base_pattern_spacing", "support_expansion"}},
|
||||||
//BBS
|
//BBS
|
||||||
{ L("Flush options") , { "flush_into_infill", "flush_into_objects", "flush_into_support"} }
|
{ L("Flush options") , { "flush_into_infill", "flush_into_objects", "flush_into_support"} }
|
||||||
@@ -94,7 +95,8 @@ std::map<std::string, std::vector<SimpleSettingData>> SettingsFactory::OBJECT_C
|
|||||||
{"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22},
|
{"support_bottom_z_distance", "",19},{"support_top_z_distance", "",20},{"support_base_pattern", "",21},{"support_base_pattern_spacing", "",22},
|
||||||
{"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26},
|
{"support_interface_top_layers", "",23},{"support_interface_bottom_layers", "",24},{"support_interface_spacing", "",25},{"support_bottom_interface_spacing", "",26},
|
||||||
{"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31},
|
{"support_object_xy_distance", "",27}, {"bridge_no_support", "",28},{"max_bridge_length", "",29},{"support_critical_regions_only", "",30},{"support_remove_small_overhang","",31},
|
||||||
{"support_object_first_layer_gap","",32}
|
{"build_plate_tilt_x","",32},{"build_plate_tilt_y","",33},
|
||||||
|
{"support_object_first_layer_gap","",34}
|
||||||
}},
|
}},
|
||||||
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
|
{ L("Speed"), {{"support_speed", "",12}, {"support_interface_speed", "",13}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -537,6 +537,14 @@ int GLGizmoFdmSupports::get_selection_support_threshold_angle()
|
|||||||
return auto_support ? support_threshold_angle : 0;
|
return auto_support ? support_threshold_angle : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<double, double> GLGizmoFdmSupports::get_build_plate_tilt()
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
double tilt_x = cfg.opt_float("build_plate_tilt_x");
|
||||||
|
double tilt_y = cfg.opt_float("build_plate_tilt_y");
|
||||||
|
return {tilt_x, tilt_y};
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
||||||
{
|
{
|
||||||
float threshold = (float(M_PI)/180.f)*threshold_deg;
|
float threshold = (float(M_PI)/180.f)*threshold_deg;
|
||||||
@@ -544,6 +552,12 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
|||||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||||
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
||||||
|
|
||||||
|
// Compute gravity direction accounting for build plate tilt
|
||||||
|
auto [tilt_x_deg, tilt_y_deg] = get_build_plate_tilt();
|
||||||
|
double tilt_x_rad = tilt_x_deg * M_PI / 180.0;
|
||||||
|
double tilt_y_rad = tilt_y_deg * M_PI / 180.0;
|
||||||
|
Vec3d gravity_dir = Vec3d(-tan(tilt_y_rad), -tan(tilt_x_rad), -1.0).normalized();
|
||||||
|
|
||||||
int mesh_id = -1;
|
int mesh_id = -1;
|
||||||
for (const ModelVolume* mv : mo->volumes) {
|
for (const ModelVolume* mv : mo->volumes) {
|
||||||
if (! mv->is_model_part())
|
if (! mv->is_model_part())
|
||||||
@@ -552,10 +566,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
|||||||
++mesh_id;
|
++mesh_id;
|
||||||
|
|
||||||
const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
|
const Transform3d trafo_matrix = mi->get_matrix_no_offset() * mv->get_matrix_no_offset();
|
||||||
Vec3f down = (trafo_matrix.inverse() * (-Vec3d::UnitZ())).cast<float>().normalized();
|
Vec3f down = (trafo_matrix.inverse() * gravity_dir).cast<float>().normalized();
|
||||||
Vec3f limit = (trafo_matrix.inverse() * Vec3d(std::sin(threshold), 0, -std::cos(threshold))).cast<float>().normalized();
|
float dot_limit = std::cos(threshold);
|
||||||
|
|
||||||
float dot_limit = limit.dot(down);
|
|
||||||
|
|
||||||
// Now calculate dot product of vert_direction and facets' normals.
|
// Now calculate dot product of vert_direction and facets' normals.
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ private:
|
|||||||
void select_facets_by_angle(float threshold, bool block);
|
void select_facets_by_angle(float threshold, bool block);
|
||||||
// BBS
|
// BBS
|
||||||
int get_selection_support_threshold_angle();
|
int get_selection_support_threshold_angle();
|
||||||
|
std::pair<double, double> get_build_plate_tilt();
|
||||||
|
|
||||||
int m_support_threshold_angle = -1;
|
int m_support_threshold_angle = -1;
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,18 @@ GLGizmoPainterBase::ClippingPlaneDataWrapper GLGizmoPainterBase::get_clipping_pl
|
|||||||
return clp_data_out;
|
return clp_data_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3f GLGizmoPainterBase::get_tilt_up_direction() const
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
double tilt_x_deg = cfg.opt_float("build_plate_tilt_x");
|
||||||
|
double tilt_y_deg = cfg.opt_float("build_plate_tilt_y");
|
||||||
|
if (tilt_x_deg == 0. && tilt_y_deg == 0.)
|
||||||
|
return Vec3f::UnitZ();
|
||||||
|
double tilt_x_rad = Geometry::deg2rad(tilt_x_deg);
|
||||||
|
double tilt_y_rad = Geometry::deg2rad(tilt_y_deg);
|
||||||
|
return Vec3f(float(tan(tilt_y_rad)), float(tan(tilt_x_rad)), 1.f).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
||||||
{
|
{
|
||||||
auto* shader = wxGetApp().get_shader("mm_gouraud");
|
auto* shader = wxGetApp().get_shader("mm_gouraud");
|
||||||
@@ -119,11 +131,15 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
|||||||
float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg));
|
float normal_z = -::cos(Geometry::deg2rad(m_highlight_by_angle_threshold_deg));
|
||||||
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
|
||||||
|
|
||||||
|
// Compute up direction accounting for build plate tilt
|
||||||
|
Vec3f up_direction = get_tilt_up_direction();
|
||||||
|
|
||||||
shader->set_uniform("volume_world_matrix", trafo_matrix);
|
shader->set_uniform("volume_world_matrix", trafo_matrix);
|
||||||
shader->set_uniform("volume_mirrored", is_left_handed);
|
shader->set_uniform("volume_mirrored", is_left_handed);
|
||||||
shader->set_uniform("slope.actived", m_parent.is_using_slope());
|
shader->set_uniform("slope.actived", m_parent.is_using_slope());
|
||||||
shader->set_uniform("slope.volume_world_normal_matrix", normal_matrix);
|
shader->set_uniform("slope.volume_world_normal_matrix", normal_matrix);
|
||||||
shader->set_uniform("slope.normal_z", normal_z);
|
shader->set_uniform("slope.normal_z", normal_z);
|
||||||
|
shader->set_uniform("slope.up_direction", up_direction);
|
||||||
m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix);
|
m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix);
|
||||||
|
|
||||||
if (is_left_handed)
|
if (is_left_handed)
|
||||||
@@ -691,7 +707,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
mi->get_assemble_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix() :
|
mi->get_assemble_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix() :
|
||||||
mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
|
mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
|
||||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
|
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
|
||||||
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
|
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true, get_tilt_up_direction());
|
||||||
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
|
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
|
||||||
m_seed_fill_last_mesh_id = m_rr.mesh_id;
|
m_seed_fill_last_mesh_id = m_rr.mesh_id;
|
||||||
}
|
}
|
||||||
@@ -803,7 +819,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::SinglePointCursor::cursor_factory(phr.z_world,
|
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::SinglePointCursor::cursor_factory(phr.z_world,
|
||||||
camera_pos, m_cursor_height, trafo_matrix, clp);
|
camera_pos, m_cursor_height, trafo_matrix, clp);
|
||||||
m_triangle_selectors[mesh_idx]->select_patch(int(phr.first_facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate,
|
m_triangle_selectors[mesh_idx]->select_patch(int(phr.first_facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate,
|
||||||
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, get_tilt_up_direction());
|
||||||
|
|
||||||
m_triangle_selectors[mesh_idx]->request_update_render_data(true);
|
m_triangle_selectors[mesh_idx]->request_update_render_data(true);
|
||||||
m_last_mouse_click = _mouse_position;
|
m_last_mouse_click = _mouse_position;
|
||||||
@@ -855,7 +871,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
m_triangle_selectors[mesh_idx]->seed_fill_apply_on_triangles(new_state);
|
m_triangle_selectors[mesh_idx]->seed_fill_apply_on_triangles(new_state);
|
||||||
if (m_tool_type == ToolType::SMART_FILL)
|
if (m_tool_type == ToolType::SMART_FILL)
|
||||||
m_triangle_selectors[mesh_idx]->seed_fill_select_triangles(mesh_hit, facet_idx, trafo_matrix_not_translate, clp, m_smart_fill_angle,
|
m_triangle_selectors[mesh_idx]->seed_fill_select_triangles(mesh_hit, facet_idx, trafo_matrix_not_translate, clp, m_smart_fill_angle,
|
||||||
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
|
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true, get_tilt_up_direction());
|
||||||
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
||||||
// BBS: add infill_angle parameter
|
// BBS: add infill_angle parameter
|
||||||
m_triangle_selectors[mesh_idx]->bucket_fill_select_triangles(mesh_hit, facet_idx, clp, -1.f, false, true);
|
m_triangle_selectors[mesh_idx]->bucket_fill_select_triangles(mesh_hit, facet_idx, clp, -1.f, false, true);
|
||||||
@@ -874,12 +890,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
camera_pos, m_cursor_radius,
|
camera_pos, m_cursor_radius,
|
||||||
m_cursor_type, trafo_matrix, clp);
|
m_cursor_type, trafo_matrix, clp);
|
||||||
m_triangle_selectors[mesh_idx]->select_patch(int(first_position.facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate,
|
m_triangle_selectors[mesh_idx]->select_patch(int(first_position.facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate,
|
||||||
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, get_tilt_up_direction());
|
||||||
} else {
|
} else {
|
||||||
for (auto first_position_it = projected_mouse_positions.cbegin(); first_position_it != projected_mouse_positions.cend() - 1; ++first_position_it) {
|
for (auto first_position_it = projected_mouse_positions.cbegin(); first_position_it != projected_mouse_positions.cend() - 1; ++first_position_it) {
|
||||||
auto second_position_it = first_position_it + 1;
|
auto second_position_it = first_position_it + 1;
|
||||||
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::DoublePointCursor::cursor_factory(first_position_it->mesh_hit, second_position_it->mesh_hit, camera_pos, m_cursor_radius, m_cursor_type, trafo_matrix, clp);
|
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::DoublePointCursor::cursor_factory(first_position_it->mesh_hit, second_position_it->mesh_hit, camera_pos, m_cursor_radius, m_cursor_type, trafo_matrix, clp);
|
||||||
m_triangle_selectors[mesh_idx]->select_patch(int(first_position_it->facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate, m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
m_triangle_selectors[mesh_idx]->select_patch(int(first_position_it->facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate, m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, get_tilt_up_direction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -953,7 +969,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
const TriangleSelector::ClippingPlane &clp = this->get_clipping_plane_in_volume_coordinates(trafo_matrix);
|
const TriangleSelector::ClippingPlane &clp = this->get_clipping_plane_in_volume_coordinates(trafo_matrix);
|
||||||
if (m_tool_type == ToolType::SMART_FILL)
|
if (m_tool_type == ToolType::SMART_FILL)
|
||||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, clp, m_smart_fill_angle,
|
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, clp, m_smart_fill_angle,
|
||||||
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, false, get_tilt_up_direction());
|
||||||
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
||||||
// BBS: add infill_angle parameter
|
// BBS: add infill_angle parameter
|
||||||
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, -1.f, false);
|
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), clp, -1.f, false);
|
||||||
|
|||||||
@@ -281,6 +281,9 @@ protected:
|
|||||||
bool m_paint_on_overhangs_only = false;
|
bool m_paint_on_overhangs_only = false;
|
||||||
float m_highlight_by_angle_threshold_deg = 0.f;
|
float m_highlight_by_angle_threshold_deg = 0.f;
|
||||||
|
|
||||||
|
// Returns the up direction accounting for build plate tilt (default: UnitZ)
|
||||||
|
Vec3f get_tilt_up_direction() const;
|
||||||
|
|
||||||
GLModel m_circle;
|
GLModel m_circle;
|
||||||
Vec2d m_old_center{ Vec2d::Zero() };
|
Vec2d m_old_center{ Vec2d::Zero() };
|
||||||
float m_old_cursor_radius{ 0.0f };
|
float m_old_cursor_radius{ 0.0f };
|
||||||
|
|||||||
@@ -4364,6 +4364,8 @@ void TabPrinter::build_fff()
|
|||||||
optgroup->append_single_option_line(option, "printer_basic_information_printable_space#excluded-bed-area");
|
optgroup->append_single_option_line(option, "printer_basic_information_printable_space#excluded-bed-area");
|
||||||
// optgroup->append_single_option_line("printable_area");
|
// optgroup->append_single_option_line("printable_area");
|
||||||
optgroup->append_single_option_line("printable_height", "printer_basic_information_printable_space#printable-height");
|
optgroup->append_single_option_line("printable_height", "printer_basic_information_printable_space#printable-height");
|
||||||
|
optgroup->append_single_option_line("build_plate_tilt_x");
|
||||||
|
optgroup->append_single_option_line("build_plate_tilt_y");
|
||||||
optgroup->append_single_option_line("support_multi_bed_types","printer_basic_information_printable_space#support-multi-bed-types");
|
optgroup->append_single_option_line("support_multi_bed_types","printer_basic_information_printable_space#support-multi-bed-types");
|
||||||
optgroup->append_single_option_line("best_object_pos", "printer_basic_information_printable_space#best-object-position");
|
optgroup->append_single_option_line("best_object_pos", "printer_basic_information_printable_space#best-object-position");
|
||||||
// todo: for multi_extruder test
|
// todo: for multi_extruder test
|
||||||
|
|||||||
Reference in New Issue
Block a user