ENH:paint along line function auto enter front view perspective

Jira: STUDIO-5678
Change-Id: Ie93e8080fd4f45a8e21ff79a0248d85821797a83
This commit is contained in:
zhou.xu 2024-01-02 17:30:46 +08:00 committed by Lane.Wei
parent 044919252b
commit 1f75cd846f
8 changed files with 163 additions and 26 deletions

View File

@ -139,7 +139,7 @@ public:
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
bool is_looking_front() const { return abs(get_dir_up().dot(Vec3d::UnitZ())-1) < 0.001; }
// forces camera right vector to be parallel to XY plane
void recover_from_free_camera() {
if (std::abs(get_dir_right()(2)) > EPSILON)

View File

@ -334,11 +334,6 @@ private:
bool render_combo(const std::string &label, const std::vector<std::string> &lines, size_t &selection_idx, float label_width, float item_width);
bool render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in);
enum DoubleShowType {
Normal, // origin data
PERCENTAGE,
DEGREE,
};
bool render_slider_double_input_by_format(const std::string &label, float &value_in, float value_min, float value_max, DoubleShowType show_type = DoubleShowType::Normal);
bool cut_line_processing() const;
void discard_cut_line_processing();

View File

@ -145,7 +145,52 @@ void GLGizmoBase::Grabber::render(float size, const std::array<float, 4>& render
}
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
bool GLGizmoBase::render_slider_double_input_by_format(
const SliderInputLayout &layout, const std::string &label, float &value_in, float value_min, float value_max, int keep_digit, DoubleShowType show_type)
{
ImGui::AlignTextToFramePadding();
m_imgui->text(label);
ImGui::SameLine(layout.sliders_left_width);
ImGui::PushItemWidth(layout.sliders_width);
float old_val = value_in; // (show_type == DoubleShowType::Normal)
float value = value_in; // (show_type == DoubleShowType::Normal)
std::string format = "%." + std::to_string(keep_digit) + "f";
if (show_type == DoubleShowType::PERCENTAGE) {
format = "%." + std::to_string(keep_digit) + "f %%";
old_val = value_in;
value = value_in * 100;
} else if (show_type == DoubleShowType::DEGREE) {
format = "%." + std::to_string(keep_digit) + "f " + _u8L("°");
old_val = value_in;
value = Geometry::rad2deg(value_in);
}
if (m_imgui->bbl_slider_float_style(("##" + label).c_str(), &value, value_min, value_max, format.c_str())) {
if (show_type == DoubleShowType::PERCENTAGE) {
value_in = value * 0.01f;
} else if (show_type == DoubleShowType::DEGREE) {
value_in = Geometry::deg2rad(value);
} else { //(show_type == DoubleShowType::Normal)
value_in = value;
}
}
ImGui::SameLine(layout.input_left_width);
ImGui::PushItemWidth(layout.input_width);
if (ImGui::BBLDragFloat(("##input_" + label).c_str(), &value, 0.05f, value_min, value_max, format.c_str())) {
if (show_type == DoubleShowType::PERCENTAGE) {
value_in = value * 0.01f;
} else if (show_type == DoubleShowType::DEGREE) {
value_in = Geometry::deg2rad(value);
} else { //(show_type == DoubleShowType::Normal)
value_in = value;
}
}
return !is_approx(old_val, value_in);
}
GLGizmoBase::GLGizmoBase(GLCanvas3D &parent, const std::string &icon_filename, unsigned int sprite_id)
: m_parent(parent)
, m_group_id(-1)
, m_state(Off)

View File

