Automatic placement of instance at bed level

This commit is contained in:
Enrico Turri 2018-10-30 16:03:03 +01:00
parent 66e97aa4eb
commit 503166a6a4
6 changed files with 193 additions and 6 deletions

View File

@ -712,18 +712,32 @@ void ModelObject::center_around_origin()
if (!this->instances.empty()) { if (!this->instances.empty()) {
for (ModelInstance *i : this->instances) { for (ModelInstance *i : this->instances) {
#if ENABLE_MIRROR
i->set_offset(i->get_offset() - shift); i->set_offset(i->get_offset() - shift);
#else
// apply rotation and scaling to vector as well before translating instance,
// in order to leave final position unaltered
i->set_offset(i->get_offset() + i->transform_vector(-shift, true));
#endif // ENABLE_MIRROR
} }
this->invalidate_bounding_box(); this->invalidate_bounding_box();
} }
} }
void ModelObject::ensure_on_bed()
{
translate_instances(Vec3d(0.0, 0.0, -get_min_z()));
}
void ModelObject::translate_instances(const Vec3d& vector)
{
for (size_t i = 0; i < instances.size(); ++i)
{
translate_instance(i, vector);
}
}
void ModelObject::translate_instance(size_t instance_idx, const Vec3d& vector)
{
ModelInstance* i = instances[instance_idx];
i->set_offset(i->get_offset() + vector);
invalidate_bounding_box();
}
void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z) void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
{ {
for (ModelVolume *v : this->volumes) for (ModelVolume *v : this->volumes)
@ -895,6 +909,42 @@ void ModelObject::repair()
v->mesh.repair(); v->mesh.repair();
} }
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_instance_min_z(size_t instance_idx) const
{
double min_z = DBL_MAX;
ModelInstance* inst = instances[instance_idx];
Vec3d local_unit_z = (inst->world_matrix(true).inverse() * Vec3d::UnitZ()).normalized();
for (ModelVolume *v : volumes)
{
for (uint32_t f = 0; f < v->mesh.stl.stats.number_of_facets; ++f)
{
const stl_facet* facet = v->mesh.stl.facet_start + f;
min_z = std::min(min_z, local_unit_z.dot(facet->vertex[0].cast<double>()));
min_z = std::min(min_z, local_unit_z.dot(facet->vertex[1].cast<double>()));
min_z = std::min(min_z, local_unit_z.dot(facet->vertex[2].cast<double>()));
}
}
return min_z + inst->get_offset(Z);
}
unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) unsigned int ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
{ {
unsigned int num_printable = 0; unsigned int num_printable = 0;
@ -1136,7 +1186,11 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
{ {
// Rotate around mesh origin. // Rotate around mesh origin.
TriangleMesh copy(*mesh); TriangleMesh copy(*mesh);
#if ENABLE_MIRROR
copy.transform(world_matrix(true, false, true, true).cast<float>());
#else
copy.transform(world_matrix(true, false, true).cast<float>()); copy.transform(world_matrix(true, false, true).cast<float>());
#endif // ENABLE_MIRROR
BoundingBoxf3 bbox = copy.bounding_box(); BoundingBoxf3 bbox = copy.bounding_box();
if (!empty(bbox)) { if (!empty(bbox)) {

View File

@ -153,6 +153,9 @@ public:
// A snug bounding box around the transformed non-modifier object volumes. // A snug bounding box around the transformed non-modifier object volumes.
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const; BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
void center_around_origin(); void center_around_origin();
void ensure_on_bed();
void translate_instances(const Vec3d& vector);
void translate_instance(size_t instance_idx, const Vec3d& vector);
void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); } void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); }
void translate(coordf_t x, coordf_t y, coordf_t z); void translate(coordf_t x, coordf_t y, coordf_t z);
void scale(const Vec3d &versor); void scale(const Vec3d &versor);
@ -167,6 +170,9 @@ public:
void split(ModelObjectPtrs* new_objects); void split(ModelObjectPtrs* new_objects);
void repair(); void repair();
double get_min_z() const;
double get_instance_min_z(size_t instance_idx) const;
// Called by Print::validate() from the UI thread. // Called by Print::validate() from the UI thread.
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume); unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);

View File

