Performance improvements:

Lazy "Place on face" gizmo update.
Caching of MeshObject::raw_mesh_bounding_box() for the object size display.
ModelObject::bounding_box(), raw_mesh_bounding_box(), full_raw_mesh_bounding_box() will not copy the mesh.
TriangleMesh::transformed_bounding_box(const Transform3d &trafo) will not copy the mesh data.
get_options_for_bundle() will not return reference to temp value
is_splittable() calls cheap mesh.has_multiple_patches()
This commit is contained in:
bubnikv 2019-01-26 18:51:34 +01:00
parent 48d64b0842
commit 588c07c12a
10 changed files with 76 additions and 108 deletions

View file

@ -32,6 +32,7 @@ public:
} }
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)); this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
} }
void reset() { this->defined = false; this->min = PointClass::Zero(); this->max = PointClass::Zero(); }
void merge(const PointClass &point); void merge(const PointClass &point);
void merge(const std::vector<PointClass> &points); void merge(const std::vector<PointClass> &points);
void merge(const BoundingBoxBase<PointClass> &bb); void merge(const BoundingBoxBase<PointClass> &bb);

View file

@ -573,6 +573,8 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->origin_translation = rhs.origin_translation; this->origin_translation = rhs.origin_translation;
m_bounding_box = rhs.m_bounding_box; m_bounding_box = rhs.m_bounding_box;
m_bounding_box_valid = rhs.m_bounding_box_valid; m_bounding_box_valid = rhs.m_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->clear_volumes(); this->clear_volumes();
this->volumes.reserve(rhs.volumes.size()); this->volumes.reserve(rhs.volumes.size());
@ -604,6 +606,8 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
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 = std::move(rhs.m_bounding_box);
m_bounding_box_valid = std::move(rhs.m_bounding_box_valid); m_bounding_box_valid = std::move(rhs.m_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->clear_volumes(); this->clear_volumes();
this->volumes = std::move(rhs.volumes); this->volumes = std::move(rhs.volumes);
@ -783,19 +787,11 @@ void ModelObject::clear_instances()
const BoundingBoxf3& ModelObject::bounding_box() const const BoundingBoxf3& ModelObject::bounding_box() const
{ {
if (! m_bounding_box_valid) { if (! m_bounding_box_valid) {
BoundingBoxf3 raw_bbox;
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
{
TriangleMesh m = v->mesh;
m.transform(v->get_matrix());
raw_bbox.merge(m.bounding_box());
}
BoundingBoxf3 bb;
for (const ModelInstance *i : this->instances)
bb.merge(i->transform_bounding_box(raw_bbox));
m_bounding_box = bb;
m_bounding_box_valid = true; m_bounding_box_valid = true;
BoundingBoxf3 raw_bbox = this->raw_mesh_bounding_box();
m_bounding_box.reset();
for (const ModelInstance *i : this->instances)
m_bounding_box.merge(i->transform_bounding_box(raw_bbox));
} }
return m_bounding_box; return m_bounding_box;
} }
@ -842,6 +838,26 @@ TriangleMesh ModelObject::full_raw_mesh() const
return mesh; return mesh;
} }
BoundingBoxf3 ModelObject::raw_mesh_bounding_box() const
{
if (! m_raw_mesh_bounding_box_valid) {
m_raw_mesh_bounding_box_valid = true;
m_raw_mesh_bounding_box.reset();
for (const ModelVolume *v : this->volumes)
if (v->is_model_part())
m_raw_mesh_bounding_box.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
}
return m_raw_mesh_bounding_box;
}
BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
{
BoundingBoxf3 bb;
for (const ModelVolume *v : this->volumes)
bb.merge(v->mesh.transformed_bounding_box(v->get_matrix()));
return bb;
}
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied. // 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. // This bounding box is only used for the actual slicing.
BoundingBoxf3 ModelObject::raw_bounding_box() const BoundingBoxf3 ModelObject::raw_bounding_box() const
@ -896,20 +912,6 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
return bb; return bb;
} }
#if ENABLE_VOLUMES_CENTERING_FIXES
BoundingBoxf3 ModelObject::full_raw_mesh_bounding_box() const
{
BoundingBoxf3 bb;
for (const ModelVolume *v : this->volumes)
{
TriangleMesh vol_mesh(v->mesh);
vol_mesh.transform(v->get_matrix());
bb.merge(vol_mesh.bounding_box());
}
return bb;
}
#endif // ENABLE_VOLUMES_CENTERING_FIXES
void ModelObject::center_around_origin() void ModelObject::center_around_origin()
{ {
// calculate the displacements needed to // calculate the displacements needed to

View file

@ -205,7 +205,7 @@ public:
// This bounding box is approximate and not snug. // This bounding box is approximate and not snug.
// This bounding box is being cached. // This bounding box is being cached.
const BoundingBoxf3& bounding_box() const; const BoundingBoxf3& bounding_box() const;
void invalidate_bounding_box() { m_bounding_box_valid = false; } void invalidate_bounding_box() { m_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;
@ -219,10 +219,10 @@ public:
BoundingBoxf3 raw_bounding_box() const; BoundingBoxf3 raw_bounding_box() const;
// 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;
#if ENABLE_VOLUMES_CENTERING_FIXES // A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
// Bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes. 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; BoundingBoxf3 full_raw_mesh_bounding_box() const;
#endif // ENABLE_VOLUMES_CENTERING_FIXES
void center_around_origin(); void center_around_origin();
void ensure_on_bed(); void ensure_on_bed();
void translate_instances(const Vec3d& vector); void translate_instances(const Vec3d& vector);
@ -261,7 +261,8 @@ protected:
void set_model(Model *model) { m_model = model; } void set_model(Model *model) { m_model = model; }
private: private:
ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {} ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()),
m_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) {}
~ModelObject(); ~ModelObject();
/* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */ /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
@ -280,6 +281,8 @@ private:
// Bounding box, cached. // Bounding box, cached.
mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_bounding_box;
mutable bool m_bounding_box_valid; mutable bool m_bounding_box_valid;
mutable BoundingBoxf3 m_raw_mesh_bounding_box;
mutable bool m_raw_mesh_bounding_box_valid;
}; };
// An object STL, or a modifier volume, over which a different set of parameters shall be applied. // An object STL, or a modifier volume, over which a different set of parameters shall be applied.

