mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-10-03 02:53:14 +08:00
Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_transformations
This commit is contained in:
commit
7b08170077
@ -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) {
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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));
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user