@ -1478,6 +1478,98 @@ void GLCanvas3D::Selection::mirror(Axis axis)
} }
#endif // ENABLE_MIRROR #endif // ENABLE_MIRROR
void GLCanvas3D::Selection::translate(unsigned int object_idx, const Vec3d& displacement)
{
if (!m_valid)
return;
for (unsigned int i : m_list)
{
GLVolume* v = (*m_volumes)[i];
if (v->object_idx() == object_idx)
v->set_offset(v->get_offset() + displacement);
}
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
if (done.size() == m_volumes->size())
break;
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
// Process unselected volumes of the object.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
if (done.size() == m_volumes->size())
break;
if (done.find(j) != done.end())
continue;
GLVolume* v = (*m_volumes)[j];
if (v->object_idx() != object_idx)
continue;
v->set_offset(v->get_offset() + displacement);
done.insert(j);
}
}
m_bounding_box_dirty = true;
}
void GLCanvas3D::Selection::translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement)
{
if (!m_valid)
return;
for (unsigned int i : m_list)
{
GLVolume* v = (*m_volumes)[i];
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
v->set_offset(v->get_offset() + displacement);
}
std::set<unsigned int> done; // prevent processing volumes twice
done.insert(m_list.begin(), m_list.end());
for (unsigned int i : m_list)
{
if (done.size() == m_volumes->size())
break;
const GLVolume* volume = (*m_volumes)[i];
int object_idx = volume->object_idx();
if (object_idx >= 1000)
continue;
// Process unselected volumes of the object.
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
{
if (done.size() == m_volumes->size())
break;
if (done.find(j) != done.end())
continue;
GLVolume* v = (*m_volumes)[j];
if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx))
continue;
v->set_offset(v->get_offset() + displacement);
done.insert(j);
}
}
m_bounding_box_dirty = true;
}
void GLCanvas3D::Selection::render(bool show_indirect_selection) const void GLCanvas3D::Selection::render(bool show_indirect_selection) const
{ {
if (is_empty()) if (is_empty())
@ -6666,6 +6758,14 @@ void GLCanvas3D::_on_move()
wipe_tower_origin = v->get_offset(); wipe_tower_origin = v->get_offset();
} }
for (const std::pair<int, int>& i : done)
{
ModelObject* m = m_model->objects[i.first];
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
}
if (object_moved) if (object_moved)
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
@ -6700,10 +6800,19 @@ void GLCanvas3D::_on_rotate()
if (model_object != nullptr) if (model_object != nullptr)
{ {
model_object->instances[instance_idx]->set_rotation(v->get_rotation()); model_object->instances[instance_idx]->set_rotation(v->get_rotation());
model_object->instances[instance_idx]->set_offset(v->get_offset());
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
} }
for (const std::pair<int, int>& i : done)
{
ModelObject* m = m_model->objects[i.first];
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
}
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
} }
@ -6734,10 +6843,19 @@ void GLCanvas3D::_on_scale()
if (model_object != nullptr) if (model_object != nullptr)
{ {
model_object->instances[instance_idx]->set_scaling_factor(v->get_scaling_factor()); model_object->instances[instance_idx]->set_scaling_factor(v->get_scaling_factor());
model_object->instances[instance_idx]->set_offset(v->get_offset());
model_object->invalidate_bounding_box(); model_object->invalidate_bounding_box();
} }
} }
for (const std::pair<int, int>& i : done)
{
ModelObject* m = m_model->objects[i.first];
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
}
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
} }

View File

@ -508,6 +508,9 @@ public:
void mirror(Axis axis); void mirror(Axis axis);
#endif // ENABLE_MIRROR #endif // ENABLE_MIRROR
void translate(unsigned int object_idx, const Vec3d& displacement);
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
void render(bool show_indirect_selection) const; void render(bool show_indirect_selection) const;
private: private:

View File

@ -706,6 +706,7 @@ void ObjectList::load_part( ModelObject* model_object,
if (model_object->origin_translation != Vec3d::Zero()) if (model_object->origin_translation != Vec3d::Zero())
{ {
object->center_around_origin(); object->center_around_origin();
object->ensure_on_bed();
delta = model_object->origin_translation - object->origin_translation; delta = model_object->origin_translation - object->origin_translation;
} }
for (auto volume : object->volumes) { for (auto volume : object->volumes) {

View File

@ -1151,6 +1151,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
if (type_3mf) { if (type_3mf) {
for (ModelObject* model_object : model.objects) { for (ModelObject* model_object : model.objects) {
model_object->center_around_origin(); model_object->center_around_origin();
model_object->ensure_on_bed();
} }
} }
@ -1235,6 +1236,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
} }
} }
object->ensure_on_bed();
// print.auto_assign_extruders(object); // print.auto_assign_extruders(object);
// print.add_model_object(object); // print.add_model_object(object);
} }
@ -1628,6 +1631,7 @@ void Plater::priv::split_object()
{ {
m->name = current_model_object->name + "_" + std::to_string(counter++); m->name = current_model_object->name + "_" + std::to_string(counter++);
m->center_around_origin(); m->center_around_origin();
m->ensure_on_bed();
} }
remove(obj_idx); remove(obj_idx);
@ -2552,6 +2556,7 @@ void Plater::changed_object_settings(int obj_idx)
// recenter and re - align to Z = 0 // recenter and re - align to Z = 0
auto model_object = p->model.objects[obj_idx]; auto model_object = p->model.objects[obj_idx];
model_object->center_around_origin(); model_object->center_around_origin();
model_object->ensure_on_bed();
} }
// update print // update print