SLA gizmo now shows arrows pointing at the points so they are easy to see

This commit is contained in:
Lukas Matena 2019-03-13 14:32:09 +01:00
parent 46d19aa52d
commit 2750a8113d
2 changed files with 83 additions and 33 deletions

View file

@ -1873,8 +1873,8 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b
float render_color[3];
for (int i = 0; i < (int)m_editing_mode_cache.size(); ++i)
{
const sla::SupportPoint& support_point = m_editing_mode_cache[i].first;
const bool& point_selected = m_editing_mode_cache[i].second;
const sla::SupportPoint& support_point = m_editing_mode_cache[i].support_point;
const bool& point_selected = m_editing_mode_cache[i].selected;
// First decide about the color of the point.
if (picking) {
@ -1889,7 +1889,7 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b
render_color[2] = 1.0f;
}
else { // neigher hover nor picking
bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].first.is_new_island;
bool supports_new_island = m_lock_unique_islands && m_editing_mode_cache[i].support_point.is_new_island;
if (m_editing_mode) {
render_color[0] = point_selected ? 1.0f : (supports_new_island ? 0.3f : 0.7f);
render_color[1] = point_selected ? 0.3f : (supports_new_island ? 0.3f : 0.7f);
@ -1903,12 +1903,32 @@ void GLGizmoSlaSupports::render_points(const GLCanvas3D::Selection& selection, b
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f};
::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive);
// Now render the sphere. Inverse matrix of the instance scaling is applied so that the
// sphere does not scale with the object.
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
::glPushMatrix();
::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2));
::glMultMatrixd(instance_scaling_matrix_inverse.data());
::gluSphere(m_quadric, m_editing_mode_cache[i].first.head_front_radius * RenderPointScale, 64, 36);
// Matrices set, we can render the point mark now.
// If in editing mode, we'll also render a cone pointing to the sphere.
if (m_editing_mode) {
if (m_editing_mode_cache[i].normal == Vec3f::Zero())
update_cache_entry_normal(i); // in case the normal is not yet cached, find and cache it
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_mode_cache[i].normal.cast<double>());
Eigen::AngleAxisd aa(q);
::glRotated(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2));
const float cone_radius = 0.25f; // mm
const float cone_height = 0.75f;
::glPushMatrix();
::glTranslatef(0.f, 0.f, m_editing_mode_cache[i].support_point.head_front_radius * RenderPointScale);
::gluCylinder(m_quadric, 0.f, cone_radius, cone_height, 36, 1);
::glTranslatef(0.f, 0.f, cone_height);
::gluDisk(m_quadric, 0.0, cone_radius, 36, 1);
::glPopMatrix();
}
::gluSphere(m_quadric, m_editing_mode_cache[i].support_point.head_front_radius * RenderPointScale, 64, 36);
::glPopMatrix();
}
@ -1957,7 +1977,7 @@ void GLGizmoSlaSupports::update_mesh()
m_AABB.init(m_V, m_F);
}
Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
{
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
if (m_V.size() == 0)
@ -1992,9 +2012,16 @@ Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
if (!m_AABB.intersect_ray(m_V, m_F, point1.cast<float>(), (point2-point1).cast<float>(), hit))
throw std::invalid_argument("unproject_on_mesh(): No intersection found.");
int fid = hit.id;
Vec3f bc(1-hit.u-hit.v, hit.u, hit.v);
return bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2));
int fid = hit.id; // facet id
Vec3f bc(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit
Vec3f a = (m_V.row(m_F(fid, 1)) - m_V.row(m_F(fid, 0)));
Vec3f b = (m_V.row(m_F(fid, 2)) - m_V.row(m_F(fid, 0)));
// Calculate and return both the point and the facet normal.
return std::make_pair(
bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2)),
a.cross(b)
);
}
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
@ -2046,10 +2073,9 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
// If there is some selection, don't add new point and deselect everything instead.
if (m_selection_empty) {
Vec3f new_pos;
try {
new_pos = unproject_on_mesh(mouse_position); // this can throw - we don't want to create a new point in that case
m_editing_mode_cache.emplace_back(std::make_pair(sla::SupportPoint(new_pos, m_new_point_head_diameter/2.f, false), false));
std::pair<Vec3f, Vec3f> pos_and_normal = unproject_on_mesh(mouse_position); // don't create anything if this throws
m_editing_mode_cache.emplace_back(sla::SupportPoint(pos_and_normal.first, m_new_point_head_diameter/2.f, false), false, pos_and_normal.second);
m_unsaved_changes = true;
}
catch (...) { // not clicked on object
@ -2090,7 +2116,7 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
// Iterate over all points, check if they're in the rectangle and if so, check that they are not obscured by the mesh:
for (unsigned int i=0; i<m_editing_mode_cache.size(); ++i) {
const sla::SupportPoint &support_point = m_editing_mode_cache[i].first;
const sla::SupportPoint &support_point = m_editing_mode_cache[i].support_point;
Vec3f pos = instance_matrix.cast<float>() * support_point.pos;
pos(2) += z_offset;
GLdouble out_x, out_y, out_z;
@ -2166,7 +2192,7 @@ bool GLGizmoSlaSupports::mouse_event(SLAGizmoEventType action, const Vec2d& mous
void GLGizmoSlaSupports::delete_selected_points(bool force)
{
for (unsigned int idx=0; idx<m_editing_mode_cache.size(); ++idx) {
if (m_editing_mode_cache[idx].second && (!m_editing_mode_cache[idx].first.is_new_island || !m_lock_unique_islands || force)) {
if (m_editing_mode_cache[idx].selected && (!m_editing_mode_cache[idx].support_point.is_new_island || !m_lock_unique_islands || force)) {
m_editing_mode_cache.erase(m_editing_mode_cache.begin() + (idx--));
m_unsaved_changes = true;
}
@ -2181,14 +2207,15 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
void GLGizmoSlaSupports::on_update(const UpdateData& data, const GLCanvas3D::Selection& selection)
{
if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].first.is_new_island || !m_lock_unique_islands)) {
Vec3f new_pos;
if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
std::pair<Vec3f, Vec3f> pos_and_normal;
try {
new_pos = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1)));
pos_and_normal = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1)));
}
catch (...) { return; }
m_editing_mode_cache[m_hover_id].first.pos = new_pos;
m_editing_mode_cache[m_hover_id].first.is_new_island = false;
m_editing_mode_cache[m_hover_id].support_point.pos = pos_and_normal.first;
m_editing_mode_cache[m_hover_id].support_point.is_new_island = false;
m_editing_mode_cache[m_hover_id].normal = pos_and_normal.second;
m_unsaved_changes = true;
// Do not update immediately, wait until the mouse is released.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
@ -2255,6 +2282,18 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
}
void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const
{
int idx = 0;
Eigen::Matrix<float, 1, 3> pp = m_editing_mode_cache[i].support_point.pos;
Eigen::Matrix<float, 1, 3> cc;
m_AABB.squared_distance(m_V, m_F, pp, idx, cc);
Vec3f a = (m_V.row(m_F(idx, 1)) - m_V.row(m_F(idx, 0)));
Vec3f b = (m_V.row(m_F(idx, 2)) - m_V.row(m_F(idx, 0)));
m_editing_mode_cache[i].normal = a.cross(b);
}
#if ENABLE_IMGUI
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit, const GLCanvas3D::Selection& selection)
@ -2295,9 +2334,9 @@ RENDER_AGAIN:
ImGui::SameLine();
if (ImGui::SliderFloat("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f")) {
// value was changed
for (auto& point_and_selection : m_editing_mode_cache)
if (point_and_selection.second) {
point_and_selection.first.head_front_radius = m_new_point_head_diameter / 2.f;
for (auto& cache_entry : m_editing_mode_cache)
if (cache_entry.selected) {
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
m_unsaved_changes = true;
}
}
@ -2480,16 +2519,16 @@ void GLGizmoSlaSupports::select_point(int i)
{
if (i == AllPoints || i == NoPoints) {
for (auto& point_and_selection : m_editing_mode_cache)
point_and_selection.second = ( i == AllPoints );
point_and_selection.selected = ( i == AllPoints );
m_selection_empty = (i == NoPoints);
if (i == AllPoints)
m_new_point_head_diameter = m_editing_mode_cache[0].first.head_front_radius * 2.f;
m_new_point_head_diameter = m_editing_mode_cache[0].support_point.head_front_radius * 2.f;
}
else {
m_editing_mode_cache[i].second = true;
m_editing_mode_cache[i].selected = true;
m_selection_empty = false;
m_new_point_head_diameter = m_editing_mode_cache[i].first.head_front_radius * 2.f;
m_new_point_head_diameter = m_editing_mode_cache[i].support_point.head_front_radius * 2.f;
}
}
@ -2499,7 +2538,7 @@ void GLGizmoSlaSupports::editing_mode_discard_changes()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode_cache.emplace_back(point, false);
m_editing_mode = false;
m_unsaved_changes = false;
}
@ -2513,8 +2552,8 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
if (m_unsaved_changes) {
m_model_object->sla_points_status = sla::PointsStatus::UserModified;
m_model_object->sla_support_points.clear();
for (const std::pair<sla::SupportPoint, bool>& point_and_selection : m_editing_mode_cache)
m_model_object->sla_support_points.push_back(point_and_selection.first);
for (const CacheEntry& cache_entry : m_editing_mode_cache)
m_model_object->sla_support_points.push_back(cache_entry.support_point);
// Recalculate support structures once the editing mode is left.
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
@ -2531,7 +2570,7 @@ void GLGizmoSlaSupports::editing_mode_reload_cache()
{
m_editing_mode_cache.clear();
for (const sla::SupportPoint& point : m_model_object->sla_support_points)
m_editing_mode_cache.push_back(std::make_pair(point, false));
m_editing_mode_cache.emplace_back(point, false);
m_unsaved_changes = false;
}

View file

@ -471,7 +471,7 @@ private:
ModelObject* m_old_model_object = nullptr;
int m_active_instance = -1;
int m_old_instance_id = -1;
Vec3f unproject_on_mesh(const Vec2d& mouse_pos);
std::pair<Vec3f, Vec3f> unproject_on_mesh(const Vec2d& mouse_pos);
const float RenderPointScale = 1.f;
@ -484,6 +484,16 @@ private:
Geometry::Transformation transformation;
};
class CacheEntry {
public:
CacheEntry(const sla::SupportPoint& point, bool sel, const Vec3f& norm = Vec3f::Zero()) :
support_point(point), selected(sel), normal(norm) {}
sla::SupportPoint support_point;
bool selected; // whether the point is selected
Vec3f normal;
};
// This holds information to decide whether recalculation is necessary:
SourceDataSummary m_source_data;
@ -510,6 +520,7 @@ private:
void render_points(const GLCanvas3D::Selection& selection, bool picking = false) const;
bool is_mesh_update_necessary() const;
void update_mesh();
void update_cache_entry_normal(unsigned int i) const;
#if !ENABLE_IMGUI
void render_tooltip_texture() const;
@ -523,7 +534,7 @@ private:
float m_new_point_head_diameter; // Size of a new point.
float m_minimal_point_distance = 20.f;
float m_density = 100.f;
std::vector<std::pair<sla::SupportPoint, bool>> m_editing_mode_cache; // a support point and whether it is currently selected
mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
bool m_selection_rectangle_active = false;
Vec2d m_selection_rectangle_start_corner;