Automatic placement of instance at bed level
This commit is contained in:
parent
66e97aa4eb
commit
503166a6a4
@ -712,18 +712,32 @@ void ModelObject::center_around_origin()
|
||||
|
||||
if (!this->instances.empty()) {
|
||||
for (ModelInstance *i : this->instances) {
|
||||
#if ENABLE_MIRROR
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
for (ModelVolume *v : this->volumes)
|
||||
@ -895,6 +909,42 @@ void ModelObject::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 num_printable = 0;
|
||||
@ -1136,7 +1186,11 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
|
||||
{
|
||||
// Rotate around mesh origin.
|
||||
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>());
|
||||
#endif // ENABLE_MIRROR
|
||||
BoundingBoxf3 bbox = copy.bounding_box();
|
||||
|
||||
if (!empty(bbox)) {
|
||||
|
@ -153,6 +153,9 @@ public:
|
||||
// A snug bounding box around the transformed non-modifier object volumes.
|
||||
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
||||
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(coordf_t x, coordf_t y, coordf_t z);
|
||||
void scale(const Vec3d &versor);
|
||||
@ -167,6 +170,9 @@ public:
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
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.
|
||||
unsigned int check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||
|
||||
|
@ -1478,6 +1478,98 @@ void GLCanvas3D::Selection::mirror(Axis axis)
|
||||
}
|
||||
#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
|
||||
{
|
||||
if (is_empty())
|
||||
@ -6666,6 +6758,14 @@ void GLCanvas3D::_on_move()
|
||||
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)
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
|
||||
|
||||
@ -6700,10 +6800,19 @@ void GLCanvas3D::_on_rotate()
|
||||
if (model_object != nullptr)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -6734,10 +6843,19 @@ void GLCanvas3D::_on_scale()
|
||||
if (model_object != nullptr)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -508,6 +508,9 @@ public:
|
||||
void mirror(Axis axis);
|
||||
#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;
|
||||
|
||||
private:
|
||||
|
@ -706,6 +706,7 @@ void ObjectList::load_part( ModelObject* model_object,
|
||||
if (model_object->origin_translation != Vec3d::Zero())
|
||||
{
|
||||
object->center_around_origin();
|
||||
object->ensure_on_bed();
|
||||
delta = model_object->origin_translation - object->origin_translation;
|
||||
}
|
||||
for (auto volume : object->volumes) {
|
||||
|
@ -1151,6 +1151,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
|
||||
if (type_3mf) {
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
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.add_model_object(object);
|
||||
}
|
||||
@ -1628,6 +1631,7 @@ void Plater::priv::split_object()
|
||||
{
|
||||
m->name = current_model_object->name + "_" + std::to_string(counter++);
|
||||
m->center_around_origin();
|
||||
m->ensure_on_bed();
|
||||
}
|
||||
|
||||
remove(obj_idx);
|
||||
@ -2552,6 +2556,7 @@ void Plater::changed_object_settings(int obj_idx)
|
||||
// recenter and re - align to Z = 0
|
||||
auto model_object = p->model.objects[obj_idx];
|
||||
model_object->center_around_origin();
|
||||
model_object->ensure_on_bed();
|
||||
}
|
||||
|
||||
// update print
|
||||
|
Loading…
Reference in New Issue
Block a user