mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 04:45:57 +08:00
Cut WIP:
* Added a first detection if a connector position is valid * Code cleaning: Deleted unused set_range_and_pos function * Some code refactoring
This commit is contained in:
parent
a42212487d
commit
f9e22513c1
@ -369,18 +369,6 @@ bool GLGizmoCut3D::render_revert_button(const std::string& label_id)
|
||||
|
||||
void GLGizmoCut3D::render_cut_plane()
|
||||
{
|
||||
const BoundingBoxf3 box = bounding_box();
|
||||
|
||||
const float min_x = box.min.x() - Margin - m_plane_center.x();
|
||||
const float max_x = box.max.x() + Margin - m_plane_center.x();
|
||||
const float min_y = box.min.y() - Margin - m_plane_center.y();
|
||||
const float max_y = box.max.y() + Margin - m_plane_center.y();
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat_attr");
|
||||
@ -389,6 +377,12 @@ void GLGizmoCut3D::render_cut_plane()
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
shader->start_using();
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
@ -410,14 +404,18 @@ void GLGizmoCut3D::render_cut_plane()
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
|
||||
if (!m_plane.is_initialized()) {
|
||||
m_plane.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f };
|
||||
init_data.reserve_vertices(4);
|
||||
init_data.reserve_indices(6);
|
||||
|
||||
const BoundingBoxf3 bb = bounding_box();
|
||||
const float min_x = bb.min.x() - Margin - m_plane_center.x();
|
||||
const float max_x = bb.max.x() + Margin - m_plane_center.x();
|
||||
const float min_y = bb.min.y() - Margin - m_plane_center.y();
|
||||
const float max_y = bb.max.y() + Margin - m_plane_center.y();
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(min_x, min_y, 0.0));
|
||||
init_data.add_vertex(Vec3f(max_x, min_y, 0.0));
|
||||
@ -547,14 +545,9 @@ std::string GLGizmoCut3D::on_get_name() const
|
||||
|
||||
void GLGizmoCut3D::on_set_state()
|
||||
{
|
||||
if (get_state() == On) {
|
||||
if (get_state() == On)
|
||||
update_bb();
|
||||
|
||||
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
|
||||
m_selected.clear();
|
||||
m_selected.resize(selection->model_object()->cut_connectors.size(), false);
|
||||
}
|
||||
}
|
||||
m_rotation_gizmo.set_center(m_plane_center);
|
||||
m_rotation_gizmo.set_state(m_state);
|
||||
|
||||
@ -653,6 +646,13 @@ bool GLGizmoCut3D::update_bb()
|
||||
m_min_pos = box.min;
|
||||
m_bb_center = box.center();
|
||||
set_center_pos(m_bb_center + m_center_offset);
|
||||
|
||||
m_plane.reset();
|
||||
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
|
||||
m_selected.clear();
|
||||
m_selected.resize(selection->model_object()->cut_connectors.size(), false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -841,7 +841,8 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
static bool hide_clipped = true;
|
||||
static bool fill_cut = true;
|
||||
static float contour_width = 0.2f;
|
||||
m_imgui->checkbox("hide_clipped", hide_clipped);
|
||||
if (m_imgui->checkbox("hide_clipped", hide_clipped) && !hide_clipped)
|
||||
m_clp_normal = m_c->object_clipper()->get_clipping_plane()->get_normal();
|
||||
m_imgui->checkbox("fill_cut", fill_cut);
|
||||
m_imgui->slider_float("contour_width", &contour_width, 0.f, 3.f);
|
||||
m_c->object_clipper()->set_behavior(hide_clipped, fill_cut, contour_width);
|
||||
@ -860,11 +861,43 @@ void GLGizmoCut3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
}
|
||||
}
|
||||
|
||||
// get volume transformation regarding to the "border". Border is related from the siae of connectors
|
||||
Transform3d GLGizmoCut3D::get_volume_transformation(const ModelVolume* volume) const
|
||||
{
|
||||
bool is_prizm_dowel = m_connector_type == CutConnectorType::Dowel && m_connector_style == size_t(CutConnectorStyle::Prizm);
|
||||
const Transform3d connector_trafo = Geometry::assemble_transform(
|
||||
is_prizm_dowel ? Vec3d(0.0, 0.0, -m_connector_depth_ratio) : Vec3d::Zero(),
|
||||
m_rotation_gizmo.get_rotation(),
|
||||
Vec3d(0.5*m_connector_size, 0.5*m_connector_size, is_prizm_dowel ? 2 * m_connector_depth_ratio : m_connector_depth_ratio),
|
||||
Vec3d::Ones());
|
||||
const Vec3d connector_bb = m_connector_mesh.transformed_bounding_box(connector_trafo).size();
|
||||
|
||||
const Vec3d bb = volume->mesh().bounding_box().size();
|
||||
|
||||
// calculate an unused border - part of the the volume, where we can't put connectors
|
||||
const Vec3d border_scale(connector_bb.x() / bb.x(), connector_bb.y() / bb.y(), connector_bb.z() / bb.z());
|
||||
|
||||
const Transform3d vol_matrix = volume->get_matrix();
|
||||
const Vec3d vol_trans = vol_matrix.translation();
|
||||
// offset of the volume will be changed after scaling, so calculate the needed offset and set it to a volume_trafo
|
||||
const Vec3d offset(vol_trans.x() * border_scale.x(), vol_trans.y() * border_scale.y(), vol_trans.z() * border_scale.z());
|
||||
|
||||
// scale and translate volume to suppress to put connectors too close to the border
|
||||
return Geometry::assemble_transform(offset, Vec3d::Zero(), Vec3d::Ones() - border_scale, Vec3d::Ones()) * vol_matrix;
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_connectors(bool picking)
|
||||
{
|
||||
m_has_invalid_connector = false;
|
||||
|
||||
if (m_connector_mode == CutConnectorMode::Auto)
|
||||
return;
|
||||
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const CutConnectors& connectors = mo->cut_connectors;
|
||||
if (connectors.size() != m_selected.size())
|
||||
return;
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat_attr") : wxGetApp().get_shader("gouraud_light_attr");
|
||||
@ -892,47 +925,59 @@ void GLGizmoCut3D::render_connectors(bool picking)
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
|
||||
ColorRGBA render_color;
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const CutConnectors& connectors = mo->cut_connectors;
|
||||
size_t cache_size = connectors.size();
|
||||
|
||||
const Vec3d& instance_offset = mo->instances[m_c->selection_info()->get_active_instance()]->get_offset();
|
||||
const ModelInstance* mi = mo->instances[m_c->selection_info()->get_active_instance()];
|
||||
const Vec3d& instance_offset = mi->get_offset();
|
||||
const float sla_shift = m_c->selection_info()->get_sla_shift();
|
||||
|
||||
const ClippingPlane* cp = m_c->object_clipper()->get_clipping_plane();
|
||||
const Vec3d& normal = cp ? cp->get_normal() : Vec3d::Ones();
|
||||
const Vec3d& normal = cp && cp->is_active() ? cp->get_normal() : m_clp_normal;
|
||||
|
||||
for (size_t i = 0; i < cache_size; ++i) {
|
||||
const Transform3d instance_trafo = Geometry::assemble_transform(Vec3d(0.0, 0.0, sla_shift), Vec3d::Zero(), Vec3d::Ones(), Vec3d::Ones()) * mi->get_transformation().get_matrix();
|
||||
|
||||
for (size_t i = 0; i < connectors.size(); ++i) {
|
||||
const CutConnector& connector = connectors[i];
|
||||
const bool& point_selected = m_selected[i];
|
||||
|
||||
double height = connector.height;
|
||||
// recalculate connector position to world position
|
||||
Vec3d pos = connector.pos + instance_offset;
|
||||
if (m_connector_type == CutConnectorType::Dowel &&
|
||||
m_connector_style == size_t(CutConnectorStyle::Prizm)) {
|
||||
pos -= height * normal;
|
||||
height *= 2;
|
||||
}
|
||||
pos[Z] += sla_shift;
|
||||
|
||||
// First decide about the color of the point.
|
||||
if (picking)
|
||||
render_color = picking_decode(BASE_ID - i - m_connectors_group_id);
|
||||
else {
|
||||
if (size_t(m_hover_id- m_connectors_group_id) == i)
|
||||
render_color = ColorRGBA::CYAN();
|
||||
else // neither hover nor picking
|
||||
render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
}
|
||||
else { // neither hover nor picking
|
||||
int mesh_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
++mesh_id;
|
||||
if (!mv->is_model_part())
|
||||
continue;
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
m_connector_shape.set_color(render_color);
|
||||
#else
|
||||
const_cast<GLModel*>(&m_connector_shape)->set_color(-1, render_color);
|
||||
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL
|
||||
const Transform3d volume_trafo = get_volume_transformation(mv);
|
||||
|
||||
double height = connector.height;
|
||||
// recalculate connector position to world position
|
||||
Vec3d pos = connector.pos + instance_offset;
|
||||
if (m_connector_type == CutConnectorType::Dowel &&
|
||||
m_connector_style == size_t(CutConnectorStyle::Prizm)) {
|
||||
pos -= height * normal;
|
||||
height *= 2;
|
||||
if (m_c->raycaster()->raycasters()[mesh_id]->is_valid_intersection(pos, -normal, instance_trafo * volume_trafo)) {
|
||||
render_color = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
break;
|
||||
}
|
||||
render_color = ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f);
|
||||
}
|
||||
if (!m_has_invalid_connector && render_color == ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f))
|
||||
m_has_invalid_connector = true;
|
||||
}
|
||||
}
|
||||
pos[Z] += sla_shift;
|
||||
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
m_connector_shape.set_color(render_color);
|
||||
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() * Geometry::assemble_transform(
|
||||
Vec3d(pos.x(), pos.y(), pos.z()),
|
||||
m_rotation_gizmo.get_rotation(),
|
||||
@ -942,6 +987,8 @@ void GLGizmoCut3D::render_connectors(bool picking)
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
const_cast<GLModel*>(&m_connector_shape)->set_color(-1, render_color);
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(pos.x(), pos.y(), pos.z()));
|
||||
|
||||
@ -968,6 +1015,9 @@ void GLGizmoCut3D::render_connectors(bool picking)
|
||||
|
||||
bool GLGizmoCut3D::can_perform_cut() const
|
||||
{
|
||||
if (m_has_invalid_connector)
|
||||
return false;
|
||||
|
||||
BoundingBoxf3 box = bounding_box();
|
||||
double dist = (m_plane_center - box.center()).norm();
|
||||
if (dist > box.radius())
|
||||
@ -1053,7 +1103,10 @@ bool GLGizmoCut3D::unproject_on_cut_plane(const Vec2d& mouse_position, std::pair
|
||||
Vec3f hit;
|
||||
Vec3f normal;
|
||||
bool clipping_plane_was_hit = false;
|
||||
m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * mv->get_matrix(),
|
||||
|
||||
const Transform3d volume_trafo = get_volume_transformation(mv);
|
||||
|
||||
m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, instance_trafo * volume_trafo,
|
||||
camera, hit, normal, m_c->object_clipper()->get_clipping_plane(),
|
||||
nullptr, &clipping_plane_was_hit);
|
||||
if (clipping_plane_was_hit) {
|
||||
@ -1082,7 +1135,12 @@ void GLGizmoCut3D::update_connector_shape()
|
||||
if (m_connector_shape.is_initialized())
|
||||
m_connector_shape.reset();
|
||||
|
||||
m_connector_shape.init_from(ModelObject::get_connector_mesh({ m_connector_type, CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id) }));
|
||||
const indexed_triangle_set its = ModelObject::get_connector_mesh({ m_connector_type, CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id) });
|
||||
m_connector_shape.init_from(its);
|
||||
|
||||
m_connector_mesh.clear();
|
||||
m_connector_mesh = TriangleMesh(its);
|
||||
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::update_model_object() const
|
||||
|
@ -11,6 +11,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
enum class CutConnectorType : int;
|
||||
class ModelVolume;
|
||||
|
||||
namespace GUI {
|
||||
class Selection;
|
||||
@ -30,7 +31,10 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
Vec3d m_bb_center{ Vec3d::Zero() };
|
||||
Vec3d m_center_offset{ Vec3d::Zero() };
|
||||
|
||||
GLModel m_connector_shape;
|
||||
GLModel m_connector_shape;
|
||||
TriangleMesh m_connector_mesh;
|
||||
// workaround for using of the clipping plane normal
|
||||
Vec3d m_clp_normal{ Vec3d::Ones() };
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
GLModel m_plane;
|
||||
@ -57,6 +61,8 @@ class GLGizmoCut3D : public GLGizmoBase
|
||||
bool m_selection_empty = true;
|
||||
bool m_wait_for_up_event = false;
|
||||
|
||||
bool m_has_invalid_connector{ false };
|
||||
|
||||
Matrix3d m_rotation_matrix;
|
||||
Vec3d m_rotations{ Vec3d::Zero() };
|
||||
|
||||
@ -136,6 +142,7 @@ private:
|
||||
void render_connect_mode_radio_button(CutConnectorMode mode);
|
||||
bool render_revert_button(const std::string& label);
|
||||
void render_connect_type_radio_button(CutConnectorType type);
|
||||
Transform3d get_volume_transformation(const ModelVolume* volume) const;
|
||||
void render_connectors(bool picking);
|
||||
|
||||
bool can_perform_cut() const;
|
||||
|
@ -465,17 +465,6 @@ void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal)
|
||||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
void ObjectClipper::set_range_and_pos(const Vec3d& origin, const Vec3d& end, double pos)
|
||||
{
|
||||
Vec3d normal = end-origin;
|
||||
double norm = normal.norm();
|
||||
pos = std::clamp(pos, 0.0001, norm);
|
||||
normal.normalize();
|
||||
m_clp.reset(new ClippingPlane(normal, normal.dot(origin)+pos));
|
||||
m_clp_ratio = pos;
|
||||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
void ObjectClipper::set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos)
|
||||
{
|
||||
m_clp.reset(new ClippingPlane(cpl_normal, cpl_offset));
|
||||
|
@ -260,7 +260,6 @@ public:
|
||||
const ClippingPlane* get_clipping_plane() const;
|
||||
void render_cut() const;
|
||||
void set_position_by_ratio(double pos, bool keep_normal);
|
||||
void set_range_and_pos(const Vec3d& origin, const Vec3d& end, double pos);
|
||||
void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos);
|
||||
void set_behavior(bool hide_clipped, bool fill_cut, double contour_width);
|
||||
|
||||
|
@ -416,6 +416,17 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
||||
}
|
||||
|
||||
|
||||
bool MeshRaycaster::is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const
|
||||
{
|
||||
point = trafo.inverse() * point;
|
||||
|
||||
std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||
std::vector<sla::IndexedMesh::hit_result> neg_hits = m_emesh.query_ray_hits(point, -direction);
|
||||
|
||||
return !hits.empty() && !neg_hits.empty();
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
|
||||
const ClippingPlane* clipping_plane) const
|
||||
{
|
||||
|
@ -157,6 +157,8 @@ public:
|
||||
bool* was_clipping_plane_hit = nullptr // is the hit on the clipping place cross section?
|
||||
) const;
|
||||
|
||||
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
||||
|
||||
// Given a vector of points in woorld coordinates, this returns vector
|
||||
// of indices of points that are visible (i.e. not cut by clipping plane
|
||||
// or obscured by part of the mesh.
|
||||
|
Loading…
x
Reference in New Issue
Block a user