Merge branch 'lm_painter_fixes'
This commit is contained in:
commit
dbedd3f9b0
@ -34,16 +34,15 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si
|
||||
|
||||
|
||||
void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
|
||||
const Vec3f& source, const Vec3f& dir,
|
||||
float radius, CursorType cursor_type,
|
||||
EnforcerBlockerType new_state)
|
||||
const Vec3f& source, float radius,
|
||||
CursorType cursor_type, EnforcerBlockerType new_state,
|
||||
const Transform3d& trafo)
|
||||
{
|
||||
assert(facet_start < m_orig_size_indices);
|
||||
assert(is_approx(dir.norm(), 1.f));
|
||||
|
||||
// Save current cursor center, squared radius and camera direction,
|
||||
// so we don't have to pass it around.
|
||||
m_cursor = {hit, source, dir, radius*radius, cursor_type};
|
||||
// Save current cursor center, squared radius and camera direction, so we don't
|
||||
// have to pass it around.
|
||||
m_cursor = Cursor(hit, source, radius, cursor_type, trafo);
|
||||
|
||||
// In case user changed cursor size since last time, update triangle edge limit.
|
||||
if (m_old_cursor_radius != radius) {
|
||||
@ -176,8 +175,22 @@ void TriangleSelector::split_triangle(int facet_idx)
|
||||
const double limit_squared = m_edge_limit_sqr;
|
||||
|
||||
std::array<int, 3>& facet = tr->verts_idxs;
|
||||
const stl_vertex* pts[3] = { &m_vertices[facet[0]].v, &m_vertices[facet[1]].v, &m_vertices[facet[2]].v};
|
||||
double sides[3] = { (*pts[2]-*pts[1]).squaredNorm(),
|
||||
std::array<const stl_vertex*, 3> pts = { &m_vertices[facet[0]].v,
|
||||
&m_vertices[facet[1]].v,
|
||||
&m_vertices[facet[2]].v};
|
||||
std::array<stl_vertex, 3> pts_transformed; // must stay in scope of pts !!!
|
||||
|
||||
// In case the object is non-uniformly scaled, transform the
|
||||
// points to world coords.
|
||||
if (! m_cursor.uniform_scaling) {
|
||||
for (size_t i=0; i<pts.size(); ++i) {
|
||||
pts_transformed[i] = m_cursor.trafo * (*pts[i]);
|
||||
pts[i] = &pts_transformed[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::array<double, 3> sides;
|
||||
sides = { (*pts[2]-*pts[1]).squaredNorm(),
|
||||
(*pts[0]-*pts[2]).squaredNorm(),
|
||||
(*pts[1]-*pts[0]).squaredNorm() };
|
||||
|
||||
@ -204,38 +217,14 @@ void TriangleSelector::split_triangle(int facet_idx)
|
||||
}
|
||||
|
||||
|
||||
// Calculate distance of a point from a line.
|
||||
bool TriangleSelector::is_point_inside_cursor(const Vec3f& point) const
|
||||
{
|
||||
Vec3f diff = m_cursor.center - point;
|
||||
|
||||
if (m_cursor.type == CIRCLE)
|
||||
return (diff - diff.dot(m_cursor.dir) * m_cursor.dir).squaredNorm() < m_cursor.radius_sqr;
|
||||
else // SPHERE
|
||||
return diff.squaredNorm() < m_cursor.radius_sqr;
|
||||
}
|
||||
|
||||
|
||||
// Is pointer in a triangle?
|
||||
bool TriangleSelector::is_pointer_in_triangle(int facet_idx) const
|
||||
{
|
||||
auto signed_volume_sign = [](const Vec3f& a, const Vec3f& b,
|
||||
const Vec3f& c, const Vec3f& d) -> bool {
|
||||
return ((b-a).cross(c-a)).dot(d-a) > 0.;
|
||||
};
|
||||
|
||||
const Vec3f& p1 = m_vertices[m_triangles[facet_idx].verts_idxs[0]].v;
|
||||
const Vec3f& p2 = m_vertices[m_triangles[facet_idx].verts_idxs[1]].v;
|
||||
const Vec3f& p3 = m_vertices[m_triangles[facet_idx].verts_idxs[2]].v;
|
||||
const Vec3f& q1 = m_cursor.center + m_cursor.dir;
|
||||
const Vec3f q2 = m_cursor.center - m_cursor.dir;
|
||||
|
||||
if (signed_volume_sign(q1,p1,p2,p3) != signed_volume_sign(q2,p1,p2,p3)) {
|
||||
bool pos = signed_volume_sign(q1,q2,p1,p2);
|
||||
if (signed_volume_sign(q1,q2,p2,p3) == pos && signed_volume_sign(q1,q2,p3,p1) == pos)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return m_cursor.is_pointer_in_triangle(p1, p2, p3);
|
||||
}
|
||||
|
||||
|
||||
@ -245,7 +234,13 @@ bool TriangleSelector::faces_camera(int facet) const
|
||||
{
|
||||
assert(facet < m_orig_size_indices);
|
||||
// The normal is cached in mesh->stl, use it.
|
||||
return (m_mesh->stl.facet_start[facet].normal.dot(m_cursor.dir) < 0.);
|
||||
Vec3f normal = m_mesh->stl.facet_start[facet].normal;
|
||||
|
||||
if (! m_cursor.uniform_scaling) {
|
||||
// Transform the normal into world coords.
|
||||
normal = m_cursor.trafo_normal * normal;
|
||||
}
|
||||
return (normal.dot(m_cursor.dir) < 0.);
|
||||
}
|
||||
|
||||
|
||||
@ -254,7 +249,7 @@ int TriangleSelector::vertices_inside(int facet_idx) const
|
||||
{
|
||||
int inside = 0;
|
||||
for (size_t i=0; i<3; ++i) {
|
||||
if (is_point_inside_cursor(m_vertices[m_triangles[facet_idx].verts_idxs[i]].v))
|
||||
if (m_cursor.is_mesh_point_inside(m_vertices[m_triangles[facet_idx].verts_idxs[i]].v))
|
||||
++inside;
|
||||
}
|
||||
return inside;
|
||||
@ -264,9 +259,12 @@ int TriangleSelector::vertices_inside(int facet_idx) const
|
||||
// Is edge inside cursor?
|
||||
bool TriangleSelector::is_edge_inside_cursor(int facet_idx) const
|
||||
{
|
||||
Vec3f pts[3];
|
||||
for (int i=0; i<3; ++i)
|
||||
std::array<Vec3f, 3> pts;
|
||||
for (int i=0; i<3; ++i) {
|
||||
pts[i] = m_vertices[m_triangles[facet_idx].verts_idxs[i]].v;
|
||||
if (! m_cursor.uniform_scaling)
|
||||
pts[i] = m_cursor.trafo * pts[i];
|
||||
}
|
||||
|
||||
const Vec3f& p = m_cursor.center;
|
||||
|
||||
@ -690,6 +688,79 @@ void TriangleSelector::deserialize(const std::map<int, std::vector<bool>> data)
|
||||
}
|
||||
|
||||
|
||||
TriangleSelector::Cursor::Cursor(
|
||||
const Vec3f& center_, const Vec3f& source_, float radius_world,
|
||||
CursorType type_, const Transform3d& trafo_)
|
||||
: center{center_},
|
||||
source{source_},
|
||||
type{type_},
|
||||
trafo{trafo_.cast<float>()}
|
||||
{
|
||||
Vec3d sf = Geometry::Transformation(trafo_).get_scaling_factor();
|
||||
if (is_approx(sf(0), sf(1)) && is_approx(sf(1), sf(2))) {
|
||||
radius_sqr = std::pow(radius_world / sf(0), 2);
|
||||
uniform_scaling = true;
|
||||
}
|
||||
else {
|
||||
// In case that the transformation is non-uniform, all checks whether
|
||||
// something is inside the cursor should be done in world coords.
|
||||
// First transform center, source and dir in world coords and remember
|
||||
// that we did this.
|
||||
center = trafo * center;
|
||||
source = trafo * source;
|
||||
uniform_scaling = false;
|
||||
radius_sqr = radius_world * radius_world;
|
||||
trafo_normal = trafo.linear().inverse().transpose();
|
||||
}
|
||||
|
||||
// Calculate dir, in whatever coords is appropriate.
|
||||
dir = (center - source).normalized();
|
||||
}
|
||||
|
||||
|
||||
// Is a point (in mesh coords) inside a cursor?
|
||||
bool TriangleSelector::Cursor::is_mesh_point_inside(Vec3f point) const
|
||||
{
|
||||
if (! uniform_scaling)
|
||||
point = trafo * point;
|
||||
|
||||
Vec3f diff = center - point;
|
||||
|
||||
if (type == CIRCLE)
|
||||
return (diff - diff.dot(dir) * dir).squaredNorm() < radius_sqr;
|
||||
else // SPHERE
|
||||
return diff.squaredNorm() < radius_sqr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// p1, p2, p3 are in mesh coords!
|
||||
bool TriangleSelector::Cursor::is_pointer_in_triangle(const Vec3f& p1_,
|
||||
const Vec3f& p2_,
|
||||
const Vec3f& p3_) const
|
||||
{
|
||||
const Vec3f& q1 = center + dir;
|
||||
const Vec3f& q2 = center - dir;
|
||||
|
||||
auto signed_volume_sign = [](const Vec3f& a, const Vec3f& b,
|
||||
const Vec3f& c, const Vec3f& d) -> bool {
|
||||
return ((b-a).cross(c-a)).dot(d-a) > 0.;
|
||||
};
|
||||
|
||||
// In case the object is non-uniformly scaled, do the check in world coords.
|
||||
const Vec3f& p1 = uniform_scaling ? p1_ : Vec3f(trafo * p1_);
|
||||
const Vec3f& p2 = uniform_scaling ? p2_ : Vec3f(trafo * p2_);
|
||||
const Vec3f& p3 = uniform_scaling ? p3_ : Vec3f(trafo * p3_);
|
||||
|
||||
if (signed_volume_sign(q1,p1,p2,p3) != signed_volume_sign(q2,p1,p2,p3)) {
|
||||
bool pos = signed_volume_sign(q1,q2,p1,p2);
|
||||
if (signed_volume_sign(q1,q2,p2,p3) == pos && signed_volume_sign(q1,q2,p3,p1) == pos)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -32,10 +32,10 @@ public:
|
||||
void select_patch(const Vec3f& hit, // point where to start
|
||||
int facet_start, // facet that point belongs to
|
||||
const Vec3f& source, // camera position (mesh coords)
|
||||
const Vec3f& dir, // direction of the ray (mesh coords)
|
||||
float radius, // radius of the cursor
|
||||
CursorType type, // current type of cursor
|
||||
EnforcerBlockerType new_state); // enforcer or blocker?
|
||||
EnforcerBlockerType new_state, // enforcer or blocker?
|
||||
const Transform3d& trafo); // matrix to get from mesh to world
|
||||
|
||||
// Get facets currently in the given state.
|
||||
indexed_triangle_set get_facets(EnforcerBlockerType state) const;
|
||||
@ -129,11 +129,20 @@ protected:
|
||||
|
||||
// Cache for cursor position, radius and direction.
|
||||
struct Cursor {
|
||||
Cursor() = default;
|
||||
Cursor(const Vec3f& center_, const Vec3f& source_, float radius_world,
|
||||
CursorType type_, const Transform3d& trafo_);
|
||||
bool is_mesh_point_inside(Vec3f pt) const;
|
||||
bool is_pointer_in_triangle(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3) const;
|
||||
|
||||
Vec3f center;
|
||||
Vec3f source;
|
||||
Vec3f dir;
|
||||
float radius_sqr;
|
||||
CursorType type;
|
||||
Transform3f trafo;
|
||||
Transform3f trafo_normal;
|
||||
bool uniform_scaling;
|
||||
};
|
||||
|
||||
Cursor m_cursor;
|
||||
@ -142,7 +151,6 @@ protected:
|
||||
// Private functions:
|
||||
bool select_triangle(int facet_idx, EnforcerBlockerType type,
|
||||
bool recursive_call = false);
|
||||
bool is_point_inside_cursor(const Vec3f& point) const;
|
||||
int vertices_inside(int facet_idx) const;
|
||||
bool faces_camera(int facet) const;
|
||||
void undivide_triangle(int facet_idx);
|
||||
|
@ -1670,8 +1670,9 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
|
||||
} else {
|
||||
const GLGizmosManager& gm = get_gizmos_manager();
|
||||
auto gizmo_type = gm.get_current_type();
|
||||
if (gizmo_type == GLGizmosManager::FdmSupports
|
||||
if ( (gizmo_type == GLGizmosManager::FdmSupports
|
||||
|| gizmo_type == GLGizmosManager::Seam)
|
||||
&& ! vol->is_modifier)
|
||||
vol->force_neutral_color = true;
|
||||
else
|
||||
vol->force_native_color = true;
|
||||
@ -5460,6 +5461,20 @@ void GLCanvas3D::_render_objects() const
|
||||
});
|
||||
}
|
||||
|
||||
// In case a painting gizmo is open, it should render the painted triangles
|
||||
// before transparent objects are rendered. Otherwise they would not be
|
||||
// visible when inside modifier meshes etc.
|
||||
{
|
||||
const GLGizmosManager& gm = get_gizmos_manager();
|
||||
GLGizmosManager::EType type = gm.get_current_type();
|
||||
if (type == GLGizmosManager::FdmSupports
|
||||
|| type == GLGizmosManager::Seam) {
|
||||
shader->stop_using();
|
||||
gm.render_painter_gizmo();
|
||||
shader->start_using();
|
||||
}
|
||||
}
|
||||
|
||||
m_volumes.render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
|
||||
shader->stop_using();
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ bool GLGizmoFdmSupports::on_init()
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_render() const
|
||||
void GLGizmoFdmSupports::render_painter_gizmo() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
|
@ -13,14 +13,14 @@ public:
|
||||
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoPainterBase(parent, icon_filename, sprite_id) {}
|
||||
|
||||
void render_painter_gizmo() const override;
|
||||
|
||||
protected:
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
std::string on_get_name() const override;
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
void on_render() const override;
|
||||
void on_render_for_picking() const override {}
|
||||
|
||||
void update_model_object() const override;
|
||||
void update_from_model_object() override;
|
||||
|
@ -350,19 +350,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
|
||||
const Transform3d& trafo_matrix = trafo_matrices[m_rr.mesh_id];
|
||||
|
||||
// Calculate how far can a point be from the line (in mesh coords).
|
||||
// FIXME: The scaling of the mesh can be non-uniform.
|
||||
const Vec3d sf = Geometry::Transformation(trafo_matrix).get_scaling_factor();
|
||||
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
|
||||
const float limit = m_cursor_radius/avg_scaling;
|
||||
|
||||
// Calculate direction from camera to the hit (in mesh coords):
|
||||
Vec3f camera_pos = (trafo_matrix.inverse() * camera.get_position()).cast<float>();
|
||||
Vec3f dir = (m_rr.hit - camera_pos).normalized();
|
||||
|
||||
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
|
||||
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, m_rr.facet, camera_pos,
|
||||
dir, limit, m_cursor_type, new_state);
|
||||
m_cursor_radius, m_cursor_type, new_state, trafo_matrix);
|
||||
m_last_mouse_click = mouse_position;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,8 @@ class GLGizmoPainterBase : public GLGizmoBase
|
||||
private:
|
||||
ObjectID m_old_mo_id;
|
||||
size_t m_old_volumes_size = 0;
|
||||
virtual void on_render() const {}
|
||||
virtual void on_render_for_picking() const {}
|
||||
|
||||
public:
|
||||
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
@ -66,6 +68,12 @@ public:
|
||||
void set_painter_gizmo_data(const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
// Following function renders the triangles and cursor. Having this separated
|
||||
// from usual on_render method allows to render them before transparent objects,
|
||||
// so they can be seen inside them. The usual on_render is called after all
|
||||
// volumes (including transparent ones) are rendered.
|
||||
virtual void render_painter_gizmo() const = 0;
|
||||
|
||||
protected:
|
||||
void render_triangles(const Selection& selection) const;
|
||||
void render_cursor() const;
|
||||
|
@ -46,7 +46,7 @@ std::string GLGizmoSeam::on_get_name() const
|
||||
|
||||
|
||||
|
||||
void GLGizmoSeam::on_render() const
|
||||
void GLGizmoSeam::render_painter_gizmo() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
|
@ -13,6 +13,8 @@ public:
|
||||
GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoPainterBase(parent, icon_filename, sprite_id) {}
|
||||
|
||||
void render_painter_gizmo() const override;
|
||||
|
||||
protected:
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
std::string on_get_name() const override;
|
||||
@ -20,8 +22,6 @@ protected:
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
void on_render() const override;
|
||||
void on_render_for_picking() const override {}
|
||||
|
||||
void update_model_object() const override;
|
||||
void update_from_model_object() override;
|
||||
|
@ -295,11 +295,9 @@ void ObjectClipper::on_update()
|
||||
if (has_hollowed)
|
||||
meshes.push_back(get_pool()->hollowed_mesh()->get_hollowed_mesh());
|
||||
|
||||
if (meshes.empty()) {
|
||||
if (meshes.empty())
|
||||
for (const ModelVolume* mv : mo->volumes)
|
||||
if (mv->is_model_part())
|
||||
meshes.push_back(&mv->mesh());
|
||||
}
|
||||
|
||||
if (meshes != m_old_meshes) {
|
||||
m_clippers.clear();
|
||||
@ -335,9 +333,6 @@ void ObjectClipper::render_cut() const
|
||||
|
||||
size_t clipper_id = 0;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
Geometry::Transformation vol_trafo = mv->get_transformation();
|
||||
Geometry::Transformation trafo = inst_trafo * vol_trafo;
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
|
@ -437,6 +437,19 @@ void GLGizmosManager::render_current_gizmo() const
|
||||
m_gizmos[m_current]->render();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_painter_gizmo() const
|
||||
{
|
||||
// This function shall only be called when current gizmo is
|
||||
// derived from GLGizmoPainterBase.
|
||||
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
auto* gizmo = dynamic_cast<GLGizmoPainterBase*>(get_current());
|
||||
assert(gizmo); // check the precondition
|
||||
gizmo->render_painter_gizmo();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass() const
|
||||
{
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
|
@ -212,6 +212,7 @@ public:
|
||||
|
||||
void render_current_gizmo() const;
|
||||
void render_current_gizmo_for_picking_pass() const;
|
||||
void render_painter_gizmo() const;
|
||||
|
||||
void render_overlay() const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user