View file

@ -525,67 +525,22 @@ BoundingBoxf3 TriangleMesh::bounding_box() const
return bb; return bb;
} }
BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) const
{ {
bool has_shared = (stl.v_shared != nullptr); BoundingBoxf3 bbox;
if (!has_shared) if (stl.v_shared == nullptr) {
stl_generate_shared_vertices(const_cast<stl_file*>(&stl)); // Using the STL faces.
for (int i = 0; i < this->facets_count(); ++ i) {
unsigned int vertices_count = (stl.stats.shared_vertices > 0) ? (unsigned int)stl.stats.shared_vertices : 3 * (unsigned int)stl.stats.number_of_facets; const stl_facet &facet = this->stl.facet_start[i];
for (size_t j = 0; j < 3; ++ j)
if (vertices_count == 0) bbox.merge(trafo * facet.vertex[j].cast<double>());
return BoundingBoxf3();
Eigen::MatrixXd src_vertices(3, vertices_count);
if (stl.stats.shared_vertices > 0)
{
assert(stl.v_shared != nullptr);
stl_vertex* vertex_ptr = stl.v_shared;
for (int i = 0; i < stl.stats.shared_vertices; ++i)
{
src_vertices(0, i) = (double)(*vertex_ptr)(0);
src_vertices(1, i) = (double)(*vertex_ptr)(1);
src_vertices(2, i) = (double)(*vertex_ptr)(2);
vertex_ptr += 1;
} }
} else {
// Using the shared vertices should be a bit quicker than using the STL faces.
for (int i = 0; i < stl.stats.shared_vertices; ++ i)
bbox.merge(trafo * this->stl.v_shared[i].cast<double>());
} }
else return bbox;
{
stl_facet* facet_ptr = stl.facet_start;
unsigned int v_id = 0;
while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
{
for (int i = 0; i < 3; ++i)
{
src_vertices(0, v_id) = (double)facet_ptr->vertex[i](0);
src_vertices(1, v_id) = (double)facet_ptr->vertex[i](1);
src_vertices(2, v_id) = (double)facet_ptr->vertex[i](2);
++v_id;
}
facet_ptr += 1;
}
}
if (!has_shared && (stl.stats.shared_vertices > 0))
stl_invalidate_shared_vertices(const_cast<stl_file*>(&stl));
Eigen::MatrixXd dst_vertices(3, vertices_count);
dst_vertices = t * src_vertices.colwise().homogeneous();
Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0));
Vec3d v_max = v_min;
for (int i = 1; i < vertices_count; ++i)
{
for (int j = 0; j < 3; ++j)
{
v_min(j) = std::min(v_min(j), dst_vertices(j, i));
v_max(j) = std::max(v_max(j), dst_vertices(j, i));
}
}
return BoundingBoxf3(v_min, v_max);
} }
TriangleMesh TriangleMesh::convex_hull_3d() const TriangleMesh TriangleMesh::convex_hull_3d() const
@ -2010,4 +1965,5 @@ TriangleMesh make_sphere(double rho, double fa) {
TriangleMesh mesh(vertices, facets); TriangleMesh mesh(vertices, facets);
return mesh; return mesh;
} }
} }

