Drain holes are now saved in ModelObject
Internal changes in GLGizmoHollow.cpp
This commit is contained in:
parent
9836533cb3
commit
645f13a0ae
@ -606,6 +606,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||
assert(this->config.id() == rhs.config.id());
|
||||
this->sla_support_points = rhs.sla_support_points;
|
||||
this->sla_points_status = rhs.sla_points_status;
|
||||
this->sla_drain_holes = rhs.sla_drain_holes;
|
||||
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
|
||||
this->layer_height_profile = rhs.layer_height_profile;
|
||||
this->printable = rhs.printable;
|
||||
@ -646,6 +647,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||
assert(this->config.id() == rhs.config.id());
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||
this->sla_drain_holes = std::move(rhs.sla_drain_holes);
|
||||
this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
|
||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||
this->origin_translation = std::move(rhs.origin_translation);
|
||||
@ -1099,6 +1101,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
if (keep_upper) {
|
||||
upper->set_model(nullptr);
|
||||
upper->sla_support_points.clear();
|
||||
lower->sla_drain_holes.clear();
|
||||
upper->sla_points_status = sla::PointsStatus::NoPoints;
|
||||
upper->clear_volumes();
|
||||
upper->input_file = "";
|
||||
@ -1107,6 +1110,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
if (keep_lower) {
|
||||
lower->set_model(nullptr);
|
||||
lower->sla_support_points.clear();
|
||||
lower->sla_drain_holes.clear();
|
||||
lower->sla_points_status = sla::PointsStatus::NoPoints;
|
||||
lower->clear_volumes();
|
||||
lower->input_file = "";
|
||||
|
@ -203,6 +203,9 @@ public:
|
||||
// the SLA gizmo and the backend).
|
||||
sla::PointsStatus sla_points_status = sla::PointsStatus::NoPoints;
|
||||
|
||||
// Holes to be drilled into the object so resin can flow out
|
||||
std::vector<sla::DrainHole> sla_drain_holes;
|
||||
|
||||
/* This vector accumulates the total translation applied to the object by the
|
||||
center_around_origin() method. Callers might want to apply the same translation
|
||||
to new volumes before adding them to this object in order to preserve alignment
|
||||
@ -372,7 +375,7 @@ private:
|
||||
template<class Archive> void serialize(Archive &ar) {
|
||||
ar(cereal::base_class<ObjectBase>(this));
|
||||
Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config);
|
||||
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, printable, origin_translation,
|
||||
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, sla_drain_holes, printable, origin_translation,
|
||||
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid);
|
||||
}
|
||||
};
|
||||
|
@ -80,6 +80,39 @@ struct SupportPoint
|
||||
|
||||
using SupportPoints = std::vector<SupportPoint>;
|
||||
|
||||
struct DrainHole
|
||||
{
|
||||
Vec3f m_pos;
|
||||
Vec3f m_normal;
|
||||
float m_radius;
|
||||
float m_height;
|
||||
|
||||
DrainHole()
|
||||
: m_pos(Vec3f::Zero()), m_normal(Vec3f::UnitZ()), m_radius(5.f),
|
||||
m_height(10.f)
|
||||
{}
|
||||
|
||||
DrainHole(Vec3f position, Vec3f normal, float radius, float height)
|
||||
: m_pos(position)
|
||||
, m_normal(normal)
|
||||
, m_radius(radius)
|
||||
, m_height(height)
|
||||
{}
|
||||
|
||||
bool operator==(const DrainHole &sp) const
|
||||
{
|
||||
return (m_pos == sp.m_pos) && (m_normal == sp.m_normal)
|
||||
&& is_approx(m_radius, sp.m_radius) && is_approx(m_height, sp.m_height);
|
||||
}
|
||||
|
||||
bool operator!=(const DrainHole &sp) const { return !(sp == (*this)); }
|
||||
|
||||
template<class Archive> void serialize(Archive &ar)
|
||||
{
|
||||
ar(m_pos, m_normal, m_radius, m_height);
|
||||
}
|
||||
};
|
||||
|
||||
struct Contour3D;
|
||||
|
||||
/// An index-triangle structure for libIGL functions. Also serves as an
|
||||
|
@ -52,6 +52,7 @@ bool GLGizmoHollow::on_init()
|
||||
m_desc["clipping_of_view"] = _(L("Clipping of view"))+ ": ";
|
||||
m_desc["reset_direction"] = _(L("Reset direction"));
|
||||
m_desc["hollow"] = _(L("Hollow"));
|
||||
m_desc["show_supports"] = _(L("Show supports"));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -243,13 +244,13 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
|
||||
glsafe(::glMultMatrixd(instance_matrix.data()));
|
||||
|
||||
float render_color[4];
|
||||
size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
|
||||
size_t cache_size = m_model_object->sla_drain_holes.size();
|
||||
for (size_t i = 0; i < cache_size; ++i)
|
||||
{
|
||||
const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i];
|
||||
const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false;
|
||||
const sla::DrainHole& drain_hole = m_model_object->sla_drain_holes[i];
|
||||
const bool& point_selected = m_selected[i];
|
||||
|
||||
if (is_mesh_point_clipped(support_point.pos.cast<double>()))
|
||||
if (is_mesh_point_clipped(drain_hole.m_pos.cast<double>()))
|
||||
continue;
|
||||
|
||||
// First decide about the color of the point.
|
||||
@ -262,7 +263,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
|
||||
}
|
||||
else {
|
||||
render_color[3] = 1.f;
|
||||
if ((size_t(m_hover_id) == i && m_editing_mode)) { // ignore hover state unless editing mode is active
|
||||
if (size_t(m_hover_id) == i) {
|
||||
render_color[0] = 0.f;
|
||||
render_color[1] = 1.0f;
|
||||
render_color[2] = 1.0f;
|
||||
@ -280,43 +281,34 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
|
||||
|
||||
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(support_point.pos(0), support_point.pos(1), support_point.pos(2)));
|
||||
glsafe(::glTranslatef(drain_hole.m_pos(0), drain_hole.m_pos(1), drain_hole.m_pos(2)));
|
||||
glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data()));
|
||||
|
||||
if (vol->is_left_handed())
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
// 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) {
|
||||
// in case the normal is not yet cached, find and cache it
|
||||
if (m_editing_cache[i].normal == Vec3f::Zero())
|
||||
m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
|
||||
|
||||
Eigen::Quaterniond q;
|
||||
q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
|
||||
q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * drain_hole.m_normal.cast<double>());
|
||||
Eigen::AngleAxisd aa(q);
|
||||
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
|
||||
|
||||
const double cone_radius = double(support_point.head_front_radius) * RenderPointScale; //0.25; // mm
|
||||
const double cone_height = m_new_cone_height;
|
||||
//const double cone_rad_diff = m_new_cone_angle*(cone_radius/(cone_height/2.))*(cone_height/2.);
|
||||
const double cone_rad_diff = m_new_cone_angle*cone_radius;
|
||||
const double cylinder_radius = double(drain_hole.m_radius) * RenderPointScale; //0.25; // mm
|
||||
const double stick_out_length = 1.;
|
||||
const double cone_height = m_new_hole_height + stick_out_length;
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(0., 0., -cone_height/2.));
|
||||
//::gluCylinder(m_quadric, cone_radius, cone_radius, cone_height, 24, 1);
|
||||
::gluCylinder(m_quadric, cone_radius+cone_rad_diff, cone_radius-cone_rad_diff, cone_height, 24, 1);
|
||||
glsafe(::glTranslated(0., 0., -cone_height+stick_out_length));
|
||||
::gluCylinder(m_quadric, cylinder_radius, cylinder_radius, cone_height, 24, 1);
|
||||
glsafe(::glTranslated(0., 0., cone_height));
|
||||
::gluDisk(m_quadric, 0.0, cone_radius-cone_rad_diff, 24, 1);
|
||||
::gluDisk(m_quadric, 0.0, cylinder_radius, 24, 1);
|
||||
glsafe(::glTranslated(0., 0., -cone_height));
|
||||
glsafe(::glRotatef(180.f, 1.f, 0.f, 0.f));
|
||||
::gluDisk(m_quadric, 0.0, cone_radius+cone_rad_diff, 24, 1);
|
||||
::gluDisk(m_quadric, 0.0, cylinder_radius, 24, 1);
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
//::gluSphere(m_quadric, (double)support_point.head_front_radius * RenderPointScale, 24, 12);
|
||||
|
||||
if (vol->is_left_handed())
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
@ -412,8 +404,6 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
|
||||
// concludes that the event was not intended for it, it should return false.
|
||||
bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
|
||||
{
|
||||
if (m_editing_mode) {
|
||||
|
||||
// left down with shift - show the selection rectangle:
|
||||
if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) {
|
||||
if (m_hover_id == -1) {
|
||||
@ -422,7 +412,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_editing_cache[m_hover_id].selected)
|
||||
if (m_selected[m_hover_id])
|
||||
unselect_point(m_hover_id);
|
||||
else {
|
||||
if (!alt_down)
|
||||
@ -444,7 +434,9 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add drainage hole")));
|
||||
m_editing_cache.emplace_back(sla::SupportPoint(pos_and_normal.first, m_new_point_head_diameter/2.f, false), false, pos_and_normal.second);
|
||||
m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first, pos_and_normal.second, m_new_hole_radius, m_new_hole_height);
|
||||
m_selected.push_back(false);
|
||||
assert(m_selected.size == m_model_object->sla_drain_holes.size());
|
||||
m_parent.set_as_dirty();
|
||||
m_wait_for_up_event = true;
|
||||
}
|
||||
@ -466,8 +458,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation();
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
|
||||
std::vector<Vec3d> points;
|
||||
for (unsigned int i=0; i<m_editing_cache.size(); ++i)
|
||||
points.push_back(trafo.get_matrix() * m_editing_cache[i].support_point.pos.cast<double>());
|
||||
for (unsigned int i=0; i<m_model_object->sla_drain_holes.size(); ++i)
|
||||
points.push_back(trafo.get_matrix() * m_model_object->sla_drain_holes[i].m_pos.cast<double>());
|
||||
|
||||
// Now ask the rectangle which of the points are inside.
|
||||
std::vector<Vec3f> points_inside;
|
||||
@ -528,7 +520,6 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
select_point(AllPoints);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
|
||||
m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f);
|
||||
@ -552,39 +543,26 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
|
||||
|
||||
void GLGizmoHollow::delete_selected_points(bool force)
|
||||
{
|
||||
if (! m_editing_mode) {
|
||||
std::cout << "DEBUGGING: delete_selected_points called out of editing mode!" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete drainage hole")));
|
||||
|
||||
for (unsigned int idx=0; idx<m_editing_cache.size(); ++idx) {
|
||||
if (m_editing_cache[idx].selected) {
|
||||
m_editing_cache.erase(m_editing_cache.begin() + (idx--));
|
||||
for (unsigned int idx=0; idx<m_model_object->sla_drain_holes.size(); ++idx) {
|
||||
if (m_selected[idx]) {
|
||||
m_selected.erase(m_selected.begin()+idx);
|
||||
m_model_object->sla_drain_holes.erase(m_model_object->sla_drain_holes.begin() + (idx--));
|
||||
}
|
||||
}
|
||||
|
||||
select_point(NoPoints);
|
||||
|
||||
//m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLGizmoHollow::on_update(const UpdateData& data)
|
||||
{
|
||||
if (! m_editing_mode)
|
||||
return;
|
||||
else {
|
||||
if (m_hover_id != -1) {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
m_editing_cache[m_hover_id].support_point.is_new_island = false;
|
||||
m_editing_cache[m_hover_id].normal = pos_and_normal.second;
|
||||
// Do not update immediately, wait until the mouse is released.
|
||||
// m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
m_model_object->sla_drain_holes[m_hover_id].m_pos = pos_and_normal.first;
|
||||
m_model_object->sla_drain_holes[m_hover_id].m_normal = pos_and_normal.second;
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,11 +645,6 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit)
|
||||
bool first_run = true; // This is a hack to redraw the button when all points are removed,
|
||||
// so it is not delayed until the background process finishes.
|
||||
RENDER_AGAIN:
|
||||
//m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
//const ImVec2 window_size(m_imgui->scaled(18.f, 16.f));
|
||||
//ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
|
||||
//ImGui::SetNextWindowSize(ImVec2(window_size));
|
||||
|
||||
const float approx_height = m_imgui->scaled(18.0f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
@ -679,7 +652,6 @@ RENDER_AGAIN:
|
||||
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
|
||||
|
||||
const float settings_sliders_left = std::max(m_imgui->calc_text_size(m_desc.at("minimal_distance")).x, m_imgui->calc_text_size(m_desc.at("points_density")).x) + m_imgui->scaled(1.f);
|
||||
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
|
||||
const float diameter_slider_left = m_imgui->calc_text_size(m_desc.at("head_diameter")).x + m_imgui->scaled(1.f);
|
||||
@ -690,19 +662,16 @@ RENDER_AGAIN:
|
||||
float window_width = minimal_slider_width + std::max(std::max(settings_sliders_left, clipping_slider_left), diameter_slider_left);
|
||||
window_width = std::max(std::max(window_width, buttons_width_approx), lock_supports_width_approx);
|
||||
|
||||
|
||||
bool force_refresh = false;
|
||||
bool remove_selected = false;
|
||||
bool remove_all = false;
|
||||
|
||||
if (m_editing_mode) {
|
||||
|
||||
if (m_imgui->button(m_desc.at("hollow")))
|
||||
hollow_mesh();
|
||||
|
||||
float diameter_upper_cap = static_cast<ConfigOptionFloat*>(wxGetApp().preset_bundle->sla_prints.get_edited_preset().config.option("support_pillar_diameter"))->value;
|
||||
if (m_new_point_head_diameter > diameter_upper_cap)
|
||||
m_new_point_head_diameter = diameter_upper_cap;
|
||||
float diameter_upper_cap = 20.f; //static_cast<ConfigOptionFloat*>(wxGetApp().preset_bundle->sla_prints.get_edited_preset().config.option("support_pillar_diameter"))->value;
|
||||
if (m_new_hole_radius > diameter_upper_cap)
|
||||
m_new_hole_radius = diameter_upper_cap;
|
||||
m_imgui->text(m_desc.at("head_diameter"));
|
||||
ImGui::SameLine(diameter_slider_left);
|
||||
ImGui::PushItemWidth(window_width - diameter_slider_left);
|
||||
@ -711,45 +680,42 @@ RENDER_AGAIN:
|
||||
// - save the initial value of the slider before one starts messing with it
|
||||
// - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene
|
||||
// - take correct undo/redo snapshot after the user is done with moving the slider
|
||||
float initial_value = m_new_point_head_diameter;
|
||||
ImGui::SliderFloat("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f");
|
||||
float initial_value = m_new_hole_radius;
|
||||
ImGui::SliderFloat("", &m_new_hole_radius, 0.1f, diameter_upper_cap, "%.1f");
|
||||
if (ImGui::IsItemClicked()) {
|
||||
if (m_old_point_head_diameter == 0.f)
|
||||
m_old_point_head_diameter = initial_value;
|
||||
if (m_old_hole_radius == 0.f)
|
||||
m_old_hole_radius = initial_value;
|
||||
}
|
||||
if (ImGui::IsItemEdited()) {
|
||||
for (auto& cache_entry : m_editing_cache)
|
||||
if (cache_entry.selected)
|
||||
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
|
||||
for (size_t idx=0; idx<m_selected.size(); ++idx)
|
||||
if (m_selected[idx])
|
||||
m_model_object->sla_drain_holes[idx].m_radius = m_new_hole_radius;
|
||||
}
|
||||
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||
// momentarily restore the old value to take snapshot
|
||||
for (auto& cache_entry : m_editing_cache)
|
||||
if (cache_entry.selected)
|
||||
cache_entry.support_point.head_front_radius = m_old_point_head_diameter / 2.f;
|
||||
float backup = m_new_point_head_diameter;
|
||||
m_new_point_head_diameter = m_old_point_head_diameter;
|
||||
for (size_t idx=0; idx<m_selected.size(); ++idx)
|
||||
if (m_selected[idx])
|
||||
m_model_object->sla_drain_holes[idx].m_radius = m_old_hole_radius;
|
||||
float backup = m_new_hole_radius;
|
||||
m_new_hole_radius = m_old_hole_radius;
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Change drainage hole diameter")));
|
||||
m_new_point_head_diameter = backup;
|
||||
for (auto& cache_entry : m_editing_cache)
|
||||
if (cache_entry.selected)
|
||||
cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f;
|
||||
m_old_point_head_diameter = 0.f;
|
||||
m_new_hole_radius = backup;
|
||||
for (size_t idx=0; idx<m_selected.size(); ++idx)
|
||||
if (m_selected[idx])
|
||||
m_model_object->sla_drain_holes[idx].m_radius = m_new_hole_radius;
|
||||
m_old_hole_radius = 0.f;
|
||||
}
|
||||
|
||||
// !!!! Something as above should be done for the cone angle
|
||||
m_imgui->text("Hole taper: ");
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat(" ", &m_new_cone_angle, -1.f, 1.f, "%.1f");
|
||||
// !!!! Something as above should be done for the undo/redo
|
||||
m_imgui->text("Hole height: ");
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat(" ", &m_new_cone_height, 0.1f, 10.f, "%.1f");
|
||||
ImGui::SliderFloat(" ", &m_new_hole_height, 0.1f, 10.f, "%.1f");
|
||||
|
||||
m_imgui->disabled_begin(m_selection_empty);
|
||||
remove_selected = m_imgui->button(m_desc.at("remove_selected"));
|
||||
m_imgui->disabled_end();
|
||||
|
||||
m_imgui->disabled_begin(m_editing_cache.empty());
|
||||
m_imgui->disabled_begin(m_model_object->sla_drain_holes.empty());
|
||||
remove_all = m_imgui->button(m_desc.at("remove_all"));
|
||||
m_imgui->disabled_end();
|
||||
|
||||
@ -762,53 +728,6 @@ RENDER_AGAIN:
|
||||
m_imgui->text("Adaptibility: ");
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat(" ", &m_adaptability, 0.f, 1.f, "%.1f");
|
||||
}
|
||||
else { // not in editing mode:
|
||||
m_imgui->text(m_desc.at("minimal_distance"));
|
||||
ImGui::SameLine(settings_sliders_left);
|
||||
ImGui::PushItemWidth(window_width - settings_sliders_left);
|
||||
|
||||
std::vector<const ConfigOption*> opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"});
|
||||
float density = static_cast<const ConfigOptionInt*>(opts[0])->value;
|
||||
float minimal_point_distance = static_cast<const ConfigOptionFloat*>(opts[1])->value;
|
||||
|
||||
ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm");
|
||||
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
|
||||
bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider
|
||||
bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider
|
||||
|
||||
m_imgui->text(m_desc.at("points_density"));
|
||||
ImGui::SameLine(settings_sliders_left);
|
||||
|
||||
ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%");
|
||||
slider_clicked |= ImGui::IsItemClicked();
|
||||
slider_edited |= ImGui::IsItemEdited();
|
||||
slider_released |= ImGui::IsItemDeactivatedAfterEdit();
|
||||
|
||||
if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo
|
||||
m_minimal_point_distance_stash = minimal_point_distance;
|
||||
m_density_stash = density;
|
||||
}
|
||||
if (slider_edited) {
|
||||
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
|
||||
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
|
||||
}
|
||||
if (slider_released) {
|
||||
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = m_minimal_point_distance_stash;
|
||||
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)m_density_stash;
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Support parameter change")));
|
||||
m_model_object->config.opt<ConfigOptionFloat>("support_points_minimal_distance", true)->value = minimal_point_distance;
|
||||
m_model_object->config.opt<ConfigOptionInt>("support_points_density_relative", true)->value = (int)density;
|
||||
wxGetApp().obj_list()->update_and_show_object_settings_item();
|
||||
}
|
||||
|
||||
|
||||
m_imgui->disabled_begin(m_normal_cache.empty());
|
||||
remove_all = m_imgui->button(m_desc.at("remove_all"));
|
||||
m_imgui->disabled_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Following is rendered in both editing and non-editing mode:
|
||||
m_imgui->text("");
|
||||
@ -827,7 +746,6 @@ RENDER_AGAIN:
|
||||
if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
|
||||
update_clipping_plane(true);
|
||||
|
||||
|
||||
if (m_imgui->button("?")) {
|
||||
wxGetApp().CallAfter([]() {
|
||||
SlaGizmoHelpDialog help_dlg;
|
||||
@ -835,18 +753,18 @@ RENDER_AGAIN:
|
||||
});
|
||||
}
|
||||
|
||||
m_imgui->end();
|
||||
|
||||
if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
|
||||
m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode, m_model_object, m_active_instance);
|
||||
if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) {
|
||||
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_model_object, m_active_instance);
|
||||
force_refresh = true;
|
||||
}
|
||||
m_old_editing_state = m_editing_mode;
|
||||
|
||||
m_imgui->end();
|
||||
|
||||
|
||||
if (remove_selected || remove_all) {
|
||||
force_refresh = false;
|
||||
m_parent.set_as_dirty();
|
||||
bool was_in_editing = m_editing_mode;
|
||||
|
||||
if (remove_all) {
|
||||
select_point(AllPoints);
|
||||
delete_selected_points(true); // true - delete regardless of locked status
|
||||
@ -927,12 +845,11 @@ void GLGizmoHollow::on_set_state()
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
m_new_hole_radius = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
}
|
||||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
m_normal_cache.clear();
|
||||
m_clipping_plane_distance = 0.f;
|
||||
// Release clippers and the AABB raycaster.
|
||||
m_object_clipper.reset();
|
||||
@ -951,27 +868,27 @@ void GLGizmoHollow::on_start_dragging()
|
||||
if (m_hover_id != -1) {
|
||||
select_point(NoPoints);
|
||||
select_point(m_hover_id);
|
||||
m_point_before_drag = m_editing_cache[m_hover_id];
|
||||
m_hole_before_drag = m_model_object->sla_drain_holes[m_hover_id].m_pos;
|
||||
}
|
||||
else
|
||||
m_point_before_drag = CacheEntry();
|
||||
m_hole_before_drag = Vec3f::Zero();
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::on_stop_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
CacheEntry backup = m_editing_cache[m_hover_id];
|
||||
Vec3f backup = m_model_object->sla_drain_holes[m_hover_id].m_pos;
|
||||
|
||||
if (m_point_before_drag.support_point.pos != Vec3f::Zero() // some point was touched
|
||||
&& backup.support_point.pos != m_point_before_drag.support_point.pos) // and it was moved, not just selected
|
||||
if (m_hole_before_drag != Vec3f::Zero() // some point was touched
|
||||
&& backup != m_hole_before_drag) // and it was moved, not just selected
|
||||
{
|
||||
m_editing_cache[m_hover_id] = m_point_before_drag;
|
||||
m_model_object->sla_drain_holes[m_hover_id].m_pos = m_hole_before_drag;
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Move drainage hole")));
|
||||
m_editing_cache[m_hover_id] = backup;
|
||||
m_model_object->sla_drain_holes[m_hover_id].m_pos = backup;
|
||||
}
|
||||
}
|
||||
m_point_before_drag = CacheEntry();
|
||||
m_hole_before_drag = Vec3f::Zero();
|
||||
}
|
||||
|
||||
|
||||
@ -981,9 +898,8 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
|
||||
ar(m_clipping_plane_distance,
|
||||
*m_clipping_plane,
|
||||
m_model_object_id,
|
||||
m_new_point_head_diameter,
|
||||
m_normal_cache,
|
||||
m_editing_cache,
|
||||
m_new_hole_radius,
|
||||
m_selected,
|
||||
m_selection_empty
|
||||
);
|
||||
}
|
||||
@ -995,9 +911,8 @@ void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const
|
||||
ar(m_clipping_plane_distance,
|
||||
*m_clipping_plane,
|
||||
m_model_object_id,
|
||||
m_new_point_head_diameter,
|
||||
m_normal_cache,
|
||||
m_editing_cache,
|
||||
m_new_hole_radius,
|
||||
m_selected,
|
||||
m_selection_empty
|
||||
);
|
||||
}
|
||||
@ -1006,63 +921,41 @@ void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const
|
||||
|
||||
void GLGizmoHollow::select_point(int i)
|
||||
{
|
||||
if (! m_editing_mode) {
|
||||
std::cout << "DEBUGGING: select_point called when out of editing mode!" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (i == AllPoints || i == NoPoints) {
|
||||
for (auto& point_and_selection : m_editing_cache)
|
||||
point_and_selection.selected = ( i == AllPoints );
|
||||
m_selected.assign(m_selected.size(), i == AllPoints);
|
||||
m_selection_empty = (i == NoPoints);
|
||||
|
||||
if (i == AllPoints)
|
||||
m_new_point_head_diameter = m_editing_cache[0].support_point.head_front_radius * 2.f;
|
||||
m_new_hole_radius = m_model_object->sla_drain_holes[0].m_radius;
|
||||
}
|
||||
else {
|
||||
m_editing_cache[i].selected = true;
|
||||
while (size_t(i) >= m_selected.size())
|
||||
m_selected.push_back(false);
|
||||
m_selected[i] = true;
|
||||
m_selection_empty = false;
|
||||
m_new_point_head_diameter = m_editing_cache[i].support_point.head_front_radius * 2.f;
|
||||
m_new_hole_radius = m_model_object->sla_drain_holes[i].m_radius;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::unselect_point(int i)
|
||||
{
|
||||
if (! m_editing_mode) {
|
||||
std::cout << "DEBUGGING: unselect_point called when out of editing mode!" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
m_editing_cache[i].selected = false;
|
||||
m_selected[i] = false;
|
||||
m_selection_empty = true;
|
||||
for (const CacheEntry& ce : m_editing_cache) {
|
||||
if (ce.selected) {
|
||||
for (const bool sel : m_selected) {
|
||||
if (sel) {
|
||||
m_selection_empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GLGizmoHollow::unsaved_changes() const
|
||||
{
|
||||
if (m_editing_cache.size() != m_normal_cache.size())
|
||||
return true;
|
||||
|
||||
for (size_t i=0; i<m_editing_cache.size(); ++i)
|
||||
if (m_editing_cache[i].support_point != m_normal_cache[i])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoHollow::reload_cache()
|
||||
{
|
||||
|
||||
m_selected.clear();
|
||||
m_selected.assign(m_model_object->sla_drain_holes.size(), false);
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
|
||||
{
|
||||
Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
|
||||
|
@ -25,7 +25,7 @@ private:
|
||||
ObjectID m_model_object_id = 0;
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
mutable double m_z_shift = 0.f;
|
||||
mutable double m_z_shift = 0.;
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||
|
||||
const float RenderPointScale = 1.f;
|
||||
@ -46,27 +46,26 @@ private:
|
||||
class CacheEntry {
|
||||
public:
|
||||
CacheEntry() :
|
||||
support_point(sla::SupportPoint()), selected(false), normal(Vec3f::Zero()) {}
|
||||
drain_hole(sla::DrainHole()), selected(false) {}
|
||||
|
||||
CacheEntry(const sla::SupportPoint& point, bool sel = false, const Vec3f& norm = Vec3f::Zero()) :
|
||||
support_point(point), selected(sel), normal(norm) {}
|
||||
CacheEntry(const sla::DrainHole& point, bool sel = false) :
|
||||
drain_hole(point), selected(sel) {}
|
||||
|
||||
bool operator==(const CacheEntry& rhs) const {
|
||||
return (support_point == rhs.support_point);
|
||||
return (drain_hole == rhs.drain_hole);
|
||||
}
|
||||
|
||||
bool operator!=(const CacheEntry& rhs) const {
|
||||
return ! ((*this) == rhs);
|
||||
}
|
||||
|
||||
sla::SupportPoint support_point;
|
||||
sla::DrainHole drain_hole;
|
||||
bool selected; // whether the point is selected
|
||||
Vec3f normal;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(support_point, selected, normal);
|
||||
ar(drain_hole, selected);
|
||||
}
|
||||
};
|
||||
|
||||
@ -97,17 +96,14 @@ private:
|
||||
bool unsaved_changes() const;
|
||||
const TriangleMesh* mesh() const;
|
||||
|
||||
bool m_editing_mode = true; // Is editing mode active?
|
||||
bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
|
||||
float m_new_point_head_diameter; // Size of a new point.
|
||||
float m_new_cone_angle = 0.f;
|
||||
float m_new_cone_height = 5.f;
|
||||
CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited
|
||||
float m_old_point_head_diameter = 0.; // the same
|
||||
bool m_show_supports = true;
|
||||
float m_new_hole_radius; // Size of a new hole.
|
||||
float m_new_hole_height = 5.f;
|
||||
float m_old_hole_radius = 0.; // undo/redo - so we know what state was edited
|
||||
Vec3f m_hole_before_drag = Vec3f::Zero();
|
||||
float m_minimal_point_distance_stash = 0.f; // and again
|
||||
float m_density_stash = 0.f; // and again
|
||||
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
|
||||
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
|
||||
mutable std::vector<bool> m_selected; // which holes are currently selected
|
||||
|
||||
float m_offset = 2.f;
|
||||
float m_adaptability = 1.f;
|
||||
@ -148,7 +144,7 @@ protected:
|
||||
void on_set_hover_id() override
|
||||
|
||||
{
|
||||
if (! m_editing_mode || (int)m_editing_cache.size() <= m_hover_id)
|
||||
if (int(m_model_object->sla_drain_holes.size()) <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_start_dragging() override;
|
||||
|
@ -750,20 +750,31 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
||||
|
||||
if (evt.GetEventType() == wxEVT_KEY_UP)
|
||||
{
|
||||
if (m_current == SlaSupports)
|
||||
if (m_current == SlaSupports || m_current == Hollow)
|
||||
{
|
||||
bool is_editing = true;
|
||||
bool is_rectangle_dragging = false;
|
||||
|
||||
if (m_current == SlaSupports) {
|
||||
GLGizmoSlaSupports* gizmo = dynamic_cast<GLGizmoSlaSupports*>(get_current());
|
||||
is_editing = gizmo->is_in_editing_mode();
|
||||
is_rectangle_dragging = gizmo->is_selection_rectangle_dragging();
|
||||
}
|
||||
else {
|
||||
GLGizmoHollow* gizmo = dynamic_cast<GLGizmoHollow*>(get_current());
|
||||
is_rectangle_dragging = gizmo->is_selection_rectangle_dragging();
|
||||
}
|
||||
|
||||
if (keyCode == WXK_SHIFT)
|
||||
{
|
||||
// shift has been just released - SLA gizmo might want to close rectangular selection.
|
||||
if (gizmo_event(SLAGizmoEventType::ShiftUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging()))
|
||||
if (gizmo_event(SLAGizmoEventType::ShiftUp) || (is_editing && is_rectangle_dragging))
|
||||
processed = true;
|
||||
}
|
||||
else if (keyCode == WXK_ALT)
|
||||
{
|
||||
// alt has been just released - SLA gizmo might want to close rectangular selection.
|
||||
if (gizmo_event(SLAGizmoEventType::AltUp) || (gizmo->is_in_editing_mode() && gizmo->is_selection_rectangle_dragging()))
|
||||
if (gizmo_event(SLAGizmoEventType::AltUp) || (is_editing && is_rectangle_dragging))
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user