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

@ -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);