Fix some rotation-related issues (#3890)

* Fix issue with max_z after rotation

* Don't use `object.bounding_box()`, use `bounding_box_exact()` instead.

* Fix auto-orient

---------

Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
Noisyfox 2024-01-30 19:45:14 +08:00 committed by GitHub
parent d1eea4c677
commit 73ab032e82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 186 additions and 137 deletions

View file

@ -3074,7 +3074,7 @@ int CLI::run(int argc, char **argv)
} else if (opt_key == "align_xy") {
const Vec2d &p = m_config.option<ConfigOptionPoint>("align_xy")->value;
for (auto &model : m_models) {
BoundingBoxf3 bb = model.bounding_box();
BoundingBoxf3 bb = model.bounding_box_exact();
// this affects volumes:
model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z());
}

View file

@ -127,7 +127,7 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
std::vector<std::pair<double, double>> object_intervals;
for (PrintObject *print_object : print.objects()) {
const PrintInstances &print_instances = print_object->instances();
BoundingBoxf3 bounding_box = print_instances[0].model_instance->get_object()->bounding_box();
BoundingBoxf3 bounding_box = print_instances[0].model_instance->get_object()->bounding_box_exact();
if (bounding_box.min.x() < start_x_position && bounding_box.min.y() < cutter_area_y)
can_travel_form_left = false;

View file

@ -418,36 +418,12 @@ Vec3d extract_euler_angles(const Transform3d& transform)
void rotation_from_two_vectors(Vec3d from, Vec3d to, Vec3d& rotation_axis, double& phi, Matrix3d* rotation_matrix)
{
double epsilon = 1e-5;
// note: a.isMuchSmallerThan(b,prec) compares a.abs().sum()<b*prec, so previously we set b=0 && prec=dummpy_prec() is wrong
if ((from + to).isMuchSmallerThan(1, epsilon))
{
rotation_axis << 1, 0, 0;
phi = M_PI;
const Matrix3d m = Transform3d(Eigen::Quaterniond().setFromTwoVectors(from, to)).matrix().block<3, 3>(0, 0);
const Eigen::AngleAxisd aa(m);
rotation_axis = aa.axis();
phi = aa.angle();
if (rotation_matrix)
*rotation_matrix = -Matrix3d::Identity();
}
else if ((from - to).isMuchSmallerThan(1, epsilon)) {
rotation_axis << 1, 0, 0;
phi = 0;
if (rotation_matrix)
*rotation_matrix = Matrix3d::Identity();
}
else {
rotation_axis = from.cross(to);
double s = rotation_axis.norm(); // sin(phi)
double c = from.dot(to); // cos(phi)
auto& v = rotation_axis;
Matrix3d kmat;
kmat << 0, -v[2], v[1],
v[2], 0, -v[0],
-v[1], v[0], 0;
rotation_axis.normalize();
phi = acos(std::min(from.dot(to), 1.0));
if (rotation_matrix)
*rotation_matrix = Matrix3d::Identity() + kmat + kmat * kmat * ((1 - c) / (s * s));
}
*rotation_matrix = m;
}
Transform3d Transformation::get_offset_matrix() const

View file

@ -570,14 +570,30 @@ bool Model::add_default_instances()
}
// this returns the bounding box of the *transformed* instances
BoundingBoxf3 Model::bounding_box() const
BoundingBoxf3 Model::bounding_box_approx() const
{
BoundingBoxf3 bb;
for (ModelObject *o : this->objects)
bb.merge(o->bounding_box());
bb.merge(o->bounding_box_approx());
return bb;
}
BoundingBoxf3 Model::bounding_box_exact() const
{
BoundingBoxf3 bb;
for (ModelObject *o : this->objects)
bb.merge(o->bounding_box_exact());
return bb;
}
double Model::max_z() const
{
double z = 0;
for (ModelObject *o : this->objects)
z = std::max(z, o->max_z());
return z;
}
unsigned int Model::update_print_volume_state(const BuildVolume &build_volume)
{
unsigned int num_printable = 0;
@ -628,7 +644,7 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
ModelObject* object = this->objects.front();
object->clear_instances();
Vec3d ext_size = object->bounding_box().size() + dist * Vec3d::Ones();
Vec3d ext_size = object->bounding_box_exact().size() + dist * Vec3d::Ones();
for (size_t x_copy = 1; x_copy <= x; ++x_copy) {
for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
@ -647,7 +663,7 @@ bool Model::looks_like_multipart_object() const
if (obj->volumes.size() > 1 || obj->config.keys().size() > 1)
return false;
double zmin_this = obj->get_min_z();
double zmin_this = obj->min_z();
if (zmin == std::numeric_limits<double>::max())
zmin = zmin_this;
else if (std::abs(zmin - zmin_this) > EPSILON)
@ -804,13 +820,13 @@ void Model::adjust_min_z()
if (objects.empty())
return;
if (bounding_box().min(2) < 0.0)
if (this->bounding_box_exact().min.z() < 0.0)
{
for (ModelObject* obj : objects)
{
if (obj != nullptr)
{
coordf_t obj_min_z = obj->bounding_box().min(2);
coordf_t obj_min_z = obj->min_z();
if (obj_min_z < 0.0)
obj->translate_instances(Vec3d(0.0, 0.0, -obj_min_z));
}
@ -1021,12 +1037,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->printable = rhs.printable;
this->origin_translation = rhs.origin_translation;
this->cut_id.copy(rhs.cut_id);
m_bounding_box = rhs.m_bounding_box;
m_bounding_box_valid = rhs.m_bounding_box_valid;
m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
this->copy_transformation_caches(rhs);
this->clear_volumes();
this->volumes.reserve(rhs.volumes.size());
@ -1064,12 +1075,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
this->layer_height_profile = std::move(rhs.layer_height_profile);
this->printable = std::move(rhs.printable);
this->origin_translation = std::move(rhs.origin_translation);
m_bounding_box = std::move(rhs.m_bounding_box);
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid);
m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid;
m_raw_mesh_bounding_box = rhs.m_raw_mesh_bounding_box;
m_raw_mesh_bounding_box_valid = rhs.m_raw_mesh_bounding_box_valid;
this->copy_transformation_caches(rhs);
this->clear_volumes();
this->volumes = std::move(rhs.volumes);
@ -1312,16 +1318,72 @@ void ModelObject::clear_instances()
// Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug.
const BoundingBoxf3& ModelObject::bounding_box() const
const BoundingBoxf3& ModelObject::bounding_box_approx() const
{
if (! m_bounding_box_valid) {
m_bounding_box_valid = true;
if (! m_bounding_box_approx_valid) {
m_bounding_box_approx_valid = true;
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
m_bounding_box.reset();
m_bounding_box_approx.reset();
for (const ModelInstance *i : this->instances)
m_bounding_box.merge(i->transform_bounding_box(raw_bbox));
m_bounding_box_approx.merge(i->transform_bounding_box(raw_bbox));
}
return m_bounding_box_approx;
}
// Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug.
const BoundingBoxf3& ModelObject::bounding_box_exact() const
{
if (! m_bounding_box_exact_valid) {
m_bounding_box_exact_valid = true;
m_min_max_z_valid = true;
m_bounding_box_exact.reset();
for (size_t i = 0; i < this->instances.size(); ++ i)
m_bounding_box_exact.merge(this->instance_bounding_box(i));
}
return m_bounding_box_exact;
}
double ModelObject::min_z() const
{
const_cast<ModelObject*>(this)->update_min_max_z();
return m_bounding_box_exact.min.z();
}
double ModelObject::max_z() const
{
const_cast<ModelObject*>(this)->update_min_max_z();
return m_bounding_box_exact.max.z();
}
void ModelObject::update_min_max_z()
{
assert(! this->instances.empty());
if (! m_min_max_z_valid && ! this->instances.empty()) {
m_min_max_z_valid = true;
const Transform3d mat_instance = this->instances.front()->get_transformation().get_matrix();
double global_min_z = std::numeric_limits<double>::max();
double global_max_z = - std::numeric_limits<double>::max();
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
const Transform3d m = mat_instance * v->get_matrix();
const Vec3d row_z = m.linear().row(2).cast<double>();
const double shift_z = m.translation().z();
double this_min_z = std::numeric_limits<double>::max();
double this_max_z = - std::numeric_limits<double>::max();
for (const Vec3f &p : v->mesh().its.vertices) {
double z = row_z.dot(p.cast<double>());
this_min_z = std::min(this_min_z, z);
this_max_z = std::max(this_max_z, z);
}
this_min_z += shift_z;
this_max_z += shift_z;
global_min_z = std::min(global_min_z, this_min_z);
global_max_z = std::max(global_max_z, this_max_z);
}
m_bounding_box_exact.min.z() = global_min_z;
m_bounding_box_exact.max.z() = global_max_z;
}
return m_bounding_box;
}
// A mesh containing all transformed instances of this object.
@ -1532,19 +1594,19 @@ void ModelObject::ensure_on_bed(bool allow_negative_z)
if (allow_negative_z) {
if (parts_count() == 1) {
const double min_z = get_min_z();
const double max_z = get_max_z();
const double min_z = this->min_z();
const double max_z = this->max_z();
if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0)
z_offset = -min_z;
}
else {
const double max_z = get_max_z();
const double max_z = this->max_z();
if (max_z < SINKING_MIN_Z_THRESHOLD)
z_offset = SINKING_MIN_Z_THRESHOLD - max_z;
}
}
else
z_offset = -get_min_z();
z_offset = -this->min_z();
if (z_offset != 0.0)
translate_instances(z_offset * Vec3d::UnitZ());
@ -1571,8 +1633,10 @@ void ModelObject::translate(double x, double y, double z)
v->translate(x, y, z);
}
if (m_bounding_box_valid)
m_bounding_box.translate(x, y, z);
if (m_bounding_box_approx_valid)
m_bounding_box_approx.translate(x, y, z);
if (m_bounding_box_exact_valid)
m_bounding_box_exact.translate(x, y, z);
}
void ModelObject::scale(const Vec3d &versor)
@ -2049,32 +2113,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
this->invalidate_bounding_box();
}
double ModelObject::get_min_z() const
{
if (instances.empty())
return 0.0;
else {
double min_z = DBL_MAX;
for (size_t i = 0; i < instances.size(); ++i) {
min_z = std::min(min_z, get_instance_min_z(i));
}
return min_z;
}
}
double ModelObject::get_max_z() const
{
if (instances.empty())
return 0.0;
else {
double max_z = -DBL_MAX;
for (size_t i = 0; i < instances.size(); ++i) {
max_z = std::max(max_z, get_instance_max_z(i));
}
return max_z;
}
}
double ModelObject::get_instance_min_z(size_t instance_idx) const
{
double min_z = DBL_MAX;
@ -2611,7 +2649,7 @@ void ModelVolume::scale(const Vec3d& scaling_factors)
void ModelObject::scale_to_fit(const Vec3d &size)
{
Vec3d orig_size = this->bounding_box().size();
Vec3d orig_size = this->bounding_box_exact().size();
double factor = std::min(
size.x() / orig_size.x(),
std::min(

View file

@ -380,7 +380,7 @@ public:
// The pairs of <z, layer_height> are packed into a 1D array.
LayerHeightProfile layer_height_profile;
// Whether or not this object is printable
bool printable;
bool printable { true };
// This vector holds position of selected support points for SLA. The data are
// saved in mesh coordinates to allow using them for several instances.
@ -444,11 +444,22 @@ public:
void delete_last_instance();
void clear_instances();
// Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug.
// This bounding box is being cached.
const BoundingBoxf3& bounding_box() const;
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; }
// Returns the bounding box of the transformed instances. This bounding box is approximate and not snug, it is being cached.
const BoundingBoxf3& bounding_box_approx() const;
// Returns an exact bounding box of the transformed instances. The result it is being cached.
const BoundingBoxf3& bounding_box_exact() const;
// Return minimum / maximum of a printable object transformed into the world coordinate system.
// All instances share the same min / max Z.
double min_z() const;
double max_z() const;
void invalidate_bounding_box() {
m_bounding_box_approx_valid = false;
m_bounding_box_exact_valid = false;
m_min_max_z_valid = false;
m_raw_bounding_box_valid = false;
m_raw_mesh_bounding_box_valid = false;
}
// A mesh containing all transformed instances of this object.
TriangleMesh mesh() const;
@ -521,8 +532,6 @@ public:
// Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well.
void bake_xy_rotation_into_meshes(size_t instance_idx);
double get_min_z() const;
double get_max_z() const;
double get_instance_min_z(size_t instance_idx) const;
double get_instance_max_z(size_t instance_idx) const;
@ -543,14 +552,13 @@ public:
private:
friend class Model;
// This constructor assigns new ID to this ModelObject and its config.
explicit ModelObject(Model* model) : m_model(model), printable(true), origin_translation(Vec3d::Zero()),
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
explicit ModelObject(Model* model) : m_model(model), origin_translation(Vec3d::Zero())
{
assert(this->id().valid());
assert(this->config.id().valid());
assert(this->layer_height_profile.id().valid());
}
explicit ModelObject(int) : ObjectBase(-1), config(-1), layer_height_profile(-1), m_model(nullptr), printable(true), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
explicit ModelObject(int) : ObjectBase(-1), config(-1), layer_height_profile(-1), origin_translation(Vec3d::Zero())
{
assert(this->id().invalid());
assert(this->config.id().invalid());
@ -628,15 +636,31 @@ private:
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(ModelObject)
// Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized.
Model *m_model = nullptr;
Model *m_model { nullptr };
// Bounding box, cached.
mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_valid;
mutable BoundingBoxf3 m_bounding_box_approx;
mutable bool m_bounding_box_approx_valid { false };
mutable BoundingBoxf3 m_bounding_box_exact;
mutable bool m_bounding_box_exact_valid { false };
mutable bool m_min_max_z_valid { false };
mutable BoundingBoxf3 m_raw_bounding_box;
mutable bool m_raw_bounding_box_valid;
mutable bool m_raw_bounding_box_valid { false };
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
mutable bool m_raw_mesh_bounding_box_valid;
mutable bool m_raw_mesh_bounding_box_valid { false };
// Only use this method if now the source and dest ModelObjects are equal, for example they were synchronized by Print::apply().
void copy_transformation_caches(const ModelObject &src) {
m_bounding_box_approx = src.m_bounding_box_approx;
m_bounding_box_approx_valid = src.m_bounding_box_approx_valid;
m_bounding_box_exact = src.m_bounding_box_exact;
m_bounding_box_exact_valid = src.m_bounding_box_exact_valid;
m_min_max_z_valid = src.m_min_max_z_valid;
m_raw_bounding_box = src.m_raw_bounding_box;
m_raw_bounding_box_valid = src.m_raw_bounding_box_valid;
m_raw_mesh_bounding_box = src.m_raw_mesh_bounding_box;
m_raw_mesh_bounding_box_valid = src.m_raw_mesh_bounding_box_valid;
}
// Called by Print::apply() to set the model pointer after making a copy.
friend class Print;
@ -648,8 +672,7 @@ private:
friend class UndoRedo::StackImpl;
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
ModelObject() :
ObjectBase(-1), config(-1), layer_height_profile(-1),
m_model(nullptr), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {
ObjectBase(-1), config(-1), layer_height_profile(-1) {
assert(this->id().invalid());
assert(this->config.id().invalid());
assert(this->layer_height_profile.id().invalid());
@ -660,7 +683,9 @@ private:
Internal::StaticSerializationWrapper<LayerHeightProfile const> layer_heigth_profile_wrapper(layer_height_profile);
ar(name, module_name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper,
sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation,
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
m_bounding_box_approx, m_bounding_box_approx_valid,
m_bounding_box_exact, m_bounding_box_exact_valid, m_min_max_z_valid,
m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
cut_connectors, cut_id);
}
template<class Archive> void load(Archive& ar) {
@ -671,7 +696,9 @@ private:
SaveObjectGaurd gaurd(*this);
ar(name, module_name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper,
sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation,
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
m_bounding_box_approx, m_bounding_box_approx_valid,
m_bounding_box_exact, m_bounding_box_exact_valid, m_min_max_z_valid,
m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid,
cut_connectors, cut_id);
std::vector<ObjectID> volume_ids2;
std::transform(volumes.begin(), volumes.end(), std::back_inserter(volume_ids2), std::mem_fn(&ObjectBase::id));
@ -682,6 +709,9 @@ private:
// Called by Print::validate() from the UI thread.
unsigned int update_instances_print_volume_state(const BuildVolume &build_volume);
// Called by min_z(), max_z()
void update_min_max_z();
};
enum class EnforcerBlockerType : int8_t {
@ -1268,10 +1298,8 @@ public:
// BBS
void rotate(Matrix3d rotation_matrix) {
auto R = m_transformation.get_rotation_matrix().matrix().block<3, 3>(0, 0);
auto R_new = rotation_matrix * R;
auto euler_angles = Geometry::extract_euler_angles(R_new);
set_rotation(euler_angles);
const Geometry::Transformation& old_inst_trafo = get_transformation();
set_transformation(Geometry::Transformation{old_inst_trafo.get_offset_matrix() * rotation_matrix * old_inst_trafo.get_matrix_no_offset()});
}
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
@ -1574,8 +1602,12 @@ public:
void delete_material(t_model_material_id material_id);
void clear_materials();
bool add_default_instances();
// Returns approximate axis aligned bounding box of this model
BoundingBoxf3 bounding_box() const;
// Returns approximate axis aligned bounding box of this model.
BoundingBoxf3 bounding_box_approx() const;
// Returns exact axis aligned bounding box of this model.
BoundingBoxf3 bounding_box_exact() const;
// Return maximum height of all printable objects.
double max_z() const;
// Set the print_volume_state of PrintObject::instances,
// return total number of printable objects.
unsigned int update_print_volume_state(const BuildVolume &build_volume);

View file

@ -176,7 +176,7 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::
ap.has_tree_support = true;
}
ap.height = obj->bounding_box().size().z();
ap.height = obj->bounding_box_exact().size().z();
ap.name = obj->name;
return ap;
}

View file

@ -108,6 +108,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y());
// Size of the transformed mesh. This bounding may not be snug in XY plane, but it is snug in Z.
m_size = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
m_size.z() = coord_t(model_object->max_z() * (1. / SCALING_FACTOR));
this->set_instances(std::move(instances));
}
@ -2932,7 +2933,7 @@ void PrintObject::update_slicing_parameters()
{
if (!m_slicing_params.valid)
m_slicing_params = SlicingParameters::create_from_config(
this->print()->config(), m_config, this->model_object()->bounding_box().max.z(), this->object_extruders());
this->print()->config(), m_config, this->model_object()->max_z(), this->object_extruders());
}
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)

