SPE-1560 - Scale to fit command modified to avoid having the top layer exceeding the print volume max height
This commit is contained in:
parent
1873252a30
commit
d99364d74d
@ -293,6 +293,20 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
|
||||
return { w - thickness_bar_width(canvas), 0.0f, w, h };
|
||||
}
|
||||
|
||||
std::pair<SlicingParameters, const std::vector<double>> GLCanvas3D::LayersEditing::get_layers_height_data()
|
||||
{
|
||||
if (m_slicing_parameters != nullptr)
|
||||
return { *m_slicing_parameters, m_layer_height_profile };
|
||||
|
||||
assert(m_model_object != nullptr);
|
||||
this->update_slicing_parameters();
|
||||
PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile);
|
||||
std::pair<SlicingParameters, const std::vector<double>> ret = { *m_slicing_parameters, m_layer_height_profile };
|
||||
delete m_slicing_parameters;
|
||||
m_slicing_parameters = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::LayersEditing::is_initialized() const
|
||||
{
|
||||
return wxGetApp().get_shader("variable_layer_height") != nullptr;
|
||||
@ -4082,6 +4096,14 @@ void GLCanvas3D::apply_retina_scale(Vec2d &screen_coordinate) const
|
||||
#endif // ENABLE_RETINA_GL
|
||||
}
|
||||
|
||||
std::pair<SlicingParameters, const std::vector<double>> GLCanvas3D::get_layers_height_data(int object_id)
|
||||
{
|
||||
m_layers_editing.select_object(*m_model, object_id);
|
||||
std::pair<SlicingParameters, const std::vector<double>> ret = m_layers_editing.get_layers_height_data();
|
||||
m_layers_editing.select_object(*m_model, -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_shown_on_screen() const
|
||||
{
|
||||
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
|
||||
|
@ -291,6 +291,8 @@ class GLCanvas3D
|
||||
|
||||
std::string get_tooltip(const GLCanvas3D& canvas) const;
|
||||
|
||||
std::pair<SlicingParameters, const std::vector<double>> get_layers_height_data();
|
||||
|
||||
private:
|
||||
bool is_initialized() const;
|
||||
void generate_layer_height_texture();
|
||||
@ -958,6 +960,8 @@ public:
|
||||
|
||||
void apply_retina_scale(Vec2d &screen_coordinate) const;
|
||||
|
||||
std::pair<SlicingParameters, const std::vector<double>> get_layers_height_data(int object_id);
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
|
||||
|
@ -1302,11 +1302,12 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
||||
|
||||
void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
{
|
||||
auto fit = [this](double s, Vec3d offset) {
|
||||
auto fit = [this](double s, Vec3d offset, bool undoredo_snapshot) {
|
||||
if (s <= 0.0 || s == 1.0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
wxGetApp().plater()->take_snapshot(_L("Scale To Fit"));
|
||||
if (undoredo_snapshot)
|
||||
wxGetApp().plater()->take_snapshot(_L("Scale To Fit"));
|
||||
|
||||
TransformationType type;
|
||||
type.set_world();
|
||||
@ -1331,29 +1332,32 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
wxGetApp().plater()->canvas3D()->do_move(""); // avoid storing another snapshot
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
return undoredo_snapshot;
|
||||
};
|
||||
|
||||
auto fit_rectangle = [this, fit](const BuildVolume& volume) {
|
||||
auto fit_rectangle = [this, fit](const BuildVolume& volume, bool undoredo_snapshot, double* max_height = nullptr) {
|
||||
const BoundingBoxf3 print_volume = volume.bounding_volume();
|
||||
const Vec3d print_volume_size = print_volume.size();
|
||||
Vec3d print_volume_size = print_volume.size();
|
||||
print_volume_size.z() = (max_height != nullptr) ? *max_height : volume.max_print_height();
|
||||
|
||||
// adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
|
||||
const Vec3d box_size = get_bounding_box().size() + 0.02 * Vec3d::Ones();
|
||||
// adds 1/100th of a mm on both xy sides to avoid false out of print volume detections due to floating-point roundings
|
||||
Vec3d box_size = get_bounding_box().size();
|
||||
box_size.x() += 0.02;
|
||||
box_size.y() += 0.02;
|
||||
|
||||
const double sx = (box_size.x() != 0.0) ? print_volume_size.x() / box_size.x() : 0.0;
|
||||
const double sy = (box_size.y() != 0.0) ? print_volume_size.y() / box_size.y() : 0.0;
|
||||
const double sz = (box_size.z() != 0.0) ? print_volume_size.z() / box_size.z() : 0.0;
|
||||
const double sx = print_volume_size.x() / box_size.x();
|
||||
const double sy = print_volume_size.y() / box_size.y();
|
||||
const double sz = print_volume_size.z() / box_size.z();
|
||||
|
||||
if (sx != 0.0 && sy != 0.0 && sz != 0.0)
|
||||
fit(std::min(sx, std::min(sy, sz)), print_volume.center() - get_bounding_box().center());
|
||||
return fit(std::min(sx, std::min(sy, sz)), print_volume.center() - get_bounding_box().center(), undoredo_snapshot);
|
||||
};
|
||||
|
||||
auto fit_circle = [this, fit](const BuildVolume& volume) {
|
||||
auto fit_circle = [this, fit](const BuildVolume& volume, bool undoredo_snapshot, double* max_height = nullptr) {
|
||||
const Geometry::Circled& print_circle = volume.circle();
|
||||
double print_circle_radius = unscale<double>(print_circle.radius);
|
||||
|
||||
if (print_circle_radius == 0.0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
Points points;
|
||||
double max_z = 0.0;
|
||||
@ -1367,31 +1371,56 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
||||
}
|
||||
|
||||
if (points.empty())
|
||||
return;
|
||||
return false;
|
||||
|
||||
const Geometry::Circled circle = Geometry::smallest_enclosing_circle_welzl(points);
|
||||
// adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings
|
||||
const double circle_radius = unscale<double>(circle.radius) + 0.01;
|
||||
|
||||
if (circle_radius == 0.0 || max_z == 0.0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
const double s = std::min(print_circle_radius / circle_radius, volume.max_print_height() / max_z);
|
||||
const double print_volume_max_z = (max_height != nullptr) ? *max_height : volume.max_print_height();
|
||||
const double s = std::min(print_circle_radius / circle_radius, print_volume_max_z / max_z);
|
||||
const Vec3d sel_center = get_bounding_box().center();
|
||||
const Vec3d offset = s * (Vec3d(unscale<double>(circle.center.x()), unscale<double>(circle.center.y()), 0.5 * max_z) - sel_center);
|
||||
const Vec3d print_center = { unscale<double>(print_circle.center.x()), unscale<double>(print_circle.center.y()), 0.5 * volume.max_print_height() };
|
||||
fit(s, print_center - (sel_center + offset));
|
||||
return fit(s, print_center - (sel_center + offset), undoredo_snapshot);
|
||||
};
|
||||
|
||||
if (is_empty() || m_mode == Volume)
|
||||
return;
|
||||
|
||||
assert(is_single_full_instance());
|
||||
|
||||
// used to keep track whether the undo/redo snapshot has already been taken
|
||||
bool undoredo_snapshot = false;
|
||||
|
||||
switch (volume.type())
|
||||
{
|
||||
case BuildVolume::Type::Rectangle: { fit_rectangle(volume); break; }
|
||||
case BuildVolume::Type::Circle: { fit_circle(volume); break; }
|
||||
case BuildVolume::Type::Rectangle: { undoredo_snapshot = fit_rectangle(volume, !undoredo_snapshot); break; }
|
||||
case BuildVolume::Type::Circle: { undoredo_snapshot = fit_circle(volume, !undoredo_snapshot); break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
if (wxGetApp().plater()->printer_technology() == ptFFF) {
|
||||
// check whether the top layer exceeds the maximum height of the print volume
|
||||
// and, in case, reduce the scale accordingly
|
||||
const auto [slicing_parameters, profile] = wxGetApp().plater()->canvas3D()->get_layers_height_data(get_object_idx());
|
||||
auto layers = generate_object_layers(slicing_parameters, profile);
|
||||
auto layers_it = layers.rbegin();
|
||||
while (layers_it != layers.rend() && *layers_it > volume.bounding_volume().max.z()) {
|
||||
++layers_it;
|
||||
}
|
||||
if (layers_it != layers.rbegin() && layers_it != layers.rend()) {
|
||||
switch (volume.type())
|
||||
{
|
||||
case BuildVolume::Type::Rectangle: { fit_rectangle(volume, !undoredo_snapshot, &(*layers_it)); break; }
|
||||
case BuildVolume::Type::Circle: { fit_circle(volume, !undoredo_snapshot, &(*layers_it)); break; }
|
||||
default: { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
|
Loading…
Reference in New Issue
Block a user