View file

@ -60,7 +60,7 @@ public:
Polygon convex_hull(); Polygon convex_hull();
BoundingBoxf3 bounding_box() const; BoundingBoxf3 bounding_box() const;
// Returns the bbox of this TriangleMesh transformed by the given transformation // Returns the bbox of this TriangleMesh transformed by the given transformation
BoundingBoxf3 transformed_bounding_box(const Transform3d& t) const; BoundingBoxf3 transformed_bounding_box(const Transform3d &trafo) const;
// Returns the convex hull of this TriangleMesh // Returns the convex hull of this TriangleMesh
TriangleMesh convex_hull_3d() const; TriangleMesh convex_hull_3d() const;
void reset_repair_stats(); void reset_repair_stats();

View file

@ -1428,6 +1428,7 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection)
{ {
if (m_hover_id != -1) if (m_hover_id != -1)
{ {
assert(m_planes_valid);
m_normal = m_planes[m_hover_id].normal; m_normal = m_planes[m_hover_id].normal;
m_starting_center = selection.get_bounding_box().center(); m_starting_center = selection.get_bounding_box().center();
} }
@ -1446,6 +1447,8 @@ void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const
::glPushMatrix(); ::glPushMatrix();
::glMultMatrixd(m.data()); ::glMultMatrixd(m.data());
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
if (this->is_plane_update_necessary())
const_cast<GLGizmoFlatten*>(this)->update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) for (int i = 0; i < (int)m_planes.size(); ++i)
{ {
if (i == m_hover_id) if (i == m_hover_id)
@ -1478,6 +1481,8 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
::glPushMatrix(); ::glPushMatrix();
::glMultMatrixd(m.data()); ::glMultMatrixd(m.data());
::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z());
if (this->is_plane_update_necessary())
const_cast<GLGizmoFlatten*>(this)->update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) for (int i = 0; i < (int)m_planes.size(); ++i)
{ {
::glColor3f(1.0f, 1.0f, picking_color_component(i)); ::glColor3f(1.0f, 1.0f, picking_color_component(i));
@ -1497,11 +1502,11 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
{ {
m_starting_center = Vec3d::Zero(); m_starting_center = Vec3d::Zero();
bool object_changed = m_model_object != model_object; if (m_model_object != model_object) {
m_planes.clear();
m_planes_valid = false;
}
m_model_object = model_object; m_model_object = model_object;
if (model_object && (object_changed || is_plane_update_necessary()))
update_planes();
} }
void GLGizmoFlatten::update_planes() void GLGizmoFlatten::update_planes()
@ -1701,6 +1706,8 @@ void GLGizmoFlatten::update_planes()
} }
m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor(); m_first_instance_scale = m_model_object->instances.front()->get_scaling_factor();
m_first_instance_mirror = m_model_object->instances.front()->get_mirror(); m_first_instance_mirror = m_model_object->instances.front()->get_mirror();
m_planes_valid = true;
} }
@ -1709,7 +1716,7 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
if (m_state != On || !m_model_object || m_model_object->instances.empty()) if (m_state != On || !m_model_object || m_model_object->instances.empty())
return false; return false;
if (m_model_object->volumes.size() != m_volumes_matrices.size()) if (! m_planes_valid || m_model_object->volumes.size() != m_volumes_matrices.size())
return true; return true;
// We want to recalculate when the scale changes - some planes could (dis)appear. // We want to recalculate when the scale changes - some planes could (dis)appear.

View file

@ -408,6 +408,7 @@ private:
Vec3d m_first_instance_mirror; Vec3d m_first_instance_mirror;
std::vector<PlaneData> m_planes; std::vector<PlaneData> m_planes;
bool m_planes_valid = false;
mutable Vec3d m_starting_center; mutable Vec3d m_starting_center;
const ModelObject* m_model_object = nullptr; const ModelObject* m_model_object = nullptr;
std::vector<const Transform3d*> instances_matrices; std::vector<const Transform3d*> instances_matrices;

View file

@ -621,7 +621,8 @@ const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_na
if (bundle_name == _(it.first)) if (bundle_name == _(it.first))
return it.second; return it.second;
} }
return std::vector<std::string> {}; static std::vector<std::string> empty;
return empty;
} }
// category -> vector ( option ; label ) // category -> vector ( option ; label )
@ -1276,15 +1277,12 @@ bool ObjectList::is_splittable()
if (!get_volume_by_item(item, volume) || !volume) if (!get_volume_by_item(item, volume) || !volume)
return false; return false;
if (volume->is_splittable() != -1) // if is_splittable value is already known int splittable = volume->is_splittable();
return volume->is_splittable() == 0 ? false : true; if (splittable == -1) {
splittable = (int)volume->mesh.has_multiple_patches();
TriangleMeshPtrs meshptrs = volume->mesh.split(); volume->set_splittable(splittable);
bool splittable = meshptrs.size() > 1; }
for (TriangleMesh* m : meshptrs) { delete m; } return splittable != 0;
volume->set_splittable(splittable ? 1 : 0);
return splittable;
} }
bool ObjectList::selected_instances_of_same_object() bool ObjectList::selected_instances_of_same_object()

View file

@ -267,7 +267,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
bool changed_box = false; bool changed_box = false;
if (!m_cache.instance.matches_object(obj_idx)) if (!m_cache.instance.matches_object(obj_idx))
{ {
m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size()); m_cache.instance.set(obj_idx, instance_idx, (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size());
changed_box = true; changed_box = true;
} }
if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale))
@ -278,7 +278,7 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
m_new_size = Vec3d::Zero(); m_new_size = Vec3d::Zero();
#else #else
if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size()))
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh().bounding_box().size(); m_new_size = volume->get_instance_transformation().get_matrix(true, true) * (*wxGetApp().model_objects())[obj_idx]->raw_mesh_bounding_box().size();
else else
// this should never happen // this should never happen
m_new_size = Vec3d::Zero(); m_new_size = Vec3d::Zero();

View file

@ -2105,7 +2105,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx)
o->clear_instances(); o->clear_instances();
for (auto instance: model_object->instances) for (auto instance: model_object->instances)
o->add_instance(*instance); o->add_instance(*instance);
// o->invalidate_bounding_box(); o->invalidate_bounding_box();
if (o->volumes.size() == model_object->volumes.size()) { if (o->volumes.size() == model_object->volumes.size()) {
for (int i = 0; i < o->volumes.size(); i++) { for (int i = 0; i < o->volumes.size(); i++) {