View file

@ -160,7 +160,8 @@ void GLCanvas3D::LayersEditing::select_object(const Model& model, int object_id)
// Maximum height of an object changes when the object gets rotated or scaled.
// Changing maximum height of an object will invalidate the layer heigth editing profile.
// m_model_object->bounding_box() is cached, therefore it is cheap even if this method is called frequently.
const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast<float>(model_object_new->bounding_box().max.z());
const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast<float>(model_object_new->max_z());
if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z ||
(model_object_new != nullptr && m_model_object->id() != model_object_new->id())) {
m_layer_height_profile.clear();

View file

@ -238,6 +238,7 @@ orientation::OrientMesh OrientJob::get_orient_mesh(ModelInstance* instance)
om.setter = [instance](const OrientMesh& p) {
instance->rotate(p.rotation_matrix);
instance->get_object()->invalidate_bounding_box();
instance->get_object()->ensure_on_bed();
};
return om;

View file

@ -1601,7 +1601,7 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con
if (!use_global_objects && !contain_instance_totally(obj_idx, 0))
continue;
BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box();
BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box_exact();
max_height = std::max(bbox.size().z(), max_height);
}
wipe_tower_size(2) = max_height;

View file

@ -5295,7 +5295,7 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
ModelObject* old_model_object = model.objects[object_idx];
ModelVolume* old_volume = old_model_object->volumes[volume_idx];
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
bool sinking = old_model_object->min_z() < SINKING_Z_THRESHOLD;
ModelObject* new_model_object = new_model.objects.front();
old_model_object->add_volume(*new_model_object->volumes.front());
@ -5616,7 +5616,7 @@ void Plater::priv::reload_from_disk()
ModelObject *old_model_object = model.objects[obj_idx];
ModelVolume *old_volume = old_model_object->volumes[vol_idx];
bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
bool sinking = old_model_object->min_z() < SINKING_Z_THRESHOLD;
bool has_source = !old_volume->source.input_file.empty() &&
boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string());
@ -7846,7 +7846,7 @@ bool Plater::priv::layers_height_allowed() const
return false;
int obj_idx = get_selected_object_idx();
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->bounding_box().max.z() > SINKING_Z_THRESHOLD && view3D->is_layers_editing_allowed();
return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->max_z() > SINKING_Z_THRESHOLD && view3D->is_layers_editing_allowed();
}
bool Plater::priv::can_layers_editing() const
@ -9104,7 +9104,7 @@ void Plater::_calib_pa_tower(const Calib_Params& params) {
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
auto new_height = std::ceil((params.end - params.start) / params.step) + 1;
auto obj_bb = model().objects[0]->bounding_box();
auto obj_bb = model().objects[0]->bounding_box_exact();
if (new_height < obj_bb.size().z()) {
cut_horizontal(0, 0, new_height, ModelObjectCutAttribute::KeepLower);
}
@ -9245,7 +9245,7 @@ void Plater::calib_temp(const Calib_Params& params) {
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->reload_config();
// cut upper
auto obj_bb = model().objects[0]->bounding_box();
auto obj_bb = model().objects[0]->bounding_box_exact();
auto block_count = lround((350 - params.end) / 5 + 1);
if(block_count > 0){
// add EPSILON offset to avoid cutting at the exact location where the flat surface is
@ -9256,7 +9256,7 @@ void Plater::calib_temp(const Calib_Params& params) {
}
// cut bottom
obj_bb = model().objects[0]->bounding_box();
obj_bb = model().objects[0]->bounding_box_exact();
block_count = lround((350 - params.start) / 5);
if(block_count > 0){
auto new_height = block_count * 10.0 + EPSILON;
@ -9285,7 +9285,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params)
auto bed_shape = printer_config->option<ConfigOptionPoints>("printable_area")->values;
BoundingBoxf bed_ext = get_extents(bed_shape);
auto scale_obj = (bed_ext.size().x() - 10) / obj->bounding_box().size().x();
auto scale_obj = (bed_ext.size().x() - 10) / obj->bounding_box_exact().size().x();
if (scale_obj < 1.0)
obj->scale(scale_obj, 1, 1);
@ -9327,7 +9327,7 @@ void Plater::calib_max_vol_speed(const Calib_Params& params)
wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config();
// cut upper
auto obj_bb = obj->bounding_box();
auto obj_bb = obj->bounding_box_exact();
auto height = (params.end - params.start + 1) / params.step;
if (height < obj_bb.size().z()) {
cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower);
@ -9376,7 +9376,7 @@ void Plater::calib_retraction(const Calib_Params& params)
changed_objects({ 0 });
// cut upper
auto obj_bb = obj->bounding_box();
auto obj_bb = obj->bounding_box_exact();
auto height = 1.0 + 0.4 + ((params.end - params.start)) / params.step;
if (height < obj_bb.size().z()) {
cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower);
@ -9419,7 +9419,7 @@ void Plater::calib_VFA(const Calib_Params& params)
wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_ui_from_settings();
// cut upper
auto obj_bb = model().objects[0]->bounding_box();
auto obj_bb = model().objects[0]->bounding_box_exact();
auto height = 5 * ((params.end - params.start) / params.step + 1);
if (height < obj_bb.size().z()) {
cut_horizontal(0, 0, height, ModelObjectCutAttribute::KeepLower);
@ -12432,7 +12432,7 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
for (size_t obj_idx : object_idxs) {
if (obj_idx < p->model.objects.size()) {
if (p->model.objects[obj_idx]->bounding_box().min.z() >= SINKING_Z_THRESHOLD)
if (p->model.objects[obj_idx]->min_z() >= SINKING_Z_THRESHOLD)
// re - align to Z = 0
p->model.objects[obj_idx]->ensure_on_bed();
}

View file

@ -662,7 +662,7 @@ void CalibUtils::calib_temptue(const CalibInfo &calib_info, wxString &error_mess
read_model_from_file(input_file, model);
// cut upper
auto obj_bb = model.objects[0]->bounding_box();
auto obj_bb = model.objects[0]->bounding_box_exact();
auto block_count = lround((350 - params.start) / 5 + 1);
if (block_count > 0) {
// add EPSILON offset to avoid cutting at the exact location where the flat surface is
@ -673,7 +673,7 @@ void CalibUtils::calib_temptue(const CalibInfo &calib_info, wxString &error_mess
}
// cut bottom
obj_bb = model.objects[0]->bounding_box();
obj_bb = model.objects[0]->bounding_box_exact();
block_count = lround((350 - params.end) / 5);
if (block_count > 0) {
auto new_height = block_count * 10.0 + EPSILON;
@ -728,7 +728,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro
auto obj = model.objects[0];
auto bed_shape = printer_config.option<ConfigOptionPoints>("printable_area")->values;
BoundingBoxf bed_ext = get_extents(bed_shape);
auto scale_obj = (bed_ext.size().x() - 10) / obj->bounding_box().size().x();
auto scale_obj = (bed_ext.size().x() - 10) / obj->bounding_box_exact().size().x();
if (scale_obj < 1.0)
obj->scale(scale_obj, 1, 1);
@ -762,7 +762,7 @@ void CalibUtils::calib_max_vol_speed(const CalibInfo &calib_info, wxString &erro
obj->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
// cut upper
auto obj_bb = obj->bounding_box();
auto obj_bb = obj->bounding_box_exact();
double height = (params.end - params.start + 1) / params.step;
if (height < obj_bb.size().z()) {
cut_model(model, height, ModelObjectCutAttribute::KeepLower);
@ -820,7 +820,7 @@ void CalibUtils::calib_VFA(const CalibInfo &calib_info, wxString &error_message)
model.objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0));
// cut upper
auto obj_bb = model.objects[0]->bounding_box();
auto obj_bb = model.objects[0]->bounding_box_exact();
auto height = 5 * ((params.end - params.start) / params.step + 1);
if (height < obj_bb.size().z()) {
cut_model(model, height, ModelObjectCutAttribute::KeepLower);
@ -875,7 +875,7 @@ void CalibUtils::calib_retraction(const CalibInfo &calib_info, wxString &error_m
obj->config.set_key_value("layer_height", new ConfigOptionFloat(layer_height));
// cut upper
auto obj_bb = obj->bounding_box();
auto obj_bb = obj->bounding_box_exact();
auto height = 1.0 + 0.4 + ((params.end - params.start)) / params.step;
if (height < obj_bb.size().z()) {
cut_model(model, height, ModelObjectCutAttribute::KeepLower);
@ -947,7 +947,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f
ModelInstance *instance = model->objects[0]->instances[0];
instance->set_offset(instance->get_offset() + Vec3d(current_width / 2, current_depth / 2, 0));
} else {
BoundingBoxf3 bbox = model->bounding_box();
BoundingBoxf3 bbox = model->bounding_box_exact();
Vec3d bbox_center = bbox.center();
for (auto object : model->objects) {
ModelInstance *instance = object->instances[0];