mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-07 15:07:31 -06:00
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:
parent
d1eea4c677
commit
73ab032e82
12 changed files with 186 additions and 137 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue