FIX:fix GLmodel deconstruction causing section not to be rendered

Jira: STUDIO-5156
Change-Id: Ibb2f459920989ee54f7b827352dc8893424b4de6
This commit is contained in:
zhou.xu 2023-11-08 12:04:50 +08:00 committed by Lane.Wei
parent ab812bfb7c
commit 0b68a3ac72
2 changed files with 61 additions and 36 deletions

View File

@ -18,9 +18,14 @@
namespace Slic3r { namespace GUI { namespace Slic3r { namespace GUI {
MeshClipper::~MeshClipper() {
reset();
}
void MeshClipper::set_behaviour(bool fill_cut, double contour_width) void MeshClipper::set_behaviour(bool fill_cut, double contour_width)
{ {
if (fill_cut != m_fill_cut || !is_approx(contour_width, m_contour_width)) m_result.reset(); if (fill_cut != m_fill_cut || !is_approx(contour_width, m_contour_width))
reset();
m_fill_cut = fill_cut; m_fill_cut = fill_cut;
m_contour_width = contour_width; m_contour_width = contour_width;
} }
@ -29,7 +34,7 @@ void MeshClipper::set_plane(const ClippingPlane &plane)
{ {
if (m_plane != plane) { if (m_plane != plane) {
m_plane = plane; m_plane = plane;
m_result.reset(); reset();
} }
} }
@ -37,7 +42,7 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane)
{ {
if (m_limiting_plane != plane) { if (m_limiting_plane != plane) {
m_limiting_plane = plane; m_limiting_plane = plane;
m_result.reset(); reset();
} }
} }
@ -45,7 +50,7 @@ void MeshClipper::set_mesh(const TriangleMesh& mesh)
{ {
if (m_mesh != &mesh) { if (m_mesh != &mesh) {
m_mesh = &mesh; m_mesh = &mesh;
m_result.reset(); reset();
} }
} }
@ -53,7 +58,7 @@ void MeshClipper::set_negative_mesh(const TriangleMesh& mesh)
{ {
if (m_negative_mesh != &mesh) { if (m_negative_mesh != &mesh) {
m_negative_mesh = &mesh; m_negative_mesh = &mesh;
m_result.reset(); reset();
} }
} }
@ -63,7 +68,7 @@ void MeshClipper::set_transformation(const Geometry::Transformation& trafo)
{ {
if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) { if (! m_trafo.get_matrix().isApprox(trafo.get_matrix())) {
m_trafo = trafo; m_trafo = trafo;
m_result.reset(); reset();
} }
} }
@ -81,10 +86,10 @@ void MeshClipper::render_cut(const ColorRGBA &color, const std::vector<size_t> *
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
for (size_t i = 0; i < m_result->cut_islands.size(); ++i) { for (size_t i = 0; i < m_result->cut_islands.size(); ++i) {
if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) continue; if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) continue;
CutIsland &isl = m_result->cut_islands[i]; auto isl = m_result->cut_islands[i];
ColorRGBA gray{0.5f, 0.5f, 0.5f, 1.f}; ColorRGBA gray{0.5f, 0.5f, 0.5f, 1.f};
isl.model.set_color(-1, isl.disabled ? gray : color); isl->model.set_color(-1, isl->disabled ? gray : color);
isl.model.render(); isl->model.render();
} }
shader->stop_using(); shader->stop_using();
} }
@ -107,10 +112,10 @@ void MeshClipper::render_contour(const ColorRGBA &color, const std::vector<size_
shader->set_uniform("projection_matrix", camera.get_projection_matrix()); shader->set_uniform("projection_matrix", camera.get_projection_matrix());
for (size_t i = 0; i < m_result->cut_islands.size(); ++i) { for (size_t i = 0; i < m_result->cut_islands.size(); ++i) {
if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) continue; if (ignore_idxs && std::binary_search(ignore_idxs->begin(), ignore_idxs->end(), i)) continue;
CutIsland &isl = m_result->cut_islands[i]; auto isl = m_result->cut_islands[i];
ColorRGBA red{1.0f, 0.f, 0.f, 1.f}; ColorRGBA red{1.0f, 0.f, 0.f, 1.f};
isl.model_expanded.set_color(-1, isl.disabled ? red : color); isl->model_expanded.set_color(-1, isl->disabled ? red : color);
isl.model_expanded.render(); isl->model_expanded.render();
} }
shader->stop_using(); shader->stop_using();
} }
@ -127,8 +132,8 @@ int MeshClipper::is_projection_inside_cut(const Vec3d &point_in) const
Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y())); Point pt_2d = Point::new_scale(Vec2d(point.x(), point.y()));
for (int i = 0; i < int(m_result->cut_islands.size()); ++i) { for (int i = 0; i < int(m_result->cut_islands.size()); ++i) {
const CutIsland &isl = m_result->cut_islands[i]; auto isl = m_result->cut_islands[i];
if (isl.expoly_bb.contains(pt_2d) && isl.expoly.contains(pt_2d)) if (isl->expoly_bb.contains(pt_2d) && isl->expoly.contains(pt_2d))
return i; // TODO: handle intersecting contours return i; // TODO: handle intersecting contours
} }
return -1; return -1;
@ -136,7 +141,7 @@ int MeshClipper::is_projection_inside_cut(const Vec3d &point_in) const
bool MeshClipper::has_valid_contour() const bool MeshClipper::has_valid_contour() const
{ {
return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland &isl) { return !isl.expoly.empty(); }); return m_result && std::any_of(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](CutIsland *isl) { return isl &&!isl->expoly.empty(); });
} }
std::vector<Vec3d> MeshClipper::point_per_contour() const { std::vector<Vec3d> MeshClipper::point_per_contour() const {
@ -145,7 +150,7 @@ std::vector<Vec3d> MeshClipper::point_per_contour() const {
return out; return out;
} }
assert(m_result); assert(m_result);
for (const CutIsland &isl : m_result->cut_islands) { for (auto isl : m_result->cut_islands) {
assert(isl.expoly.contour.size() > 2); assert(isl.expoly.contour.size() > 2);
// Now return a point lying inside the contour but not in a hole. // Now return a point lying inside the contour but not in a hole.
// We do this by taking a point lying close to the edge, repeating // We do this by taking a point lying close to the edge, repeating
@ -154,27 +159,27 @@ std::vector<Vec3d> MeshClipper::point_per_contour() const {
bool done = false; bool done = false;
Vec2d p; Vec2d p;
size_t i = 1; size_t i = 1;
while (i < isl.expoly.contour.size()) { while (i < isl->expoly.contour.size()) {
const Vec2d &a = unscale(isl.expoly.contour.points[i - 1]); const Vec2d &a = unscale(isl->expoly.contour.points[i - 1]);
const Vec2d &b = unscale(isl.expoly.contour.points[i]); const Vec2d &b = unscale(isl->expoly.contour.points[i]);
Vec2d n = (b - a).normalized(); Vec2d n = (b - a).normalized();
std::swap(n.x(), n.y()); std::swap(n.x(), n.y());
n.x() = -1 * n.x(); n.x() = -1 * n.x();
double f = 10.; double f = 10.;
while (f > 0.05) { while (f > 0.05) {
p = (0.5 * (b + a)) + f * n; p = (0.5 * (b + a)) + f * n;
if (isl.expoly.contains(Point::new_scale(p))) { if (isl->expoly.contains(Point::new_scale(p))) {
done = true; done = true;
break; break;
} }
f = f / 10.; f = f / 10.;
} }
if (done) break; if (done) break;
i += std::max(size_t(2), isl.expoly.contour.size() / 5); i += std::max(size_t(2), isl->expoly.contour.size() / 5);
} }
// If the above failed, just return the centroid, regardless of whether // If the above failed, just return the centroid, regardless of whether
// it is inside the contour or in a hole (we must return something). // it is inside the contour or in a hole (we must return something).
Vec2d c = done ? p : unscale(isl.expoly.contour.centroid()); Vec2d c = done ? p : unscale(isl->expoly.contour.centroid());
out.emplace_back(m_result->trafo * Vec3d(c.x(), c.y(), 0.)); out.emplace_back(m_result->trafo * Vec3d(c.x(), c.y(), 0.));
} }
return out; return out;
@ -268,12 +273,15 @@ void MeshClipper::recalculate_triangles()
std::vector<Vec2f> triangles2d; std::vector<Vec2f> triangles2d;
m_result->cut_islands.resize(expolys.size());
int isl_index = 0;
for (const ExPolygon &exp : expolys) { for (const ExPolygon &exp : expolys) {
triangles2d.clear(); triangles2d.clear();
if (!m_result->cut_islands[isl_index]) {
m_result->cut_islands.push_back(CutIsland()); m_result->cut_islands[isl_index] = new CutIsland();
CutIsland &isl = m_result->cut_islands.back(); }
CutIsland* isl = m_result->cut_islands[isl_index];
isl_index++;
if (m_fill_cut) { if (m_fill_cut) {
triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.); triangles2d = triangulate_expolygon_2f(exp, m_trafo.get_matrix().matrix().determinant() < 0.);
GLModel::InitializationData init_data; // GLModel::Geometry init_data; GLModel::InitializationData init_data; // GLModel::Geometry init_data;
@ -309,7 +317,10 @@ void MeshClipper::recalculate_triangles()
init_data.entities.back().indices.push_back((unsigned int) idx + 2); init_data.entities.back().indices.push_back((unsigned int) idx + 2);
} }
if (init_data.entities.back().indices.size() != 0) isl.model.init_from(std::move(init_data)); if (init_data.entities.back().indices.size() != 0) {
isl->model.reset();
isl->model.init_from(std::move(init_data));
}
} }
if (m_contour_width != 0. && !exp.contour.empty()) { if (m_contour_width != 0. && !exp.contour.empty()) {
@ -373,23 +384,36 @@ void MeshClipper::recalculate_triangles()
init_data.entities.back().indices.push_back((unsigned int) idx + 2); init_data.entities.back().indices.push_back((unsigned int) idx + 2);
} }
if (init_data.entities.back().indices.size() != 0) isl.model_expanded.init_from(std::move(init_data)); if (init_data.entities.back().indices.size() != 0) {
isl->model_expanded.reset();
isl->model_expanded.init_from(std::move(init_data));
}
} }
isl.expoly = std::move(exp); isl->expoly = std::move(exp);
isl.expoly_bb = get_extents(isl.expoly); isl->expoly_bb = get_extents(isl->expoly);
Point centroid_scaled = isl.expoly.contour.centroid(); Point centroid_scaled = isl->expoly.contour.centroid();
Vec3d centroid_world = m_result->trafo * Vec3d(unscale(centroid_scaled).x(), unscale(centroid_scaled).y(), 0.); Vec3d centroid_world = m_result->trafo * Vec3d(unscale(centroid_scaled).x(), unscale(centroid_scaled).y(), 0.);
isl.hash = isl.expoly.contour.size() + size_t(std::abs(100. * centroid_world.x())) + size_t(std::abs(100. * centroid_world.y())) + isl->hash = isl->expoly.contour.size() + size_t(std::abs(100. * centroid_world.x())) + size_t(std::abs(100. * centroid_world.y())) +
size_t(std::abs(100. * centroid_world.z())); size_t(std::abs(100. * centroid_world.z()));
} }
// Now sort the islands so they are in defined order. This is a hack needed by cut gizmo, which sometimes // Now sort the islands so they are in defined order. This is a hack needed by cut gizmo, which sometimes
// flips the normal of the cut, in which case the contours stay the same but their order may change. // flips the normal of the cut, in which case the contours stay the same but their order may change.
std::sort(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](const CutIsland &a, const CutIsland &b) { return a.hash < b.hash; }); std::sort(m_result->cut_islands.begin(), m_result->cut_islands.end(), [](CutIsland *a, CutIsland *b) { return a && b && a->hash < b->hash; });
} }
void MeshClipper::reset()
{
if (m_result) {
for (auto it = m_result->cut_islands.begin(); it != m_result->cut_islands.end(); ++it) {
delete *it;
}
std::vector<CutIsland *>().swap(m_result->cut_islands);
}
m_result.reset();
}
Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
{ {

View File

@ -77,6 +77,7 @@ public:
// MeshClipper class cuts a mesh and is able to return a triangulated cut. // MeshClipper class cuts a mesh and is able to return a triangulated cut.
class MeshClipper { class MeshClipper {
public: public:
~MeshClipper();
// Set whether the cut should be triangulated and whether a cut // Set whether the cut should be triangulated and whether a cut
// contour should be calculated and shown. // contour should be calculated and shown.
void set_behaviour(bool fill_cut, double contour_width); void set_behaviour(bool fill_cut, double contour_width);
@ -111,7 +112,7 @@ public:
private: private:
void recalculate_triangles(); void recalculate_triangles();
void reset();
Geometry::Transformation m_trafo; Geometry::Transformation m_trafo;
const TriangleMesh * m_mesh = nullptr; const TriangleMesh * m_mesh = nullptr;
const TriangleMesh * m_negative_mesh = nullptr; const TriangleMesh * m_negative_mesh = nullptr;
@ -133,7 +134,7 @@ private:
}; };
struct ClipResult struct ClipResult
{ {
std::vector<CutIsland> cut_islands; std::vector<CutIsland*> cut_islands;
Transform3d trafo; // this rotates the cut into world coords Transform3d trafo; // this rotates the cut into world coords
}; };
std::optional<ClipResult> m_result; // the cut plane std::optional<ClipResult> m_result; // the cut plane