Fix of "Variable layer height feature breaks after rotating part #2073"

There was an approximate bounding box used at the GUI, while a snug
bounding box was used at the back end, causing invalidation
of the variable layer height editing profile on rotated objects.

A snug bounding box around the first instance is now cached.
This commit is contained in:
bubnikv 2019-04-13 14:15:54 +02:00
parent b0c33a1fe9
commit 1e455bc065
5 changed files with 54 additions and 38 deletions

View file

@ -593,6 +593,8 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->origin_translation = rhs.origin_translation;
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;
@ -627,6 +629,8 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
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;
@ -859,7 +863,7 @@ TriangleMesh ModelObject::full_raw_mesh() const
return mesh;
}
BoundingBoxf3 ModelObject::raw_mesh_bounding_box() const
const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
{
if (! m_raw_mesh_bounding_box_valid) {
m_raw_mesh_bounding_box_valid = true;
@ -880,33 +884,36 @@ BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
}
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
BoundingBoxf3 ModelObject::raw_bounding_box() const
// This bounding box is only used for the actual slicing and for layer editing UI to calculate the layers.
const BoundingBoxf3& ModelObject::raw_bounding_box() const
{
BoundingBoxf3 bb;
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
if (! m_raw_bounding_box_valid) {
m_raw_bounding_box_valid = true;
m_raw_bounding_box.reset();
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
for (const ModelVolume *v : this->volumes)
if (v->is_model_part()) {
#if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
if (this->instances.empty())
throw std::invalid_argument("Can't call raw_bounding_box() with no instances");
#endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
#else
// unmaintaned
assert(false);
// vol_mesh.transform(v->get_matrix());
// bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
}
return bb;
#if ENABLE_GENERIC_SUBPARTS_PLACEMENT
m_raw_bounding_box.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix()));
#else
// unmaintaned
assert(false);
// vol_mesh.transform(v->get_matrix());
// m_raw_bounding_box_valid.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true));
#endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
}
}
return m_raw_bounding_box;
}
// This returns an accurate snug bounding box of the transformed object instance, without the translation applied.

View file

@ -212,7 +212,7 @@ public:
// 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_mesh_bounding_box_valid = false; }
void invalidate_bounding_box() { m_bounding_box_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;
@ -223,11 +223,11 @@ public:
TriangleMesh full_raw_mesh() const;
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
BoundingBoxf3 raw_bounding_box() const;
const BoundingBoxf3& raw_bounding_box() const;
// A snug bounding box around the transformed non-modifier object volumes.
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
BoundingBoxf3 raw_mesh_bounding_box() const;
const BoundingBoxf3& raw_mesh_bounding_box() const;
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
BoundingBoxf3 full_raw_mesh_bounding_box() const;
@ -285,7 +285,7 @@ protected:
private:
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
m_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
~ModelObject();
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
@ -304,6 +304,8 @@ private:
// Bounding box, cached.
mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_valid;
mutable BoundingBoxf3 m_raw_bounding_box;
mutable bool m_raw_bounding_box_valid;
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
mutable bool m_raw_mesh_bounding_box_valid;
};

View file

@ -132,7 +132,7 @@ public:
// The slicing parameters are dependent on various configuration values
// (layer height, first layer height, raft settings, print nozzle diameter etc).
const SlicingParameters& slicing_parameters() const { return m_slicing_params; }
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z);
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
std::vector<unsigned int> object_extruders() const;

View file

@ -1370,7 +1370,7 @@ void PrintObject::update_slicing_parameters()
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
}
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object, float object_max_z)
{
PrintConfig print_config;
PrintObjectConfig object_config;
@ -1390,7 +1390,9 @@ SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full
object_extruders);
sort_remove_duplicates(object_extruders);
return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders);
if (object_max_z <= 0.f)
object_max_z = model_object.raw_bounding_box().size().z();
return SlicingParameters::create_from_config(print_config, object_config, object_max_z, object_extruders);
}
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)

View file

@ -255,16 +255,21 @@ void GLCanvas3D::LayersEditing::set_config(const DynamicPrintConfig* config)
void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
{
const ModelObject *model_object_new = (object_id >= 0) ? model.objects[object_id] : nullptr;
if (model_object_new == nullptr || this->last_object_id != object_id || m_model_object != model_object_new || m_model_object->id() != model_object_new->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->raw_bounding_box() is cached, therefore it is cheap even if this method is called frequently.
float new_max_z = (m_model_object == nullptr) ? 0.f : m_model_object->raw_bounding_box().size().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();
m_layer_height_profile_modified = false;
delete m_slicing_parameters;
m_slicing_parameters = nullptr;
m_slicing_parameters = nullptr;
m_layers_texture.valid = false;
this->last_object_id = object_id;
m_model_object = model_object_new;
m_object_max_z = new_max_z;
}
this->last_object_id = object_id;
m_model_object = model_object_new;
m_object_max_z = (m_model_object == nullptr) ? 0.f : m_model_object->bounding_box().max.z();
}
bool GLCanvas3D::LayersEditing::is_allowed() const
@ -623,7 +628,7 @@ void GLCanvas3D::LayersEditing::update_slicing_parameters()
{
if (m_slicing_parameters == nullptr) {
m_slicing_parameters = new SlicingParameters();
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object);
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object, m_object_max_z);
}
}