Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_transformations

This commit is contained in:
enricoturri1966 2023-02-28 11:49:01 +01:00
commit 7b08170077
8 changed files with 160 additions and 118 deletions

View File

@ -382,7 +382,7 @@ int CLI::run(int argc, char **argv)
} else if (opt_key == "align_xy") { } else if (opt_key == "align_xy") {
const Vec2d &p = m_config.option<ConfigOptionPoint>("align_xy")->value; const Vec2d &p = m_config.option<ConfigOptionPoint>("align_xy")->value;
for (auto &model : m_models) { for (auto &model : m_models) {
BoundingBoxf3 bb = model.bounding_box(); BoundingBoxf3 bb = model.bounding_box_exact();
// this affects volumes: // this affects volumes:
model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z()); model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z());
} }
@ -423,7 +423,7 @@ int CLI::run(int argc, char **argv)
} else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
std::vector<Model> new_models; std::vector<Model> new_models;
for (auto &model : m_models) { for (auto &model : m_models) {
model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0 model.translate(0, 0, -model.bounding_box_exact().min.z()); // align to z = 0
size_t num_objects = model.objects.size(); size_t num_objects = model.objects.size();
for (size_t i = 0; i < num_objects; ++ i) { for (size_t i = 0; i < num_objects; ++ i) {

View File

@ -323,14 +323,30 @@ bool Model::add_default_instances()
} }
// this returns the bounding box of the *transformed* instances // this returns the bounding box of the *transformed* instances
BoundingBoxf3 Model::bounding_box() const BoundingBoxf3 Model::bounding_box_approx() const
{ {
BoundingBoxf3 bb; BoundingBoxf3 bb;
for (ModelObject *o : this->objects) for (ModelObject *o : this->objects)
bb.merge(o->bounding_box()); bb.merge(o->bounding_box_approx());
return bb; 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 Model::update_print_volume_state(const BuildVolume &build_volume)
{ {
unsigned int num_printable = 0; unsigned int num_printable = 0;
@ -377,7 +393,7 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
ModelObject* object = this->objects.front(); ModelObject* object = this->objects.front();
object->clear_instances(); 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 x_copy = 1; x_copy <= x; ++x_copy) {
for (size_t y_copy = 1; y_copy <= y; ++y_copy) { for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
@ -548,13 +564,13 @@ void Model::adjust_min_z()
if (objects.empty()) if (objects.empty())
return; return;
if (bounding_box().min(2) < 0.0) if (this->bounding_box_exact().min.z() < 0.0)
{ {
for (ModelObject* obj : objects) for (ModelObject* obj : objects)
{ {
if (obj != nullptr) 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) if (obj_min_z < 0.0)
obj->translate_instances(Vec3d(0.0, 0.0, -obj_min_z)); obj->translate_instances(Vec3d(0.0, 0.0, -obj_min_z));
} }
@ -627,8 +643,11 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->printable = rhs.printable; this->printable = rhs.printable;
this->origin_translation = rhs.origin_translation; this->origin_translation = rhs.origin_translation;
this->cut_id.copy(rhs.cut_id); this->cut_id.copy(rhs.cut_id);
m_bounding_box = rhs.m_bounding_box; m_bounding_box_approx = rhs.m_bounding_box_approx;
m_bounding_box_valid = rhs.m_bounding_box_valid; m_bounding_box_approx_valid = rhs.m_bounding_box_approx_valid;
m_bounding_box_exact = rhs.m_bounding_box_exact;
m_bounding_box_exact_valid = rhs.m_bounding_box_exact_valid;
m_min_max_z_valid = rhs.m_min_max_z_valid;
m_raw_bounding_box = rhs.m_raw_bounding_box; m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid; 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 = rhs.m_raw_mesh_bounding_box;
@ -668,8 +687,11 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
this->layer_height_profile = std::move(rhs.layer_height_profile); this->layer_height_profile = std::move(rhs.layer_height_profile);
this->printable = std::move(rhs.printable); this->printable = std::move(rhs.printable);
this->origin_translation = std::move(rhs.origin_translation); this->origin_translation = std::move(rhs.origin_translation);
m_bounding_box = std::move(rhs.m_bounding_box); m_bounding_box_approx = std::move(rhs.m_bounding_box_approx);
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); m_bounding_box_approx_valid = std::move(rhs.m_bounding_box_approx_valid);
m_bounding_box_exact = std::move(rhs.m_bounding_box_exact);
m_bounding_box_exact_valid = std::move(rhs.m_bounding_box_exact_valid);
m_min_max_z_valid = rhs.m_min_max_z_valid;
m_raw_bounding_box = rhs.m_raw_bounding_box; m_raw_bounding_box = rhs.m_raw_bounding_box;
m_raw_bounding_box_valid = rhs.m_raw_bounding_box_valid; 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 = rhs.m_raw_mesh_bounding_box;
@ -864,16 +886,73 @@ void ModelObject::clear_instances()
// Returns the bounding box of the transformed instances. // Returns the bounding box of the transformed instances.
// This bounding box is approximate and not snug. // 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) { if (! m_bounding_box_approx_valid) {
m_bounding_box_valid = true; m_bounding_box_approx_valid = true;
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box(); BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
m_bounding_box.reset(); m_bounding_box_approx.reset();
for (const ModelInstance *i : this->instances) 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;
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
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. // A mesh containing all transformed instances of this object.
@ -1031,19 +1110,19 @@ void ModelObject::ensure_on_bed(bool allow_negative_z)
if (allow_negative_z) { if (allow_negative_z) {
if (parts_count() == 1) { if (parts_count() == 1) {
const double min_z = get_min_z(); const double min_z = this->min_z();
const double max_z = get_max_z(); const double max_z = this->max_z();
if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0) if (min_z >= SINKING_Z_THRESHOLD || max_z < 0.0)
z_offset = -min_z; z_offset = -min_z;
} }
else { else {
const double max_z = get_max_z(); const double max_z = this->max_z();
if (max_z < SINKING_MIN_Z_THRESHOLD) if (max_z < SINKING_MIN_Z_THRESHOLD)
z_offset = SINKING_MIN_Z_THRESHOLD - max_z; z_offset = SINKING_MIN_Z_THRESHOLD - max_z;
} }
} }
else else
z_offset = -get_min_z(); z_offset = -this->min_z();
if (z_offset != 0.0) if (z_offset != 0.0)
translate_instances(z_offset * Vec3d::UnitZ()); translate_instances(z_offset * Vec3d::UnitZ());
@ -1070,8 +1149,10 @@ void ModelObject::translate(double x, double y, double z)
v->translate(x, y, z); v->translate(x, y, z);
} }
if (m_bounding_box_valid) if (m_bounding_box_approx_valid)
m_bounding_box.translate(x, y, z); 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) void ModelObject::scale(const Vec3d &versor)
@ -1866,32 +1947,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
this->invalidate_bounding_box(); 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 ModelObject::get_instance_min_z(size_t instance_idx) const
{ {
double min_z = DBL_MAX; double min_z = DBL_MAX;
@ -2268,7 +2323,7 @@ void ModelVolume::scale(const Vec3d& scaling_factors)
void ModelObject::scale_to_fit(const Vec3d &size) 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( double factor = std::min(
size.x() / orig_size.x(), size.x() / orig_size.x(),
std::min( std::min(
@ -2373,37 +2428,6 @@ void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) cons
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
} }
BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate) const
{
// Rotate around mesh origin.
TriangleMesh copy(mesh);
#if ENABLE_WORLD_COORDINATE
copy.transform(get_transformation().get_rotation_matrix());
#else
copy.transform(get_matrix(true, false, true, true));
#endif // ENABLE_WORLD_COORDINATE
BoundingBoxf3 bbox = copy.bounding_box();
if (!empty(bbox)) {
// Scale the bounding box along the three axes.
for (unsigned int i = 0; i < 3; ++i)
{
if (std::abs(get_scaling_factor((Axis)i)-1.0) > EPSILON)
{
bbox.min(i) *= get_scaling_factor((Axis)i);
bbox.max(i) *= get_scaling_factor((Axis)i);
}
}
// Translate the bounding box.
if (! dont_translate) {
bbox.min += get_offset();
bbox.max += get_offset();
}
}
return bbox;
}
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
{ {
#if ENABLE_WORLD_COORDINATE #if ENABLE_WORLD_COORDINATE

View File

@ -168,7 +168,7 @@ private:
friend class cereal::access; friend class cereal::access;
friend class UndoRedo::StackImpl; friend class UndoRedo::StackImpl;
// Create an object for deserialization, don't allocate IDs for ModelMaterial and its config. // Create an object for deserialization, don't allocate IDs for ModelMaterial and its config.
ModelMaterial() : ObjectBase(-1), config(-1), m_model(nullptr) { assert(this->id().invalid()); assert(this->config.id().invalid()); } ModelMaterial() : ObjectBase(-1), config(-1) { assert(this->id().invalid()); assert(this->config.id().invalid()); }
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
assert(this->id().invalid()); assert(this->config.id().invalid()); assert(this->id().invalid()); assert(this->config.id().invalid());
Internal::StaticSerializationWrapper<ModelConfigObject> config_wrapper(config); Internal::StaticSerializationWrapper<ModelConfigObject> config_wrapper(config);
@ -343,7 +343,7 @@ public:
// The pairs of <z, layer_height> are packed into a 1D array. // The pairs of <z, layer_height> are packed into a 1D array.
LayerHeightProfile layer_height_profile; LayerHeightProfile layer_height_profile;
// Whether or not this object is printable // 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 // This vector holds position of selected support points for SLA. The data are
// saved in mesh coordinates to allow using them for several instances. // saved in mesh coordinates to allow using them for several instances.
@ -397,11 +397,22 @@ public:
void delete_last_instance(); void delete_last_instance();
void clear_instances(); void clear_instances();
// Returns the bounding box of the transformed instances. // Returns the bounding box of the transformed instances. This bounding box is approximate and not snug, it is being cached.
// This bounding box is approximate and not snug. const BoundingBoxf3& bounding_box_approx() const;
// This bounding box is being cached. // Returns an exact bounding box of the transformed instances. The result it is being cached.
const BoundingBoxf3& bounding_box() const; const BoundingBoxf3& bounding_box_exact() const;
void invalidate_bounding_box() { m_bounding_box_valid = false; m_raw_bounding_box_valid = false; m_raw_mesh_bounding_box_valid = false; } // 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. // A mesh containing all transformed instances of this object.
TriangleMesh mesh() const; TriangleMesh mesh() const;
@ -477,8 +488,6 @@ public:
// Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well. // 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); 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_min_z(size_t instance_idx) const;
double get_instance_max_z(size_t instance_idx) const; double get_instance_max_z(size_t instance_idx) const;
@ -500,14 +509,13 @@ public:
private: private:
friend class Model; friend class Model;
// This constructor assigns new ID to this ModelObject and its config. // This constructor assigns new ID to this ModelObject and its config.
explicit ModelObject(Model* model) : m_model(model), printable(true), origin_translation(Vec3d::Zero()), explicit ModelObject(Model* model) : m_model(model), origin_translation(Vec3d::Zero())
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
{ {
assert(this->id().valid()); assert(this->id().valid());
assert(this->config.id().valid()); assert(this->config.id().valid());
assert(this->layer_height_profile.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->id().invalid());
assert(this->config.id().invalid()); assert(this->config.id().invalid());
@ -585,15 +593,18 @@ private:
OBJECTBASE_DERIVED_COPY_MOVE_CLONE(ModelObject) OBJECTBASE_DERIVED_COPY_MOVE_CLONE(ModelObject)
// Parent object, owning this ModelObject. Set to nullptr here, so the macros above will have it initialized. // 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. // Bounding box, cached.
mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_bounding_box_approx;
mutable bool m_bounding_box_valid; 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 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 BoundingBoxf3 m_raw_mesh_bounding_box;
mutable bool m_raw_mesh_bounding_box_valid; mutable bool m_raw_mesh_bounding_box_valid { false };
// Called by Print::apply() to set the model pointer after making a copy. // Called by Print::apply() to set the model pointer after making a copy.
friend class Print; friend class Print;
@ -605,8 +616,7 @@ private:
friend class UndoRedo::StackImpl; friend class UndoRedo::StackImpl;
// Used for deserialization -> Don't allocate any IDs for the ModelObject or its config. // Used for deserialization -> Don't allocate any IDs for the ModelObject or its config.
ModelObject() : ModelObject() :
ObjectBase(-1), config(-1), layer_height_profile(-1), 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) {
assert(this->id().invalid()); assert(this->id().invalid());
assert(this->config.id().invalid()); assert(this->config.id().invalid());
assert(this->layer_height_profile.id().invalid()); assert(this->layer_height_profile.id().invalid());
@ -617,12 +627,17 @@ private:
Internal::StaticSerializationWrapper<LayerHeightProfile> layer_heigth_profile_wrapper(layer_height_profile); Internal::StaticSerializationWrapper<LayerHeightProfile> layer_heigth_profile_wrapper(layer_height_profile);
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_heigth_profile_wrapper, ar(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, 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); cut_connectors, cut_id);
} }
// Called by Print::validate() from the UI thread. // Called by Print::validate() from the UI thread.
unsigned int update_instances_print_volume_state(const BuildVolume &build_volume); 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 { enum class EnforcerBlockerType : int8_t {
@ -1106,7 +1121,7 @@ public:
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
ModelInstanceEPrintVolumeState print_volume_state; ModelInstanceEPrintVolumeState print_volume_state;
// Whether or not this instance is printable // Whether or not this instance is printable
bool printable; bool printable { true };
ModelObject* get_object() const { return this->object; } ModelObject* get_object() const { return this->object; }
@ -1156,9 +1171,7 @@ public:
// To be called on an external mesh // To be called on an external mesh
void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
// Calculate a bounding box of a transformed mesh. To be called on an external mesh. // Transform an external bounding box, thus the resulting bounding box is no more snug.
BoundingBoxf3 transform_mesh_bounding_box(const TriangleMesh& mesh, bool dont_translate = false) const;
// Transform an external bounding box.
BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const; BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const;
// Transform an external vector. // Transform an external vector.
Vec3d transform_vector(const Vec3d& v, bool dont_translate = false) const; Vec3d transform_vector(const Vec3d& v, bool dont_translate = false) const;
@ -1201,7 +1214,7 @@ private:
ModelObject* object; ModelObject* object;
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject* object) : print_volume_state(ModelInstancePVS_Inside), printable(true), object(object) { assert(this->id().valid()); } explicit ModelInstance(ModelObject* object) : print_volume_state(ModelInstancePVS_Inside), object(object) { assert(this->id().valid()); }
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object, const ModelInstance &other) : explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
m_transformation(other.m_transformation), print_volume_state(ModelInstancePVS_Inside), printable(other.printable), object(object) { assert(this->id().valid() && this->id() != other.id()); } m_transformation(other.m_transformation), print_volume_state(ModelInstancePVS_Inside), printable(other.printable), object(object) { assert(this->id().valid() && this->id() != other.id()); }
@ -1316,8 +1329,12 @@ public:
void delete_material(t_model_material_id material_id); void delete_material(t_model_material_id material_id);
void clear_materials(); void clear_materials();
bool add_default_instances(); bool add_default_instances();
// Returns approximate axis aligned bounding box of this model // Returns approximate axis aligned bounding box of this model.
BoundingBoxf3 bounding_box() const; 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, // Set the print_volume_state of PrintObject::instances,
// return total number of printable objects. // return total number of printable objects.
unsigned int update_print_volume_state(const BuildVolume &build_volume); unsigned int update_print_volume_state(const BuildVolume &build_volume);

View File

@ -77,7 +77,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
Vec3d bbox_center = bbox.center(); Vec3d bbox_center = bbox.center();
// We may need to rotate the bbox / bbox_center from the original instance to the current instance. // We may need to rotate the bbox / bbox_center from the original instance to the current instance.
double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_matrix(), instances.front().model_instance->get_matrix()); double z_diff = Geometry::rotation_diff_z(model_object->instances.front()->get_matrix(), instances.front().model_instance->get_matrix());
if (std::abs(z_diff) > EPSILON) { if (std::abs(z_diff) > EPSILON) {
auto z_rot = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()); auto z_rot = Eigen::AngleAxisd(z_diff, Vec3d::UnitZ());
bbox = bbox.transformed(Transform3d(z_rot)); bbox = bbox.transformed(Transform3d(z_rot));
bbox_center = (z_rot * bbox_center).eval(); bbox_center = (z_rot * bbox_center).eval();
@ -87,6 +87,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Transfor
m_center_offset = Point::new_scale(bbox_center.x(), bbox_center.y()); 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. // 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 = (bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
m_size.z() = model_object->max_z();
this->set_instances(std::move(instances)); this->set_instances(std::move(instances));
} }
@ -1736,7 +1737,7 @@ void PrintObject::update_slicing_parameters()
{ {
if (!m_slicing_params.valid) if (!m_slicing_params.valid)
m_slicing_params = SlicingParameters::create_from_config( 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) SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)

View File

@ -1440,7 +1440,7 @@ static void generate_initial_areas(
top_contacts[i] = nullptr; top_contacts[i] = nullptr;
move_bounds[i].clear(); move_bounds[i].clear();
} }
if (raft_contact_layer_idx != std::numeric_limits<coord_t>::max() && print_object.config().raft_expansion.value > 0) { if (raft_contact_layer_idx != std::numeric_limits<size_t>::max() && print_object.config().raft_expansion.value > 0) {
// If any tips at first_tree_layer now are completely inside the expanded raft layer, remove them as well before they are propagated to the ground. // If any tips at first_tree_layer now are completely inside the expanded raft layer, remove them as well before they are propagated to the ground.
Polygons &raft_polygons = top_contacts[raft_contact_layer_idx]->polygons; Polygons &raft_polygons = top_contacts[raft_contact_layer_idx]->polygons;
EdgeGrid::Grid grid(get_extents(raft_polygons).inflated(SCALED_EPSILON)); EdgeGrid::Grid grid(get_extents(raft_polygons).inflated(SCALED_EPSILON));

View File

@ -2246,7 +2246,7 @@ void GCodeViewer::load_shells(const Print& print)
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) { if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) {
// adds wipe tower's volume // adds wipe tower's volume
const double max_z = print.objects()[0]->model_object()->get_model()->bounding_box().max(2); const double max_z = print.objects()[0]->model_object()->get_model()->max_z();
const PrintConfig& config = print.config(); const PrintConfig& config = print.config();
const size_t extruders_count = config.nozzle_diameter.size(); const size_t extruders_count = config.nozzle_diameter.size();
if (extruders_count > 1 && config.wipe_tower && !config.complete_objects) { if (extruders_count > 1 && config.wipe_tower && !config.complete_objects) {

View File

@ -140,7 +140,7 @@ void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
// Maximum height of an object changes when the object gets rotated or scaled. // 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. // 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. // 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 || 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())) { (model_object_new != nullptr && m_model_object->id() != model_object_new->id())) {
m_layer_height_profile.clear(); m_layer_height_profile.clear();
@ -1977,7 +1977,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
if (extruders_count > 1 && wt && !co) { if (extruders_count > 1 && wt && !co) {
// Height of a print (Show at least a slab) // Height of a print (Show at least a slab)
const double height = std::max(m_model->bounding_box().max.z(), 10.0); const double height = std::max(m_model->max_z(), 10.0);
const float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value; const float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
const float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value; const float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;

View File

@ -3520,7 +3520,7 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const
ModelObject* old_model_object = model.objects[object_idx]; ModelObject* old_model_object = model.objects[object_idx];
ModelVolume* old_volume = old_model_object->volumes[volume_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(); ModelObject* new_model_object = new_model.objects.front();
old_model_object->add_volume(*new_model_object->volumes.front()); old_model_object->add_volume(*new_model_object->volumes.front());
@ -3835,7 +3835,7 @@ void Plater::priv::reload_from_disk()
ModelObject* old_model_object = model.objects[obj_idx]; ModelObject* old_model_object = model.objects[obj_idx];
ModelVolume* old_volume = old_model_object->volumes[vol_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()); 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());
bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string()); bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string());
@ -4816,7 +4816,7 @@ bool Plater::priv::layers_height_allowed() const
return false; return false;
int obj_idx = get_selected_object_idx(); 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 && return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->max_z() > SINKING_Z_THRESHOLD &&
config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed(); config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed();
} }
@ -7435,7 +7435,7 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
for (size_t obj_idx : object_idxs) { for (size_t obj_idx : object_idxs) {
if (obj_idx < p->model.objects.size()) { 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 // re - align to Z = 0
p->model.objects[obj_idx]->ensure_on_bed(); p->model.objects[obj_idx]->ensure_on_bed();
} }