@ -129,6 +129,25 @@ protected:
bool m_is_dark_mode = false;
std::chrono::system_clock::time_point start;
enum DoubleShowType {
Normal, // origin data
PERCENTAGE,
DEGREE,//input must is radian
};
struct SliderInputLayout
{
float sliders_left_width;
float sliders_width;
float input_left_width;
float input_width;
};
bool render_slider_double_input_by_format(const SliderInputLayout & layout,
const std::string & label,
float & value_in,
float value_min,
float value_max,
int keep_digit ,
DoubleShowType show_type = DoubleShowType::Normal);
public:
GLGizmoBase(GLCanvas3D& parent,

View File

@ -393,8 +393,11 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
// 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 space_size = m_imgui->get_style_scaling() * 8;
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f),
float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x + m_imgui->scaled(1.5f),
m_imgui->calc_text_size(m_desc.at("reset_direction")).x + m_imgui->scaled(1.5f) + ImGui::GetStyle().FramePadding.x * 2);
float rotate_horizontal_text= m_imgui->calc_text_size(_L("Rotate horizontally")).x + m_imgui->scaled(1.5f);
clipping_slider_left = std::max(rotate_horizontal_text, clipping_slider_left);
const float cursor_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.5f);
const float smart_fill_slider_left = m_imgui->calc_text_size(m_desc.at("smart_fill_angle")).x + m_imgui->scaled(1.5f);
const float edge_detect_slider_left = m_imgui->calc_text_size(m_desc.at("edge_detection")).x + m_imgui->scaled(1.f);
@ -442,6 +445,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
float color_button = ImGui::GetCursorPos().y;
float textbox_width = 1.5 * slider_icon_width;
SliderInputLayout slider_input_layout = {clipping_slider_left, sliders_width, drag_left_width + circle_max_width, textbox_width};
m_imgui->text(m_desc.at("filaments"));
float start_pos_x = ImGui::GetCursorPos().x;
@ -712,17 +718,49 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::BBLDragFloat("##gap_area_input", &TriangleSelectorPatch::gap_area, 0.05f, 0.0f, 0.0f, "%.2f");
}
ImGui::Separator();
if (m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only)) {
if (m_vertical_only) {
m_horizontal_only = false;
if (m_current_tool == ImGui::CircleButtonIcon || m_current_tool == ImGui::SphereButtonIcon) {
float vertical_text_width = m_imgui->calc_button_size(_L("Vertical")).x;
float horizontal_text_width = m_imgui->calc_button_size(_L("Horizontal")).x;
if (!wxGetApp().plater()->get_camera().is_looking_front()) {
m_is_front_view = false;
}
}
if (m_imgui->bbl_checkbox(_L("Horizontal"), m_horizontal_only)) {
if (m_horizontal_only) {
m_vertical_only = false;
auto vertical_only = m_vertical_only;
if (m_imgui->bbl_checkbox(_L("Vertical"), vertical_only)) {
m_vertical_only = vertical_only;
if (m_vertical_only) {
m_horizontal_only = false;
m_is_front_view = true;
change_camera_view_angle(m_front_view_radian);
}
}
}
ImGui::SameLine(vertical_text_width * 2.0);
ImGui::PushItemWidth(horizontal_text_width * 2.0);
auto horizontal_only = m_horizontal_only;
if (m_imgui->bbl_checkbox(_L("Horizontal"), horizontal_only)) {
m_horizontal_only = horizontal_only;
if (m_horizontal_only) {
m_vertical_only = false;
m_is_front_view = true;
change_camera_view_angle(m_front_view_radian);
}
}
auto is_front_view = m_is_front_view;
m_imgui->bbl_checkbox(_L("View: keep horizontal"), is_front_view);
if (m_is_front_view != is_front_view) {
m_is_front_view = is_front_view;
if (m_is_front_view) {
change_camera_view_angle(m_front_view_radian);
}
}
m_imgui->disabled_begin(!m_is_front_view);
if (render_slider_double_input_by_format(slider_input_layout, _u8L("Rotate horizontally"), m_front_view_radian, 0.f, 360.f, 0, DoubleShowType::DEGREE)) {
change_camera_view_angle(m_front_view_radian);
}
m_imgui->disabled_end();
}
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;

View File

@ -28,8 +28,6 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic
// Make sphere and save it into a vertex buffer.
m_vbo_sphere.load_its_flat_shading(its_make_sphere(1., (2*M_PI)/24.));
m_vbo_sphere.finalize_geometry(true);
m_vertical_only = false;
m_horizontal_only = false;
}
void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection)
@ -1094,6 +1092,10 @@ void GLGizmoPainterBase::on_set_state()
//camera.recover_from_free_camera();
}
m_old_state = m_state;
m_vertical_only = false;
m_horizontal_only = false;
m_is_front_view = false;
m_front_view_radian = 0;
}
@ -1127,6 +1129,14 @@ TriangleSelector::ClippingPlane GLGizmoPainterBase::get_clipping_plane_in_volume
return TriangleSelector::ClippingPlane({float(normal_transformed.x()), float(normal_transformed.y()), float(normal_transformed.z()), offset_transformed});
}
void GLGizmoPainterBase::change_camera_view_angle(float front_view_radian)
{
wxGetApp().plater()->get_camera().select_view("front");
const Selection &selection = m_parent.get_selection();
auto rotate_target = selection.get_bounding_box().center();
wxGetApp().plater()->get_camera().rotate_local_with_target(Vec3d(0, front_view_radian, 0), rotate_target);
}
std::array<float, 4> TriangleSelectorGUI::get_seed_fill_color(const std::array<float, 4> &base_color)
{
// BBS

View File

@ -305,9 +305,10 @@ protected:
static constexpr float SmartFillAngleStep = 1.f;
// BBL: paint behavior enchancement
bool m_vertical_only = false;
bool m_horizontal_only = false;
bool m_vertical_only = false;
bool m_horizontal_only = false;
bool m_is_front_view = false;
float m_front_view_radian = 0;
// It stores the value of the previous mesh_id to which the seed fill was applied.
// It is used to detect when the mouse has moved from one volume to another one.
int m_seed_fill_last_mesh_id = -1;
@ -328,7 +329,8 @@ protected:
TriangleSelector::ClippingPlane get_clipping_plane_in_volume_coordinates(const Transform3d &trafo) const;
private:
void change_camera_view_angle(float front_view_radian);
private:
std::vector<std::vector<ProjectedMousePosition>> get_projected_mouse_positions(const Vec2d &mouse_position, double resolution, const std::vector<Transform3d> &trafo_matrices) const;
std::vector<ProjectedHeightRange> get_projected_height_range(const Vec2d& mouse_position, double resolution, const std::vector<const ModelVolume*>& part_volumes, const std::vector<Transform3d>& trafo_matrices) const;

View File

@ -201,9 +201,11 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
// 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 space_size = m_imgui->get_style_scaling() * 8;
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 + ImGui::GetStyle().FramePadding.x * 2)
+ m_imgui->scaled(1.5f);
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 + ImGui::GetStyle().FramePadding.x * 2) +
m_imgui->scaled(1.5f);
float rotate_horizontal_text = m_imgui->calc_text_size(_L("Rotate horizontally")).x + m_imgui->scaled(1.5f);
clipping_slider_left = std::max(rotate_horizontal_text, clipping_slider_left);
const float cursor_size_slider_left = m_imgui->calc_text_size(m_desc.at("cursor_size")).x + m_imgui->scaled(1.f);
const float empty_button_width = m_imgui->calc_button_size("").x;
@ -222,6 +224,9 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
float textbox_width = 1.5 * slider_icon_width;
SliderInputLayout slider_input_layout = {sliders_left_width, sliders_width, drag_left_width, textbox_width};
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("cursor_type"));
std::array<wchar_t, 2> tool_ids = { ImGui::CircleButtonIcon, ImGui::SphereButtonIcon };
@ -313,8 +318,31 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
ImGui::Separator();
m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only);
if (!wxGetApp().plater()->get_camera().is_looking_front()){
m_is_front_view = false;
}
auto vertical_only = m_vertical_only;
if (m_imgui->bbl_checkbox(_L("Vertical"), vertical_only)) {
m_vertical_only = vertical_only;
if (m_vertical_only) {
m_is_front_view = true;
change_camera_view_angle(m_front_view_radian);
}
}
auto is_front_view = m_is_front_view;
m_imgui->bbl_checkbox(_L("View: keep horizontal"), is_front_view);
if (m_is_front_view != is_front_view) {
m_is_front_view = is_front_view;
if (m_is_front_view) {
change_camera_view_angle(m_front_view_radian);
}
}
m_imgui->disabled_begin(!m_is_front_view);
if (render_slider_double_input_by_format(slider_input_layout, _u8L("Rotate horizontally"), m_front_view_radian, 0.f, 360.f, 0, DoubleShowType::DEGREE)) {
change_camera_view_angle(m_front_view_radian);
}
m_imgui->disabled_end();
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;