Merge remote-tracking branch 'origin/et_sinking_contours'
This commit is contained in:
commit
226353452e
29 changed files with 549 additions and 103 deletions
|
@ -47,6 +47,8 @@
|
||||||
#define ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_2_4_0_ALPHA0)
|
#define ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_2_4_0_ALPHA0)
|
||||||
// Enable the fix of importing color print view from gcode files into GCodeViewer
|
// Enable the fix of importing color print view from gcode files into GCodeViewer
|
||||||
#define ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER (1 && ENABLE_2_4_0_ALPHA0)
|
#define ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER (1 && ENABLE_2_4_0_ALPHA0)
|
||||||
|
// Enable drawing contours, at cut level, for sinking volumes
|
||||||
|
#define ENABLE_SINKING_CONTOURS (1 && ENABLE_2_4_0_ALPHA0)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
|
|
@ -698,27 +698,29 @@ struct EdgeToFace {
|
||||||
bool operator<(const EdgeToFace &other) const { return vertex_low < other.vertex_low || (vertex_low == other.vertex_low && vertex_high < other.vertex_high); }
|
bool operator<(const EdgeToFace &other) const { return vertex_low < other.vertex_low || (vertex_low == other.vertex_low && vertex_high < other.vertex_high); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ThrowOnCancelCallback>
|
template<typename FaceFilter, typename ThrowOnCancelCallback>
|
||||||
static std::vector<EdgeToFace> create_edge_map(
|
static std::vector<EdgeToFace> create_edge_map(
|
||||||
const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel)
|
const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel)
|
||||||
{
|
{
|
||||||
std::vector<EdgeToFace> edges_map;
|
std::vector<EdgeToFace> edges_map;
|
||||||
edges_map.assign(its.indices.size() * 3, EdgeToFace());
|
edges_map.reserve(its.indices.size() * 3);
|
||||||
for (uint32_t facet_idx = 0; facet_idx < its.indices.size(); ++ facet_idx)
|
for (uint32_t facet_idx = 0; facet_idx < its.indices.size(); ++ facet_idx)
|
||||||
for (int i = 0; i < 3; ++ i) {
|
if (face_filter(facet_idx))
|
||||||
EdgeToFace &e2f = edges_map[facet_idx * 3 + i];
|
for (int i = 0; i < 3; ++ i) {
|
||||||
e2f.vertex_low = its.indices[facet_idx][i];
|
edges_map.push_back({});
|
||||||
e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3];
|
EdgeToFace &e2f = edges_map.back();
|
||||||
e2f.face = facet_idx;
|
e2f.vertex_low = its.indices[facet_idx][i];
|
||||||
// 1 based indexing, to be always strictly positive.
|
e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3];
|
||||||
e2f.face_edge = i + 1;
|
e2f.face = facet_idx;
|
||||||
if (e2f.vertex_low > e2f.vertex_high) {
|
// 1 based indexing, to be always strictly positive.
|
||||||
// Sort the vertices
|
e2f.face_edge = i + 1;
|
||||||
std::swap(e2f.vertex_low, e2f.vertex_high);
|
if (e2f.vertex_low > e2f.vertex_high) {
|
||||||
// and make the face_edge negative to indicate a flipped edge.
|
// Sort the vertices
|
||||||
e2f.face_edge = - e2f.face_edge;
|
std::swap(e2f.vertex_low, e2f.vertex_high);
|
||||||
|
// and make the face_edge negative to indicate a flipped edge.
|
||||||
|
e2f.face_edge = - e2f.face_edge;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
throw_on_cancel();
|
throw_on_cancel();
|
||||||
std::sort(edges_map.begin(), edges_map.end());
|
std::sort(edges_map.begin(), edges_map.end());
|
||||||
|
|
||||||
|
@ -727,12 +729,12 @@ static std::vector<EdgeToFace> create_edge_map(
|
||||||
|
|
||||||
// Map from a face edge to a unique edge identifier or -1 if no neighbor exists.
|
// Map from a face edge to a unique edge identifier or -1 if no neighbor exists.
|
||||||
// Two neighbor faces share a unique edge identifier even if they are flipped.
|
// Two neighbor faces share a unique edge identifier even if they are flipped.
|
||||||
template<typename ThrowOnCancelCallback>
|
template<typename FaceFilter, typename ThrowOnCancelCallback>
|
||||||
static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel)
|
static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel)
|
||||||
{
|
{
|
||||||
std::vector<Vec3i> out(its.indices.size(), Vec3i(-1, -1, -1));
|
std::vector<Vec3i> out(its.indices.size(), Vec3i(-1, -1, -1));
|
||||||
|
|
||||||
std::vector<EdgeToFace> edges_map = create_edge_map(its, throw_on_cancel);
|
std::vector<EdgeToFace> edges_map = create_edge_map(its, face_filter, throw_on_cancel);
|
||||||
|
|
||||||
// Assign a unique common edge id to touching triangle edges.
|
// Assign a unique common edge id to touching triangle edges.
|
||||||
int num_edges = 0;
|
int num_edges = 0;
|
||||||
|
@ -780,12 +782,17 @@ static inline std::vector<Vec3i> its_face_edge_ids_impl(const indexed_triangle_s
|
||||||
|
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its)
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its)
|
||||||
{
|
{
|
||||||
return its_face_edge_ids_impl(its, [](){});
|
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, [](){});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback)
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback)
|
||||||
{
|
{
|
||||||
return its_face_edge_ids_impl(its, throw_on_cancel_callback);
|
return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask)
|
||||||
|
{
|
||||||
|
return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
||||||
|
|
|
@ -118,6 +118,7 @@ private:
|
||||||
// Used for chaining slice lines into polygons.
|
// Used for chaining slice lines into polygons.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its);
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::function<void()> throw_on_cancel_callback);
|
||||||
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, const std::vector<bool> &face_mask);
|
||||||
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
// Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices.
|
||||||
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
std::vector<Vec3i> its_face_edge_ids(const indexed_triangle_set &its, std::vector<Vec3i> &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr);
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,35 @@ static inline std::vector<IntersectionLines> slice_make_lines(
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TransformVertex, typename FaceFilter>
|
||||||
|
static inline IntersectionLines slice_make_lines(
|
||||||
|
const std::vector<stl_vertex> &mesh_vertices,
|
||||||
|
const TransformVertex &transform_vertex_fn,
|
||||||
|
const std::vector<stl_triangle_vertex_indices> &mesh_faces,
|
||||||
|
const std::vector<Vec3i> &face_edge_ids,
|
||||||
|
const float plane_z,
|
||||||
|
FaceFilter face_filter)
|
||||||
|
{
|
||||||
|
IntersectionLines lines;
|
||||||
|
for (int face_idx = 0; face_idx < mesh_faces.size(); ++ face_idx)
|
||||||
|
if (face_filter(face_idx)) {
|
||||||
|
const Vec3i &indices = mesh_faces[face_idx];
|
||||||
|
stl_vertex vertices[3] { transform_vertex_fn(mesh_vertices[indices(0)]), transform_vertex_fn(mesh_vertices[indices(1)]), transform_vertex_fn(mesh_vertices[indices(2)]) };
|
||||||
|
// find facet extents
|
||||||
|
const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z()));
|
||||||
|
const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z()));
|
||||||
|
assert(min_z <= plane_z && max_z >= plane_z);
|
||||||
|
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||||
|
IntersectionLine il;
|
||||||
|
// Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume.
|
||||||
|
if (min_z != max_z && slice_facet(plane_z, vertices, indices, face_edge_ids[face_idx], idx_vertex_lowest, false, il) == FacetSliceType::Slicing) {
|
||||||
|
assert(il.edge_type != IntersectionLine::FacetEdgeType::Horizontal);
|
||||||
|
lines.emplace_back(il);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
// For projecting triangle sets onto slice slabs.
|
// For projecting triangle sets onto slice slabs.
|
||||||
struct SlabLines {
|
struct SlabLines {
|
||||||
// Intersection lines of a slice with a triangle set, CCW oriented.
|
// Intersection lines of a slice with a triangle set, CCW oriented.
|
||||||
|
@ -1720,6 +1749,69 @@ std::vector<Polygons> slice_mesh(
|
||||||
return layers;
|
return layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialized version for a single slicing plane only, running on a single thread.
|
||||||
|
Polygons slice_mesh(
|
||||||
|
const indexed_triangle_set &mesh,
|
||||||
|
// Unscaled Zs
|
||||||
|
const float plane_z,
|
||||||
|
const MeshSlicingParams ¶ms)
|
||||||
|
{
|
||||||
|
std::vector<IntersectionLines> lines;
|
||||||
|
|
||||||
|
{
|
||||||
|
bool trafo_identity = is_identity(params.trafo);
|
||||||
|
Transform3f tf;
|
||||||
|
std::vector<bool> face_mask(mesh.indices.size(), false);
|
||||||
|
|
||||||
|
{
|
||||||
|
// 1) Mark vertices as below or above the slicing plane.
|
||||||
|
std::vector<char> vertex_side(mesh.vertices.size(), 0);
|
||||||
|
if (trafo_identity) {
|
||||||
|
for (size_t i = 0; i < mesh.vertices.size(); ++ i) {
|
||||||
|
float z = mesh.vertices[i].z();
|
||||||
|
char s = z < plane_z ? -1 : z == plane_z ? 0 : 1;
|
||||||
|
vertex_side[i] = s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tf = make_trafo_for_slicing(params.trafo);
|
||||||
|
for (size_t i = 0; i < mesh.vertices.size(); ++ i) {
|
||||||
|
//FIXME don't need to transform x & y, just Z.
|
||||||
|
float z = (tf * mesh.vertices[i]).z();
|
||||||
|
char s = z < plane_z ? -1 : z == plane_z ? 0 : 1;
|
||||||
|
vertex_side[i] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Mark faces crossing the plane.
|
||||||
|
for (size_t i = 0; i < mesh.indices.size(); ++ i) {
|
||||||
|
const Vec3i &face = mesh.indices[i];
|
||||||
|
int sides[3] = { vertex_side[face(0)], vertex_side[face(1)], vertex_side[face(2)] };
|
||||||
|
face_mask[i] = sides[0] * sides[1] <= 0 || sides[1] * sides[2] <= 0 || sides[0] * sides[2] <= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Calculate face neighbors for just the faces in face_mask.
|
||||||
|
std::vector<Vec3i> face_edge_ids = its_face_edge_ids(mesh, face_mask);
|
||||||
|
|
||||||
|
// 4) Slice "face_mask" triangles, collect line segments.
|
||||||
|
// It likely is not worthwile to copy the vertices. Apply the transformation in place.
|
||||||
|
if (trafo_identity) {
|
||||||
|
lines.emplace_back(slice_make_lines(
|
||||||
|
mesh.vertices, [](const Vec3f &p) { return Vec3f(scaled<float>(p.x()), scaled<float>(p.y()), p.z()); },
|
||||||
|
mesh.indices, face_edge_ids, plane_z, [&face_mask](int face_idx) { return face_mask[face_idx]; }));
|
||||||
|
} else {
|
||||||
|
// Transform the vertices, scale up in XY, not in Z.
|
||||||
|
lines.emplace_back(slice_make_lines(mesh.vertices, [tf](const Vec3f& p) { return tf * p; }, mesh.indices, face_edge_ids, plane_z,
|
||||||
|
[&face_mask](int face_idx) { return face_mask[face_idx]; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) Chain the line segments.
|
||||||
|
std::vector<Polygons> layers = make_loops(lines, params, [](){});
|
||||||
|
assert(layers.size() == 1);
|
||||||
|
return layers.front();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ExPolygons> slice_mesh_ex(
|
std::vector<ExPolygons> slice_mesh_ex(
|
||||||
const indexed_triangle_set &mesh,
|
const indexed_triangle_set &mesh,
|
||||||
const std::vector<float> &zs,
|
const std::vector<float> &zs,
|
||||||
|
|
|
@ -52,6 +52,12 @@ std::vector<Polygons> slice_mesh(
|
||||||
const MeshSlicingParams ¶ms,
|
const MeshSlicingParams ¶ms,
|
||||||
std::function<void()> throw_on_cancel = []{});
|
std::function<void()> throw_on_cancel = []{});
|
||||||
|
|
||||||
|
// Specialized version for a single slicing plane only, running on a single thread.
|
||||||
|
Polygons slice_mesh(
|
||||||
|
const indexed_triangle_set &mesh,
|
||||||
|
const float plane_z,
|
||||||
|
const MeshSlicingParams ¶ms);
|
||||||
|
|
||||||
std::vector<ExPolygons> slice_mesh_ex(
|
std::vector<ExPolygons> slice_mesh_ex(
|
||||||
const indexed_triangle_set &mesh,
|
const indexed_triangle_set &mesh,
|
||||||
const std::vector<float> &zs,
|
const std::vector<float> &zs,
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
#include "GLShader.hpp"
|
#include "GLShader.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#if ENABLE_ENVIRONMENT_MAP
|
#if ENABLE_ENVIRONMENT_MAP || ENABLE_SINKING_CONTOURS
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
#endif // ENABLE_ENVIRONMENT_MAP
|
#endif // ENABLE_ENVIRONMENT_MAP || ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||||
|
@ -24,6 +24,9 @@
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/AppConfig.hpp"
|
#include "libslic3r/AppConfig.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
#include "libslic3r/Tesselate.hpp"
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -284,6 +287,74 @@ void GLIndexedVertexArray::render(
|
||||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
const float GLVolume::SinkingContours::HalfWidth = 0.25f;
|
||||||
|
|
||||||
|
void GLVolume::SinkingContours::render()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
|
||||||
|
glsafe(::glPushMatrix());
|
||||||
|
glsafe(::glTranslated(m_shift.x(), m_shift.y(), m_shift.z()));
|
||||||
|
m_model.render();
|
||||||
|
glsafe(::glPopMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLVolume::SinkingContours::update()
|
||||||
|
{
|
||||||
|
if (m_parent.is_sinking() && !m_parent.is_below_printbed()) {
|
||||||
|
const BoundingBoxf3& box = m_parent.transformed_convex_hull_bounding_box();
|
||||||
|
if (!m_old_box.size().isApprox(box.size()) || m_old_box.min.z() != box.min.z()) {
|
||||||
|
m_old_box = box;
|
||||||
|
m_shift = Vec3d::Zero();
|
||||||
|
|
||||||
|
const TriangleMesh& mesh = GUI::wxGetApp().plater()->model().objects[m_parent.object_idx()]->volumes[m_parent.volume_idx()]->mesh();
|
||||||
|
assert(mesh.has_shared_vertices());
|
||||||
|
|
||||||
|
m_model.reset();
|
||||||
|
GUI::GLModel::InitializationData init_data;
|
||||||
|
MeshSlicingParams slicing_params;
|
||||||
|
slicing_params.trafo = m_parent.world_matrix();
|
||||||
|
Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params));
|
||||||
|
for (Polygon& polygon : polygons) {
|
||||||
|
if (polygon.is_clockwise())
|
||||||
|
polygon.reverse();
|
||||||
|
Polygons outer_polys = offset(polygon, float(scale_(HalfWidth)));
|
||||||
|
assert(outer_polys.size() == 1);
|
||||||
|
if (outer_polys.empty())
|
||||||
|
// no outer contour, skip
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ExPolygon expoly(std::move(outer_polys.front()));
|
||||||
|
expoly.holes = offset(polygon, -float(scale_(HalfWidth)));
|
||||||
|
polygons_reverse(expoly.holes);
|
||||||
|
|
||||||
|
GUI::GLModel::InitializationData::Entity entity;
|
||||||
|
entity.type = GUI::GLModel::PrimitiveType::Triangles;
|
||||||
|
const std::vector<Vec3d> triangulation = triangulate_expolygon_3d(expoly);
|
||||||
|
for (const Vec3d& v : triangulation) {
|
||||||
|
entity.positions.emplace_back(v.cast<float>() + Vec3f(0.0f, 0.0f, 0.015f)); // add a small positive z to avoid z-fighting
|
||||||
|
entity.normals.emplace_back(Vec3f::UnitZ());
|
||||||
|
const size_t positions_count = entity.positions.size();
|
||||||
|
if (positions_count % 3 == 0) {
|
||||||
|
entity.indices.emplace_back(positions_count - 3);
|
||||||
|
entity.indices.emplace_back(positions_count - 2);
|
||||||
|
entity.indices.emplace_back(positions_count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init_data.entities.emplace_back(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_model.init_from(init_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_shift = box.center() - m_old_box.center();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_model.reset();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
const std::array<float, 4> GLVolume::SELECTED_COLOR = { 0.0f, 1.0f, 0.0f, 1.0f };
|
const std::array<float, 4> GLVolume::SELECTED_COLOR = { 0.0f, 1.0f, 0.0f, 1.0f };
|
||||||
const std::array<float, 4> GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
|
const std::array<float, 4> GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||||
const std::array<float, 4> GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
|
const std::array<float, 4> GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
|
||||||
|
@ -304,6 +375,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
||||||
: m_transformed_bounding_box_dirty(true)
|
: m_transformed_bounding_box_dirty(true)
|
||||||
, m_sla_shift_z(0.0)
|
, m_sla_shift_z(0.0)
|
||||||
, m_transformed_convex_hull_bounding_box_dirty(true)
|
, m_transformed_convex_hull_bounding_box_dirty(true)
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
, m_sinking_contours(*this)
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
// geometry_id == 0 -> invalid
|
// geometry_id == 0 -> invalid
|
||||||
, geometry_id(std::pair<size_t, size_t>(0, 0))
|
, geometry_id(std::pair<size_t, size_t>(0, 0))
|
||||||
, extruder_id(0)
|
, extruder_id(0)
|
||||||
|
@ -321,6 +395,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
||||||
, force_transparent(false)
|
, force_transparent(false)
|
||||||
, force_native_color(false)
|
, force_native_color(false)
|
||||||
, force_neutral_color(false)
|
, force_neutral_color(false)
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
, force_sinking_contours(false)
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
, tverts_range(0, size_t(-1))
|
, tverts_range(0, size_t(-1))
|
||||||
, qverts_range(0, size_t(-1))
|
, qverts_range(0, size_t(-1))
|
||||||
{
|
{
|
||||||
|
@ -517,6 +594,13 @@ bool GLVolume::is_below_printbed() const
|
||||||
return transformed_convex_hull_bounding_box().max(2) < 0.0;
|
return transformed_convex_hull_bounding_box().max(2) < 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void GLVolume::render_sinking_contours()
|
||||||
|
{
|
||||||
|
m_sinking_contours.render();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
std::vector<int> GLVolumeCollection::load_object(
|
std::vector<int> GLVolumeCollection::load_object(
|
||||||
const ModelObject *model_object,
|
const ModelObject *model_object,
|
||||||
int obj_idx,
|
int obj_idx,
|
||||||
|
@ -752,6 +836,68 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
||||||
if (disable_cullface)
|
if (disable_cullface)
|
||||||
glsafe(::glDisable(GL_CULL_FACE));
|
glsafe(::glDisable(GL_CULL_FACE));
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func);
|
||||||
|
for (GLVolumeWithIdAndZ& volume : to_render) {
|
||||||
|
volume.first->set_render_color();
|
||||||
|
|
||||||
|
// render sinking contours of non-hovered volumes
|
||||||
|
if (volume.first->is_sinking() && !volume.first->is_below_printbed() &&
|
||||||
|
volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) {
|
||||||
|
shader->stop_using();
|
||||||
|
volume.first->render_sinking_contours();
|
||||||
|
shader->start_using();
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
|
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||||
|
|
||||||
|
shader->set_uniform("uniform_color", volume.first->render_color);
|
||||||
|
shader->set_uniform("z_range", m_z_range, 2);
|
||||||
|
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
||||||
|
shader->set_uniform("print_box.min", m_print_box_min, 3);
|
||||||
|
shader->set_uniform("print_box.max", m_print_box_max, 3);
|
||||||
|
shader->set_uniform("print_box.actived", volume.first->shader_outside_printer_detection_enabled);
|
||||||
|
shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix());
|
||||||
|
shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
||||||
|
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
||||||
|
shader->set_uniform("slope.normal_z", m_slope.normal_z);
|
||||||
|
|
||||||
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
|
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
|
||||||
|
bool use_environment_texture = environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1";
|
||||||
|
shader->set_uniform("use_environment_tex", use_environment_texture);
|
||||||
|
if (use_environment_texture)
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id));
|
||||||
|
#endif // ENABLE_ENVIRONMENT_MAP
|
||||||
|
glcheck();
|
||||||
|
|
||||||
|
volume.first->render();
|
||||||
|
|
||||||
|
#if ENABLE_ENVIRONMENT_MAP
|
||||||
|
if (use_environment_texture)
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
#endif // ENABLE_ENVIRONMENT_MAP
|
||||||
|
|
||||||
|
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||||
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||||
|
|
||||||
|
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||||
|
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (GLVolumeWithIdAndZ& volume : to_render) {
|
||||||
|
// render sinking contours of hovered/displaced volumes
|
||||||
|
if (volume.first->is_sinking() && !volume.first->is_below_printbed() &&
|
||||||
|
(volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) {
|
||||||
|
shader->stop_using();
|
||||||
|
glsafe(::glDepthFunc(GL_ALWAYS));
|
||||||
|
volume.first->render_sinking_contours();
|
||||||
|
glsafe(::glDepthFunc(GL_LESS));
|
||||||
|
shader->start_using();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||||
|
|
||||||
|
@ -791,6 +937,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
||||||
|
|
||||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
if (disable_cullface)
|
if (disable_cullface)
|
||||||
glsafe(::glEnable(GL_CULL_FACE));
|
glsafe(::glEnable(GL_CULL_FACE));
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
#include "GLModel.hpp"
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#define HAS_GLSAFE
|
#define HAS_GLSAFE
|
||||||
|
@ -250,6 +254,9 @@ public:
|
||||||
enum EHoverState : unsigned char
|
enum EHoverState : unsigned char
|
||||||
{
|
{
|
||||||
HS_None,
|
HS_None,
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
HS_Hover,
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
HS_Select,
|
HS_Select,
|
||||||
HS_Deselect
|
HS_Deselect
|
||||||
};
|
};
|
||||||
|
@ -262,7 +269,7 @@ private:
|
||||||
Geometry::Transformation m_volume_transformation;
|
Geometry::Transformation m_volume_transformation;
|
||||||
|
|
||||||
// Shift in z required by sla supports+pad
|
// Shift in z required by sla supports+pad
|
||||||
double m_sla_shift_z;
|
double m_sla_shift_z;
|
||||||
// Bounding box of this volume, in unscaled coordinates.
|
// Bounding box of this volume, in unscaled coordinates.
|
||||||
BoundingBoxf3 m_transformed_bounding_box;
|
BoundingBoxf3 m_transformed_bounding_box;
|
||||||
// Whether or not is needed to recalculate the transformed bounding box.
|
// Whether or not is needed to recalculate the transformed bounding box.
|
||||||
|
@ -274,6 +281,26 @@ private:
|
||||||
// Whether or not is needed to recalculate the transformed convex hull bounding box.
|
// Whether or not is needed to recalculate the transformed convex hull bounding box.
|
||||||
bool m_transformed_convex_hull_bounding_box_dirty;
|
bool m_transformed_convex_hull_bounding_box_dirty;
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
class SinkingContours
|
||||||
|
{
|
||||||
|
static const float HalfWidth;
|
||||||
|
GLVolume& m_parent;
|
||||||
|
GUI::GLModel m_model;
|
||||||
|
BoundingBoxf3 m_old_box;
|
||||||
|
Vec3d m_shift{ Vec3d::Zero() };
|
||||||
|
|
||||||
|
public:
|
||||||
|
SinkingContours(GLVolume& volume) : m_parent(volume) {}
|
||||||
|
void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
SinkingContours m_sinking_contours;
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Color of the triangles / quads held by this volume.
|
// Color of the triangles / quads held by this volume.
|
||||||
std::array<float, 4> color;
|
std::array<float, 4> color;
|
||||||
|
@ -334,7 +361,11 @@ public:
|
||||||
bool force_native_color : 1;
|
bool force_native_color : 1;
|
||||||
// Whether or not render this volume in neutral
|
// Whether or not render this volume in neutral
|
||||||
bool force_neutral_color : 1;
|
bool force_neutral_color : 1;
|
||||||
};
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
// Whether or not to force rendering of sinking contours
|
||||||
|
bool force_sinking_contours : 1;
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
};
|
||||||
|
|
||||||
// Is mouse or rectangle selection over this object to select/deselect it ?
|
// Is mouse or rectangle selection over this object to select/deselect it ?
|
||||||
EHoverState hover;
|
EHoverState hover;
|
||||||
|
@ -461,6 +492,9 @@ public:
|
||||||
|
|
||||||
bool is_sinking() const;
|
bool is_sinking() const;
|
||||||
bool is_below_printbed() const;
|
bool is_below_printbed() const;
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void render_sinking_contours();
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
// Return an estimate of the memory consumed by this class.
|
// Return an estimate of the memory consumed by this class.
|
||||||
size_t cpu_memory_used() const {
|
size_t cpu_memory_used() const {
|
||||||
|
|
|
@ -792,7 +792,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons
|
||||||
for (const Polygon& poly : polygons) {
|
for (const Polygon& poly : polygons) {
|
||||||
triangles_count += poly.points.size() - 2;
|
triangles_count += poly.points.size() - 2;
|
||||||
}
|
}
|
||||||
size_t vertices_count = 3 * triangles_count;
|
const size_t vertices_count = 3 * triangles_count;
|
||||||
|
|
||||||
if (m_render_fill) {
|
if (m_render_fill) {
|
||||||
GLModel::InitializationData fill_data;
|
GLModel::InitializationData fill_data;
|
||||||
|
@ -803,13 +803,13 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons
|
||||||
entity.normals.reserve(vertices_count);
|
entity.normals.reserve(vertices_count);
|
||||||
entity.indices.reserve(vertices_count);
|
entity.indices.reserve(vertices_count);
|
||||||
|
|
||||||
ExPolygons polygons_union = union_ex(polygons);
|
const ExPolygons polygons_union = union_ex(polygons);
|
||||||
for (const ExPolygon& poly : polygons_union) {
|
for (const ExPolygon& poly : polygons_union) {
|
||||||
std::vector<Vec3d> triangulation = triangulate_expolygon_3d(poly, false);
|
const std::vector<Vec3d> triangulation = triangulate_expolygon_3d(poly);
|
||||||
for (const Vec3d& v : triangulation) {
|
for (const Vec3d& v : triangulation) {
|
||||||
entity.positions.emplace_back(v.cast<float>() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting
|
entity.positions.emplace_back(v.cast<float>() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting
|
||||||
entity.normals.emplace_back(Vec3f::UnitZ());
|
entity.normals.emplace_back(Vec3f::UnitZ());
|
||||||
size_t positions_count = entity.positions.size();
|
const size_t positions_count = entity.positions.size();
|
||||||
if (positions_count % 3 == 0) {
|
if (positions_count % 3 == 0) {
|
||||||
entity.indices.emplace_back(positions_count - 3);
|
entity.indices.emplace_back(positions_count - 3);
|
||||||
entity.indices.emplace_back(positions_count - 2);
|
entity.indices.emplace_back(positions_count - 2);
|
||||||
|
@ -2938,6 +2938,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
for (GLVolume* volume : m_volumes.volumes) {
|
||||||
|
volume->force_sinking_contours = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto show_sinking_contours = [this]() {
|
||||||
|
const Selection::IndicesList& idxs = m_selection.get_volume_idxs();
|
||||||
|
for (unsigned int idx : idxs) {
|
||||||
|
m_volumes.volumes[idx]->force_sinking_contours = true;
|
||||||
|
}
|
||||||
|
m_dirty = true;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
if (m_gizmos.on_mouse(evt)) {
|
if (m_gizmos.on_mouse(evt)) {
|
||||||
if (wxWindow::FindFocus() != m_canvas)
|
if (wxWindow::FindFocus() != m_canvas)
|
||||||
// Grab keyboard focus for input in gizmo dialogs.
|
// Grab keyboard focus for input in gizmo dialogs.
|
||||||
|
@ -2962,6 +2976,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
default: { break; }
|
default: { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
else if (evt.Dragging()) {
|
||||||
|
switch (m_gizmos.get_current_type())
|
||||||
|
{
|
||||||
|
case GLGizmosManager::EType::Move:
|
||||||
|
case GLGizmosManager::EType::Scale:
|
||||||
|
case GLGizmosManager::EType::Rotate:
|
||||||
|
{
|
||||||
|
show_sinking_contours();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3271,6 +3300,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
else
|
else
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
if (m_moving)
|
||||||
|
show_sinking_contours();
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
if (on_enter_workaround)
|
if (on_enter_workaround)
|
||||||
m_mouse.position = Vec2d(-1., -1.);
|
m_mouse.position = Vec2d(-1., -1.);
|
||||||
|
@ -5579,6 +5613,11 @@ void GLCanvas3D::_update_volumes_hover_state()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
else if (volume.selected)
|
||||||
|
volume.hover = GLVolume::HS_Hover;
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
|
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
#include "libslic3r/Polygon.hpp"
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
@ -87,6 +90,35 @@ void GLModel::init_from(const TriangleMesh& mesh)
|
||||||
m_render_data.emplace_back(data);
|
m_render_data.emplace_back(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void GLModel::init_from(const Polygons& polygons, float z)
|
||||||
|
{
|
||||||
|
auto append_polygon = [](const Polygon& polygon, float z, GUI::GLModel::InitializationData& data) {
|
||||||
|
if (!polygon.empty()) {
|
||||||
|
GUI::GLModel::InitializationData::Entity entity;
|
||||||
|
entity.type = GUI::GLModel::PrimitiveType::LineLoop;
|
||||||
|
// contour
|
||||||
|
entity.positions.reserve(polygon.size() + 1);
|
||||||
|
entity.indices.reserve(polygon.size() + 1);
|
||||||
|
unsigned int id = 0;
|
||||||
|
for (const Point& p : polygon) {
|
||||||
|
Vec3f position = unscale(p.x(), p.y(), 0.0).cast<float>();
|
||||||
|
position.z() = z;
|
||||||
|
entity.positions.emplace_back(position);
|
||||||
|
entity.indices.emplace_back(id++);
|
||||||
|
}
|
||||||
|
data.entities.emplace_back(entity);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializationData init_data;
|
||||||
|
for (const Polygon& polygon : polygons) {
|
||||||
|
append_polygon(polygon, z, init_data);
|
||||||
|
}
|
||||||
|
init_from(init_data);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
bool GLModel::init_from_file(const std::string& filename)
|
bool GLModel::init_from_file(const std::string& filename)
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::exists(filename))
|
if (!boost::filesystem::exists(filename))
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class TriangleMesh;
|
class TriangleMesh;
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
class Polygon;
|
||||||
|
using Polygons = std::vector<Polygon>;
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
@ -58,6 +62,9 @@ namespace GUI {
|
||||||
|
|
||||||
void init_from(const InitializationData& data);
|
void init_from(const InitializationData& data);
|
||||||
void init_from(const TriangleMesh& mesh);
|
void init_from(const TriangleMesh& mesh);
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void init_from(const Polygons& polygons, float z);
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
bool init_from_file(const std::string& filename);
|
bool init_from_file(const std::string& filename);
|
||||||
|
|
||||||
// if entity_id == -1 set the color of all entities
|
// if entity_id == -1 set the color of all entities
|
||||||
|
|
|
@ -154,8 +154,8 @@ public:
|
||||||
|
|
||||||
void update(const UpdateData& data);
|
void update(const UpdateData& data);
|
||||||
|
|
||||||
void render() const { m_tooltip.clear(); on_render(); }
|
void render() { m_tooltip.clear(); on_render(); }
|
||||||
void render_for_picking() const { on_render_for_picking(); }
|
void render_for_picking() { on_render_for_picking(); }
|
||||||
void render_input_window(float x, float y, float bottom_limit);
|
void render_input_window(float x, float y, float bottom_limit);
|
||||||
|
|
||||||
virtual std::string get_tooltip() const { return ""; }
|
virtual std::string get_tooltip() const { return ""; }
|
||||||
|
@ -175,8 +175,8 @@ protected:
|
||||||
virtual void on_start_dragging() {}
|
virtual void on_start_dragging() {}
|
||||||
virtual void on_stop_dragging() {}
|
virtual void on_stop_dragging() {}
|
||||||
virtual void on_update(const UpdateData& data) {}
|
virtual void on_update(const UpdateData& data) {}
|
||||||
virtual void on_render() const = 0;
|
virtual void on_render() = 0;
|
||||||
virtual void on_render_for_picking() const = 0;
|
virtual void on_render_for_picking() = 0;
|
||||||
virtual void on_render_input_window(float x, float y, float bottom_limit) {}
|
virtual void on_render_input_window(float x, float y, float bottom_limit) {}
|
||||||
|
|
||||||
// Returns the picking color for the given id, based on the BASE_ID constant
|
// Returns the picking color for the given id, based on the BASE_ID constant
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||||
#include "libslic3r/AppConfig.hpp"
|
#include "libslic3r/AppConfig.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
@ -82,14 +84,18 @@ void GLGizmoCut::on_update(const UpdateData& data)
|
||||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut::on_render() const
|
void GLGizmoCut::on_render()
|
||||||
{
|
{
|
||||||
BoundingBoxf3 box = bounding_box();
|
const BoundingBoxf3 box = bounding_box();
|
||||||
Vec3d plane_center = box.center();
|
Vec3d plane_center = box.center();
|
||||||
plane_center.z() = m_cut_z;
|
plane_center.z() = m_cut_z;
|
||||||
m_max_z = box.max.z();
|
m_max_z = box.max.z();
|
||||||
set_cut_z(m_cut_z);
|
set_cut_z(m_cut_z);
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
update_contours();
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
const float min_x = box.min.x() - Margin;
|
const float min_x = box.min.x() - Margin;
|
||||||
const float max_x = box.max.x() + Margin;
|
const float max_x = box.max.x() + Margin;
|
||||||
const float min_y = box.min.y() - Margin;
|
const float min_y = box.min.y() - Margin;
|
||||||
|
@ -136,9 +142,17 @@ void GLGizmoCut::on_render() const
|
||||||
m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0));
|
m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0));
|
||||||
|
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
glsafe(::glPushMatrix());
|
||||||
|
glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
|
||||||
|
glsafe(::glLineWidth(2.0f));
|
||||||
|
m_cut_contours.contours.render();
|
||||||
|
glsafe(::glPopMatrix());
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut::on_render_for_picking() const
|
void GLGizmoCut::on_render_for_picking()
|
||||||
{
|
{
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||||
|
@ -199,7 +213,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||||
perform_cut(m_parent.get_selection());
|
perform_cut(m_parent.get_selection());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoCut::set_cut_z(double cut_z) const
|
void GLGizmoCut::set_cut_z(double cut_z)
|
||||||
{
|
{
|
||||||
// Clamp the plane to the object's bounding box
|
// Clamp the plane to the object's bounding box
|
||||||
m_cut_z = std::clamp(cut_z, 0.0, m_max_z);
|
m_cut_z = std::clamp(cut_z, 0.0, m_max_z);
|
||||||
|
@ -261,5 +275,47 @@ BoundingBoxf3 GLGizmoCut::bounding_box() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void GLGizmoCut::update_contours()
|
||||||
|
{
|
||||||
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
|
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
|
||||||
|
|
||||||
|
const int object_idx = selection.get_object_idx();
|
||||||
|
const int instance_idx = selection.get_instance_idx();
|
||||||
|
|
||||||
|
if (0.0 < m_cut_z && m_cut_z < m_max_z) {
|
||||||
|
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_idx != object_idx || m_cut_contours.instance_idx != instance_idx) {
|
||||||
|
m_cut_contours.cut_z = m_cut_z;
|
||||||
|
|
||||||
|
if (m_cut_contours.object_idx != object_idx) {
|
||||||
|
m_cut_contours.mesh = wxGetApp().plater()->model().objects[object_idx]->raw_mesh();
|
||||||
|
m_cut_contours.mesh.repair();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cut_contours.position = box.center();
|
||||||
|
m_cut_contours.shift = Vec3d::Zero();
|
||||||
|
m_cut_contours.object_idx = object_idx;
|
||||||
|
m_cut_contours.instance_idx = instance_idx;
|
||||||
|
m_cut_contours.contours.reset();
|
||||||
|
|
||||||
|
MeshSlicingParams slicing_params;
|
||||||
|
slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
|
||||||
|
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params);
|
||||||
|
if (!polys.empty()) {
|
||||||
|
m_cut_contours.contours.init_from(polys, static_cast<float>(m_cut_z));
|
||||||
|
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (box.center() != m_cut_contours.position) {
|
||||||
|
m_cut_contours.shift = box.center() - m_cut_contours.position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_cut_contours.contours.reset();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
#define slic3r_GLGizmoCut_hpp_
|
#define slic3r_GLGizmoCut_hpp_
|
||||||
|
|
||||||
#include "GLGizmoBase.hpp"
|
#include "GLGizmoBase.hpp"
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
#include "slic3r/GUI/GLModel.hpp"
|
||||||
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
@ -13,8 +16,8 @@ class GLGizmoCut : public GLGizmoBase
|
||||||
static const double Margin;
|
static const double Margin;
|
||||||
static const std::array<float, 4> GrabberColor;
|
static const std::array<float, 4> GrabberColor;
|
||||||
|
|
||||||
mutable double m_cut_z{ 0.0 };
|
double m_cut_z{ 0.0 };
|
||||||
mutable double m_max_z{ 0.0 };
|
double m_max_z{ 0.0 };
|
||||||
double m_start_z{ 0.0 };
|
double m_start_z{ 0.0 };
|
||||||
Vec3d m_drag_pos;
|
Vec3d m_drag_pos;
|
||||||
Vec3d m_drag_center;
|
Vec3d m_drag_center;
|
||||||
|
@ -22,11 +25,26 @@ class GLGizmoCut : public GLGizmoBase
|
||||||
bool m_keep_lower{ true };
|
bool m_keep_lower{ true };
|
||||||
bool m_rotate_lower{ false };
|
bool m_rotate_lower{ false };
|
||||||
|
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
struct CutContours
|
||||||
|
{
|
||||||
|
TriangleMesh mesh;
|
||||||
|
GLModel contours;
|
||||||
|
double cut_z{ 0.0 };
|
||||||
|
Vec3d position{ Vec3d::Zero() };
|
||||||
|
Vec3d shift{ Vec3d::Zero() };
|
||||||
|
int object_idx{ -1 };
|
||||||
|
int instance_idx{ -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
CutContours m_cut_contours;
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||||
|
|
||||||
double get_cut_z() const { return m_cut_z; }
|
double get_cut_z() const { return m_cut_z; }
|
||||||
void set_cut_z(double cut_z) const;
|
void set_cut_z(double cut_z);
|
||||||
|
|
||||||
std::string get_tooltip() const override;
|
std::string get_tooltip() const override;
|
||||||
|
|
||||||
|
@ -39,14 +57,17 @@ protected:
|
||||||
virtual bool on_is_activable() const override;
|
virtual bool on_is_activable() const override;
|
||||||
virtual void on_start_dragging() override;
|
virtual void on_start_dragging() override;
|
||||||
virtual void on_update(const UpdateData& data) override;
|
virtual void on_update(const UpdateData& data) override;
|
||||||
virtual void on_render() const override;
|
virtual void on_render() override;
|
||||||
virtual void on_render_for_picking() const override;
|
virtual void on_render_for_picking() override;
|
||||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void perform_cut(const Selection& selection);
|
void perform_cut(const Selection& selection);
|
||||||
double calc_projection(const Linef3& mouse_ray) const;
|
double calc_projection(const Linef3& mouse_ray) const;
|
||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
|
#if ENABLE_SINKING_CONTOURS
|
||||||
|
void update_contours();
|
||||||
|
#endif // ENABLE_SINKING_CONTOURS
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
|
|
|
@ -54,7 +54,7 @@ void GLGizmoFlatten::on_start_dragging()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoFlatten::on_render() const
|
void GLGizmoFlatten::on_render()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ void GLGizmoFlatten::on_render() const
|
||||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||||
glsafe(::glMultMatrixd(m.data()));
|
glsafe(::glMultMatrixd(m.data()));
|
||||||
if (this->is_plane_update_necessary())
|
if (this->is_plane_update_necessary())
|
||||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
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)
|
||||||
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f));
|
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f));
|
||||||
|
@ -86,7 +86,7 @@ void GLGizmoFlatten::on_render() const
|
||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoFlatten::on_render_for_picking() const
|
void GLGizmoFlatten::on_render_for_picking()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ void GLGizmoFlatten::on_render_for_picking() const
|
||||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||||
glsafe(::glMultMatrixd(m.data()));
|
glsafe(::glMultMatrixd(m.data()));
|
||||||
if (this->is_plane_update_necessary())
|
if (this->is_plane_update_necessary())
|
||||||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
update_planes();
|
||||||
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
||||||
glsafe(::glColor4fv(picking_color_component(i).data()));
|
glsafe(::glColor4fv(picking_color_component(i).data()));
|
||||||
m_planes[i].vbo.render();
|
m_planes[i].vbo.render();
|
||||||
|
|
|
@ -53,8 +53,8 @@ protected:
|
||||||
virtual std::string on_get_name() const override;
|
virtual std::string on_get_name() const override;
|
||||||
virtual bool on_is_activable() const override;
|
virtual bool on_is_activable() const override;
|
||||||
virtual void on_start_dragging() override;
|
virtual void on_start_dragging() override;
|
||||||
virtual void on_render() const override;
|
virtual void on_render() override;
|
||||||
virtual void on_render_for_picking() const override;
|
virtual void on_render_for_picking() override;
|
||||||
virtual void on_set_state() override;
|
virtual void on_set_state() override;
|
||||||
virtual CommonGizmosDataID on_get_requirements() const override;
|
virtual CommonGizmosDataID on_get_requirements() const override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void GLGizmoHollow::on_render() const
|
void GLGizmoHollow::on_render()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info();
|
const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info();
|
||||||
|
@ -88,7 +88,7 @@ void GLGizmoHollow::on_render() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GLGizmoHollow::on_render_for_picking() const
|
void GLGizmoHollow::on_render_for_picking()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
//#if ENABLE_RENDER_PICKING_PASS
|
//#if ENABLE_RENDER_PICKING_PASS
|
||||||
|
|
|
@ -39,8 +39,8 @@ public:
|
||||||
private:
|
private:
|
||||||
bool on_init() override;
|
bool on_init() override;
|
||||||
void on_update(const UpdateData& data) override;
|
void on_update(const UpdateData& data) override;
|
||||||
void on_render() const override;
|
void on_render() override;
|
||||||
void on_render_for_picking() const override;
|
void on_render_for_picking() override;
|
||||||
|
|
||||||
void render_points(const Selection& selection, bool picking = false) const;
|
void render_points(const Selection& selection, bool picking = false) const;
|
||||||
void hollow_mesh(bool postpone_error_messages = false);
|
void hollow_mesh(bool postpone_error_messages = false);
|
||||||
|
|
|
@ -87,7 +87,7 @@ void GLGizmoMove3D::on_update(const UpdateData& data)
|
||||||
m_displacement.z() = calc_projection(data);
|
m_displacement.z() = calc_projection(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoMove3D::on_render() const
|
void GLGizmoMove3D::on_render()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ void GLGizmoMove3D::on_render() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoMove3D::on_render_for_picking() const
|
void GLGizmoMove3D::on_render_for_picking()
|
||||||
{
|
{
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ protected:
|
||||||
virtual void on_start_dragging() override;
|
virtual void on_start_dragging() override;
|
||||||
virtual void on_stop_dragging() override;
|
virtual void on_stop_dragging() override;
|
||||||
virtual void on_update(const UpdateData& data) override;
|
virtual void on_update(const UpdateData& data) override;
|
||||||
virtual void on_render() const override;
|
virtual void on_render() override;
|
||||||
virtual void on_render_for_picking() const override;
|
virtual void on_render_for_picking() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double calc_projection(const UpdateData& data) const;
|
double calc_projection(const UpdateData& data) const;
|
||||||
|
|
|
@ -66,8 +66,8 @@ class GLGizmoPainterBase : public GLGizmoBase
|
||||||
private:
|
private:
|
||||||
ObjectID m_old_mo_id;
|
ObjectID m_old_mo_id;
|
||||||
size_t m_old_volumes_size = 0;
|
size_t m_old_volumes_size = 0;
|
||||||
void on_render() const override {}
|
void on_render() override {}
|
||||||
void on_render_for_picking() const override {}
|
void on_render_for_picking() override {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||||
|
|
|
@ -125,7 +125,7 @@ void GLGizmoRotate::on_update(const UpdateData& data)
|
||||||
m_angle = theta;
|
m_angle = theta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoRotate::on_render() const
|
void GLGizmoRotate::on_render()
|
||||||
{
|
{
|
||||||
if (!m_grabbers[0].enabled)
|
if (!m_grabbers[0].enabled)
|
||||||
return;
|
return;
|
||||||
|
@ -169,7 +169,7 @@ void GLGizmoRotate::on_render() const
|
||||||
glsafe(::glPopMatrix());
|
glsafe(::glPopMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoRotate::on_render_for_picking() const
|
void GLGizmoRotate::on_render_for_picking()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
@ -483,17 +483,17 @@ void GLGizmoRotate3D::on_stop_dragging()
|
||||||
m_gizmos[m_hover_id].stop_dragging();
|
m_gizmos[m_hover_id].stop_dragging();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoRotate3D::on_render() const
|
void GLGizmoRotate3D::on_render()
|
||||||
{
|
{
|
||||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||||
|
|
||||||
if ((m_hover_id == -1) || (m_hover_id == 0))
|
if (m_hover_id == -1 || m_hover_id == 0)
|
||||||
m_gizmos[X].render();
|
m_gizmos[X].render();
|
||||||
|
|
||||||
if ((m_hover_id == -1) || (m_hover_id == 1))
|
if (m_hover_id == -1 || m_hover_id == 1)
|
||||||
m_gizmos[Y].render();
|
m_gizmos[Y].render();
|
||||||
|
|
||||||
if ((m_hover_id == -1) || (m_hover_id == 2))
|
if (m_hover_id == -1 || m_hover_id == 2)
|
||||||
m_gizmos[Z].render();
|
m_gizmos[Z].render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,8 @@ protected:
|
||||||
std::string on_get_name() const override { return ""; }
|
std::string on_get_name() const override { return ""; }
|
||||||
void on_start_dragging() override;
|
void on_start_dragging() override;
|
||||||
void on_update(const UpdateData& data) override;
|
void on_update(const UpdateData& data) override;
|
||||||
void on_render() const override;
|
void on_render() override;
|
||||||
void on_render_for_picking() const override;
|
void on_render_for_picking() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render_circle() const;
|
void render_circle() const;
|
||||||
|
@ -124,10 +124,10 @@ protected:
|
||||||
g.update(data);
|
g.update(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void on_render() const override;
|
void on_render() override;
|
||||||
void on_render_for_picking() const override
|
void on_render_for_picking() override
|
||||||
{
|
{
|
||||||
for (const GLGizmoRotate& g : m_gizmos) {
|
for (GLGizmoRotate& g : m_gizmos) {
|
||||||
g.render_for_picking();
|
g.render_for_picking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ void GLGizmoScale3D::on_update(const UpdateData& data)
|
||||||
do_scale_uniform(data);
|
do_scale_uniform(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::on_render() const
|
void GLGizmoScale3D::on_render()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ void GLGizmoScale3D::on_render() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoScale3D::on_render_for_picking() const
|
void GLGizmoScale3D::on_render_for_picking()
|
||||||
{
|
{
|
||||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||||
|
|
|
@ -52,8 +52,8 @@ protected:
|
||||||
virtual bool on_is_activable() const override;
|
virtual bool on_is_activable() const override;
|
||||||
virtual void on_start_dragging() override;
|
virtual void on_start_dragging() override;
|
||||||
virtual void on_update(const UpdateData& data) override;
|
virtual void on_update(const UpdateData& data) override;
|
||||||
virtual void on_render() const override;
|
virtual void on_render() override;
|
||||||
virtual void on_render_for_picking() const override;
|
virtual void on_render_for_picking() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
|
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
|
||||||
|
|
|
@ -74,7 +74,7 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void GLGizmoSlaSupports::on_render() const
|
void GLGizmoSlaSupports::on_render()
|
||||||
{
|
{
|
||||||
ModelObject* mo = m_c->selection_info()->model_object();
|
ModelObject* mo = m_c->selection_info()->model_object();
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
|
@ -101,7 +101,7 @@ void GLGizmoSlaSupports::on_render() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GLGizmoSlaSupports::on_render_for_picking() const
|
void GLGizmoSlaSupports::on_render_for_picking()
|
||||||
{
|
{
|
||||||
const Selection& selection = m_parent.get_selection();
|
const Selection& selection = m_parent.get_selection();
|
||||||
//glsafe(::glEnable(GL_DEPTH_TEST));
|
//glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
|
|
@ -70,8 +70,8 @@ public:
|
||||||
private:
|
private:
|
||||||
bool on_init() override;
|
bool on_init() override;
|
||||||
void on_update(const UpdateData& data) override;
|
void on_update(const UpdateData& data) override;
|
||||||
void on_render() const override;
|
void on_render() override;
|
||||||
void on_render_for_picking() const override;
|
void on_render_for_picking() override;
|
||||||
|
|
||||||
void render_points(const Selection& selection, bool picking = false) const;
|
void render_points(const Selection& selection, bool picking = false) const;
|
||||||
bool unsaved_changes() const;
|
bool unsaved_changes() const;
|
||||||
|
|
|
@ -4689,6 +4689,7 @@ void Plater::render_project_state_debug_window() const { p->render_project_state
|
||||||
#endif // ENABLE_PROJECT_DIRTY_STATE
|
#endif // ENABLE_PROJECT_DIRTY_STATE
|
||||||
|
|
||||||
Sidebar& Plater::sidebar() { return *p->sidebar; }
|
Sidebar& Plater::sidebar() { return *p->sidebar; }
|
||||||
|
const Model& Plater::model() const { return p->model; }
|
||||||
Model& Plater::model() { return p->model; }
|
Model& Plater::model() { return p->model; }
|
||||||
const Print& Plater::fff_print() const { return p->fff_print; }
|
const Print& Plater::fff_print() const { return p->fff_print; }
|
||||||
Print& Plater::fff_print() { return p->fff_print; }
|
Print& Plater::fff_print() { return p->fff_print; }
|
||||||
|
|
|
@ -149,6 +149,7 @@ public:
|
||||||
#endif // ENABLE_PROJECT_DIRTY_STATE
|
#endif // ENABLE_PROJECT_DIRTY_STATE
|
||||||
|
|
||||||
Sidebar& sidebar();
|
Sidebar& sidebar();
|
||||||
|
const Model& model() const;
|
||||||
Model& model();
|
Model& model();
|
||||||
const Print& fff_print() const;
|
const Print& fff_print() const;
|
||||||
Print& fff_print();
|
Print& fff_print();
|
||||||
|
|
|
@ -699,14 +699,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||||
int rot_axis_max = 0;
|
int rot_axis_max = 0;
|
||||||
if (rotation.isApprox(Vec3d::Zero())) {
|
if (rotation.isApprox(Vec3d::Zero())) {
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
GLVolume &volume = *(*m_volumes)[i];
|
GLVolume &v = *(*m_volumes)[i];
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
|
v.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
|
||||||
volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
|
v.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
|
||||||
}
|
}
|
||||||
else if (m_mode == Volume) {
|
else if (m_mode == Volume) {
|
||||||
volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
|
v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
|
||||||
volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
|
v.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -747,22 +747,22 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
GLVolume &volume = *(*m_volumes)[i];
|
GLVolume &v = *(*m_volumes)[i];
|
||||||
if (is_single_full_instance())
|
if (is_single_full_instance())
|
||||||
rotate_instance(volume, i);
|
rotate_instance(v, i);
|
||||||
else if (is_single_volume() || is_single_modifier()) {
|
else if (is_single_volume() || is_single_modifier()) {
|
||||||
if (transformation_type.independent())
|
if (transformation_type.independent())
|
||||||
volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
|
v.set_volume_rotation(v.get_volume_rotation() + rotation);
|
||||||
else {
|
else {
|
||||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||||
const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
|
||||||
volume.set_volume_rotation(new_rotation);
|
v.set_volume_rotation(new_rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_mode == Instance)
|
if (m_mode == Instance)
|
||||||
rotate_instance(volume, i);
|
rotate_instance(v, i);
|
||||||
else if (m_mode == Volume) {
|
else if (m_mode == Volume) {
|
||||||
// extracts rotations from the composed transformation
|
// extracts rotations from the composed transformation
|
||||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||||
|
@ -770,9 +770,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
|
||||||
if (transformation_type.joint()) {
|
if (transformation_type.joint()) {
|
||||||
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
|
const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
|
||||||
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
|
const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
|
||||||
volume.set_volume_offset(local_pivot + offset);
|
v.set_volume_offset(local_pivot + offset);
|
||||||
}
|
}
|
||||||
volume.set_volume_rotation(new_rotation);
|
v.set_volume_rotation(new_rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,9 +840,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
||||||
bool is_sla = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
bool is_sla = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
||||||
|
|
||||||
for (unsigned int i : m_list) {
|
for (unsigned int i : m_list) {
|
||||||
GLVolume &volume = *(*m_volumes)[i];
|
GLVolume &v = *(*m_volumes)[i];
|
||||||
if (!is_sla) {
|
if (!is_sla) {
|
||||||
if (volume.is_modifier)
|
if (v.is_modifier)
|
||||||
is_any_volume_sinking = true;
|
is_any_volume_sinking = true;
|
||||||
else
|
else
|
||||||
is_any_volume_sinking |= std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end();
|
is_any_volume_sinking |= std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end();
|
||||||
|
@ -854,23 +854,23 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
||||||
// extracts scaling factors from the composed transformation
|
// extracts scaling factors from the composed transformation
|
||||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||||
if (transformation_type.joint())
|
if (transformation_type.joint())
|
||||||
volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||||
|
|
||||||
volume.set_instance_scaling_factor(new_scale);
|
v.set_instance_scaling_factor(new_scale);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) {
|
||||||
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
// Non-uniform scaling. Transform the scaling factors into the local coordinate system.
|
||||||
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
// This is only possible, if the instance rotation is mulitples of ninety degrees.
|
||||||
assert(Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation()));
|
assert(Geometry::is_rotation_ninety_degrees(v.get_instance_rotation()));
|
||||||
volume.set_instance_scaling_factor((volume.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs());
|
v.set_instance_scaling_factor((v.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
volume.set_instance_scaling_factor(scale);
|
v.set_instance_scaling_factor(scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_single_volume() || is_single_modifier())
|
else if (is_single_volume() || is_single_modifier())
|
||||||
volume.set_volume_scaling_factor(scale);
|
v.set_volume_scaling_factor(scale);
|
||||||
else {
|
else {
|
||||||
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale);
|
||||||
if (m_mode == Instance) {
|
if (m_mode == Instance) {
|
||||||
|
@ -878,9 +878,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
||||||
// extracts scaling factors from the composed transformation
|
// extracts scaling factors from the composed transformation
|
||||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||||
if (transformation_type.joint())
|
if (transformation_type.joint())
|
||||||
volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
|
||||||
|
|
||||||
volume.set_instance_scaling_factor(new_scale);
|
v.set_instance_scaling_factor(new_scale);
|
||||||
}
|
}
|
||||||
else if (m_mode == Volume) {
|
else if (m_mode == Volume) {
|
||||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3);
|
||||||
|
@ -888,9 +888,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type
|
||||||
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm());
|
||||||
if (transformation_type.joint()) {
|
if (transformation_type.joint()) {
|
||||||
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
|
||||||
volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset);
|
||||||
}
|
}
|
||||||
volume.set_volume_scaling_factor(new_scale);
|
v.set_volume_scaling_factor(new_scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue