From 48a8e33ec3a179ded1c3f3ed25f984c093320874 Mon Sep 17 00:00:00 2001 From: HanifKoh <76276251+HanifKoh@users.noreply.github.com> Date: Mon, 5 Oct 2026 14:26:15 +0800 Subject: [PATCH] Delete Gizmo, SLA and Utils Files Nothing Builds or Includes (#16101) GLGizmoSlaSupports, GLGizmoHollow, GLGizmoFaceDetector, GLGizmoText and GLGizmoAdvancedCut were already left out of the build, and GLGizmos.hpp, the only header including some of them, had no includers. VoxelizeCSGMesh.hpp uses types that no longer exist, SLA/bicubic.h does not compile, and Utils/ProfileDescription.hpp is included nowhere. Their CMake and gettext source-list entries go with them. --- localization/i18n/list.txt | 4 - src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp | 116 - src/libslic3r/SLA/bicubic.h | 186 -- src/slic3r/CMakeLists.txt | 9 - src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp | 2015 ----------------- src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp | 222 -- src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp | 133 -- src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp | 39 - src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp | 872 ------- src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp | 111 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 1236 ---------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 159 -- src/slic3r/GUI/Gizmos/GLGizmoText.cpp | 1680 -------------- src/slic3r/GUI/Gizmos/GLGizmoText.hpp | 126 -- src/slic3r/GUI/Gizmos/GLGizmos.hpp | 41 - src/slic3r/Utils/ProfileDescription.hpp | 60 - 16 files changed, 7009 deletions(-) delete mode 100644 src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp delete mode 100644 src/libslic3r/SLA/bicubic.h delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoText.cpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmoText.hpp delete mode 100644 src/slic3r/GUI/Gizmos/GLGizmos.hpp delete mode 100644 src/slic3r/Utils/ProfileDescription.hpp diff --git a/localization/i18n/list.txt b/localization/i18n/list.txt index 4d5ab72073..a083449903 100644 --- a/localization/i18n/list.txt +++ b/localization/i18n/list.txt @@ -74,11 +74,8 @@ src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp src/slic3r/GUI/Gizmos/GLGizmoCut.cpp src/slic3r/GUI/Gizmos/GLGizmoCut.hpp src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp -src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp -src/slic3r/GUI/Gizmos/GLGizmoText.cpp -src/slic3r/GUI/Gizmos/GLGizmoText.hpp src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -257,7 +254,6 @@ src/slic3r/Utils/MKS.cpp src/slic3r/Utils/Moonraker.cpp src/slic3r/Utils/OctoPrint.cpp src/slic3r/Utils/Repetier.cpp -src/slic3r/Utils/ProfileDescription.hpp src/slic3r/GUI/SendMultiMachinePage.cpp src/slic3r/GUI/MultiMachinePage.cpp src/slic3r/GUI/MultiMachineManagerPage.cpp diff --git a/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp b/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp deleted file mode 100644 index f64d17b9a4..0000000000 --- a/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef VOXELIZECSGMESH_HPP -#define VOXELIZECSGMESH_HPP - -#include -#include - -#include "CSGMesh.hpp" -#include "libslic3r/OpenVDBUtils.hpp" -#include "libslic3r/Execution/ExecutionTBB.hpp" - -namespace Slic3r { namespace csg { - -using VoxelizeParams = MeshToGridParams; - -// This method can be overriden when a specific CSGPart type supports caching -// of the voxel grid -template -VoxelGridPtr get_voxelgrid(const CSGPartT &csgpart, VoxelizeParams params) -{ - const indexed_triangle_set *its = csg::get_mesh(csgpart); - VoxelGridPtr ret; - - params.trafo(params.trafo() * csg::get_transform(csgpart)); - - if (its) - ret = mesh_to_grid(*its, params); - - return ret; -} - -namespace detail { - -inline void perform_csg(CSGType op, VoxelGridPtr &dst, VoxelGridPtr &src) -{ - if (!dst || !src) - return; - - switch (op) { - case CSGType::Union: - if (is_grid_empty(*dst) && !is_grid_empty(*src)) - dst = clone(*src); - else - grid_union(*dst, *src); - - break; - case CSGType::Difference: - grid_difference(*dst, *src); - break; - case CSGType::Intersection: - grid_intersection(*dst, *src); - break; - } -} - -} // namespace detail - -template -VoxelGridPtr voxelize_csgmesh(const Range &csgrange, - const VoxelizeParams ¶ms = {}) -{ - using namespace detail; - - VoxelGridPtr ret; - - std::vector grids (csgrange.size()); - - execution::for_each(ex_tbb, size_t(0), csgrange.size(), [&](size_t csgidx) { - if (params.statusfn() && params.statusfn()(-1)) - return; - - auto it = csgrange.begin(); - std::advance(it, csgidx); - auto &csgpart = *it; - grids[csgidx] = get_voxelgrid(csgpart, params); - }, execution::max_concurrency(ex_tbb)); - - size_t csgidx = 0; - struct Frame { CSGType op = CSGType::Union; VoxelGridPtr grid; }; - std::stack opstack{std::vector{}}; - - opstack.push({CSGType::Union, mesh_to_grid({}, params)}); - - for (auto &csgpart : csgrange) { - if (params.statusfn() && params.statusfn()(-1)) - break; - - auto &partgrid = grids[csgidx++]; - - auto op = get_operation(csgpart); - - if (get_stack_operation(csgpart) == CSGStackOp::Push) { - opstack.push({op, mesh_to_grid({}, params)}); - op = CSGType::Union; - } - - Frame *top = &opstack.top(); - - perform_csg(get_operation(csgpart), top->grid, partgrid); - - if (get_stack_operation(csgpart) == CSGStackOp::Pop) { - VoxelGridPtr popgrid = std::move(top->grid); - auto popop = opstack.top().op; - opstack.pop(); - VoxelGridPtr &grid = opstack.top().grid; - perform_csg(popop, grid, popgrid); - } - } - - ret = std::move(opstack.top().grid); - - return ret; -} - -}} // namespace Slic3r::csg - -#endif // VOXELIZECSGMESH_HPP diff --git a/src/libslic3r/SLA/bicubic.h b/src/libslic3r/SLA/bicubic.h deleted file mode 100644 index 870d00dbd6..0000000000 --- a/src/libslic3r/SLA/bicubic.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef BICUBIC_HPP -#define BICUBIC_HPP - -#include -#include -#include - -#include - -namespace Slic3r { - -namespace BicubicInternal { - // Linear kernel, to be able to test cubic methods with hat kernels. - template - struct LinearKernel - { - typedef T FloatType; - - static T a00() { return T(0.); } - static T a01() { return T(0.); } - static T a02() { return T(0.); } - static T a03() { return T(0.); } - static T a10() { return T(1.); } - static T a11() { return T(-1.); } - static T a12() { return T(0.); } - static T a13() { return T(0.); } - static T a20() { return T(0.); } - static T a21() { return T(1.); } - static T a22() { return T(0.); } - static T a23() { return T(0.); } - static T a30() { return T(0.); } - static T a31() { return T(0.); } - static T a32() { return T(0.); } - static T a33() { return T(0.); } - }; - - // Interpolation kernel aka Catmul-Rom aka Keyes kernel. - template - struct CubicCatmulRomKernel - { - typedef T FloatType; - - static T a00() { return 0; } - static T a01() { return (T)-0.5; } - static T a02() { return (T) 1.; } - static T a03() { return (T)-0.5; } - static T a10() { return (T) 1.; } - static T a11() { return 0; } - static T a12() { return (T)-5./2.; } - static T a13() { return (T) 3./2.; } - static T a20() { return 0; } - static T a21() { return (T) 0.5; } - static T a22() { return (T) 2.; } - static T a23() { return (T)-3./2.; } - static T a30() { return 0; } - static T a31() { return 0; } - static T a32() { return (T)-0.5; } - static T a33() { return (T) 0.5; } - }; - - // B-spline kernel - template - struct CubicBSplineKernel - { - typedef T FloatType; - - static T a00() { return (T) 1./6.; } - static T a01() { return (T) -3./6.; } - static T a02() { return (T) 3./6.; } - static T a03() { return (T) -1./6.; } - static T a10() { return (T) 4./6.; } - static T a11() { return 0; } - static T a12() { return (T) -6./6.; } - static T a13() { return (T) 3./6.; } - static T a20() { return (T) 1./6.; } - static T a21() { return (T) 3./6.; } - static T a22() { return (T) 3./6.; } - static T a23() { return (T)- 3./6.; } - static T a30() { return 0; } - static T a31() { return 0; } - static T a32() { return 0; } - static T a33() { return (T) 1./6.; } - }; - - template - inline T clamp(T a, T lower, T upper) - { - return (a < lower) ? lower : - (a > upper) ? upper : a; - } -} - -template -struct CubicKernel -{ - typedef typename KERNEL KernelInternal; - typedef typename KERNEL::FloatType FloatType; - - static FloatType kernel(FloatType x) - { - x = fabs(x); - if (x >= (FloatType)2.) - return 0.0f; - if (x <= (FloatType)1.) { - FloatType x2 = x * x; - FloatType x3 = x2 * x; - return KERNEL::a10() + KERNEL::a11() * x + KERNEL::a12() * x2 + KERNEL::a13() * x3; - } - assert(x > (FloatType)1. && x < (FloatType)2.); - x -= (FloatType)1.; - FloatType x2 = x * x; - FloatType x3 = x2 * x; - return KERNEL::a00() + KERNEL::a01() * x + KERNEL::a02() * x2 + KERNEL::a03() * x3; - } - - static FloatType interpolate(FloatType f0, FloatType f1, FloatType f2, FloatType f3, FloatType x) - { - const FloatType x2 = x*x; - const FloatType x3 = x*x*x; - return f0*(KERNEL::a00() + KERNEL::a01() * x + KERNEL::a02() * x2 + KERNEL::a03() * x3) + - f1*(KERNEL::a10() + KERNEL::a11() * x + KERNEL::a12() * x2 + KERNEL::a13() * x3) + - f2*(KERNEL::a20() + KERNEL::a21() * x + KERNEL::a22() * x2 + KERNEL::a23() * x3) + - f3*(KERNEL::a30() + KERNEL::a31() * x + KERNEL::a32() * x2 + KERNEL::a33() * x3); - } -}; - -// Linear splines -typedef CubicKernel> LinearKernelf; -typedef CubicKernel> LinearKerneld; -// Catmul-Rom splines -typedef CubicKernel> CubicCatmulRomKernelf; -typedef CubicKernel> CubicCatmulRomKerneld; -typedef CubicKernel> CubicInterpolationKernelf; -typedef CubicKernel> CubicInterpolationKerneld; -// Cubic B-splines -typedef CubicKernel> CubicBSplineKernelf; -typedef CubicKernel> CubicBSplineKerneld; - -template -static float cubic_interpolate(const Eigen::ArrayBase &F, const typename KERNEL::FloatType pt, const typename KERNEL::FloatType dx) -{ - typedef typename KERNEL::FloatType T; - const int w = int(F.size()); - const int ix = (int)floor(pt); - const T s = pt - (T)ix; - - if (ix > 1 && ix + 2 < w) { - // Inside the fully interpolated region. - return KERNEL::interpolate(F[ix - 1], F[ix], F[ix + 1], F[ix + 2], s); - } - // Transition region. Extend with a constant function. - auto f = [&F, w](x) { return F[BicubicInternal::clamp(x, 0, w - 1)]; } - return KERNEL::interpolate(f(ix - 1), f(ix), f(ix + 1), f(ix + 2), s); -} - -template -static float bicubic_interpolate(const Eigen::MatrixBase &F, const Eigen::Matrix &pt, const typename KERNEL::FloatType dx) -{ - typedef typename KERNEL::FloatType T; - const int w = F.cols(); - const int h = F.rows(); - const int ix = (int)floor(pt[0]); - const int iy = (int)floor(pt[1]); - const T s = pt[0] - (T)ix; - const T t = pt[1] - (T)iy; - - if (ix > 1 && ix + 2 < w && iy > 1 && iy + 2 < h) { - // Inside the fully interpolated region. - return KERNEL::interpolate( - KERNEL::interpolate(F(ix-1,iy-1),F(ix ,iy-1),F(ix+1,iy-1),F(ix+2,iy-1),s), - KERNEL::interpolate(F(ix-1,iy ),F(ix ,iy ),F(ix+1,iy ),F(ix+2,iy ),s), - KERNEL::interpolate(F(ix-1,iy+1),F(ix ,iy+1),F(ix+1,iy+1),F(ix+2,iy+1),s), - KERNEL::interpolate(F(ix-1,iy+2),F(ix ,iy+2),F(ix+1,iy+2),F(ix+2,iy+2),s),t); - } - // Transition region. Extend with a constant function. - auto f = [&f, w, h](int x, int y) { return F(BicubicInternal::clamp(x,0,w-1),BicubicInternal::clamp(y,0,h-1)); } - return KERNEL::interpolate( - KERNEL::interpolate(f(ix-1,iy-1),f(ix ,iy-1),f(ix+1,iy-1),f(ix+2,iy-1),s), - KERNEL::interpolate(f(ix-1,iy ),f(ix ,iy ),f(ix+1,iy ),f(ix+2,iy ),s), - KERNEL::interpolate(f(ix-1,iy+1),f(ix ,iy+1),f(ix+1,iy+1),f(ix+2,iy+1),s), - KERNEL::interpolate(f(ix-1,iy+2),f(ix ,iy+2),f(ix+1,iy+2),f(ix+2,iy+2),s),t); -} - -} // namespace Slic3r - -#endif /* BICUBIC_HPP */ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 23d5ea225b..4f8fe80cc4 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -178,16 +178,12 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoCut.hpp GUI/Gizmos/GLGizmoEmboss.cpp GUI/Gizmos/GLGizmoEmboss.hpp - #GUI/Gizmos/GLGizmoFaceDetector.cpp - #GUI/Gizmos/GLGizmoFaceDetector.hpp GUI/Gizmos/GLGizmoFdmSupports.cpp GUI/Gizmos/GLGizmoFdmSupports.hpp GUI/Gizmos/GLGizmoFlatten.cpp GUI/Gizmos/GLGizmoFlatten.hpp GUI/Gizmos/GLGizmoFuzzySkin.cpp GUI/Gizmos/GLGizmoFuzzySkin.hpp - #GUI/Gizmos/GLGizmoHollow.cpp - #GUI/Gizmos/GLGizmoHollow.hpp GUI/Gizmos/GLGizmoMeasure.cpp GUI/Gizmos/GLGizmoMeasure.hpp GUI/Gizmos/GLGizmoMeshBoolean.cpp @@ -208,8 +204,6 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoSeam.hpp GUI/Gizmos/GLGizmoSimplify.cpp GUI/Gizmos/GLGizmoSimplify.hpp - #GUI/Gizmos/GLGizmoSlaSupports.cpp - #GUI/Gizmos/GLGizmoSlaSupports.hpp GUI/Gizmos/GLGizmosManager.cpp GUI/Gizmos/GLGizmosManager.hpp GUI/Gizmos/GLGizmoSVG.cpp @@ -218,8 +212,6 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoTextureDisplacement.hpp GUI/Gizmos/GLGizmoUtils.cpp GUI/Gizmos/GLGizmoUtils.hpp - #GUI/Gizmos/GLGizmoText.cpp - #GUI/Gizmos/GLGizmoText.hpp GUI/GLCanvas3D.cpp GUI/GLCanvas3D.hpp GUI/GLModel.cpp @@ -806,7 +798,6 @@ set(SLIC3R_GUI_SOURCES Utils/PrintHost.hpp Utils/Process.cpp Utils/Process.hpp - Utils/ProfileDescription.hpp Utils/Profile.hpp Utils/RaycastManager.cpp Utils/RaycastManager.hpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp deleted file mode 100644 index 09bb92dddf..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp +++ /dev/null @@ -1,2015 +0,0 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. -#include "GLGizmoAdvancedCut.hpp" -#include "slic3r/GUI/Widgets/ProgressDialog.hpp" -#include "slic3r/GUI/GUI.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" - -#include - -#include -#include -#include -#include - -#include - -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "libslic3r/AppConfig.hpp" -#include "../GUI/MsgDialog.hpp" - -#include - -#include "slic3r/GUI/CameraUtils.hpp" - -namespace Slic3r { -namespace GUI { - -const double units_in_to_mm = 25.4; -const double units_mm_to_in = 1 / units_in_to_mm; - -const int c_connectors_group_id = 4; -const float UndefFloat = -999.f; - -// connector colors -static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW(); -static const ColorRGBA DOWEL_COLOR = ColorRGBA::DARK_YELLOW(); -static const ColorRGBA HOVERED_PLAG_COLOR = ColorRGBA::CYAN(); -static const ColorRGBA HOVERED_DOWEL_COLOR = {0.0f, 0.5f, 0.5f, 1.0f}; -static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY(); -static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::GRAY(); // DARK_GRAY(); -static const ColorRGBA CONNECTOR_DEF_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; -static const ColorRGBA CONNECTOR_ERR_COLOR = {1.0f, 0.3f, 0.3f, 0.5f}; -static const ColorRGBA HOVERED_ERR_COLOR = {1.0f, 0.3f, 0.3f, 1.0f}; - -static Vec3d rotate_vec3d_around_vec3d_with_rotate_matrix( - const Vec3d& rotate_point, - const Vec3d& origin_point, - const Transform3d& rotate_matrix) -{ - Transform3d translate_to_point = Transform3d::Identity(); - translate_to_point.translate(origin_point); - Transform3d translate_to_zero = Transform3d::Identity(); - translate_to_zero.translate(-origin_point); - return (translate_to_point * rotate_matrix * translate_to_zero) * rotate_point; -} - -static inline void rotate_point_2d(double& x, double& y, const double c, const double s) -{ - double xold = x; - double yold = y; - x = c * xold - s * yold; - y = s * xold + c * yold; -} - -static void rotate_x_3d(std::array& verts, float radian_angle) -{ - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < verts.size(); ++i) - rotate_point_2d(verts[i](1), verts[i](2), c, s); -} - -static void rotate_y_3d(std::array& verts, float radian_angle) -{ - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < verts.size(); ++i) - rotate_point_2d(verts[i](2), verts[i](0), c, s); -} - -static void rotate_z_3d(std::array& verts, float radian_angle) -{ - double c = cos(radian_angle); - double s = sin(radian_angle); - for (uint32_t i = 0; i < verts.size(); ++i) - rotate_point_2d(verts[i](0), verts[i](1), c, s); -} - -const double GLGizmoAdvancedCut::Offset = 10.0; -const double GLGizmoAdvancedCut::Margin = 20.0; -const ColorRGBA GLGizmoAdvancedCut::GrabberColor = { 1.0f, 1.0f, 0.0f, 1.0f }; -const ColorRGBA GLGizmoAdvancedCut::GrabberHoverColor = { 0.7f, 0.7f, 0.0f, 1.0f }; - -GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoRotate3D(parent, icon_filename, sprite_id, nullptr) - , m_movement(0.0) - , m_buffered_movement(0.0) - , m_last_active_id(0) - , m_keep_upper(true) - , m_keep_lower(true) - , m_cut_to_parts(false) - , m_do_segment(false) - , m_segment_smoothing_alpha(0.5) - , m_segment_number(5) - , m_connector_type(CutConnectorType::Plug) - , m_connector_style(size_t(CutConnectorStyle::Prizm)) - , m_connector_shape_id(size_t(CutConnectorShape::Circle)) -{ - for (int i = 0; i < 4; i++) - m_cut_plane_points[i] = { 0., 0., 0. }; - - m_group_id = (m_gizmos.size()); - m_rotation.setZero(); - //m_current_base_rotation.setZero(); - m_rotate_cmds.clear(); - m_buffered_rotation.setZero(); -} - -void GLGizmoAdvancedCut::data_changed(bool is_serializing) -{ - GLGizmoRotate3D::data_changed(is_serializing); - finish_rotation(); -} - -bool GLGizmoAdvancedCut::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down) -{ - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - - if (shift_down && !m_connectors_editing && - (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::Dragging)) { - process_cut_line(action, mouse_position); - return true; - } - - if (action == SLAGizmoEventType::LeftDown) { - if (!m_connectors_editing) - return false; - - if (m_hover_id != -1) { - //start_dragging(); - return true; - } - - if (shift_down || alt_down) { - // left down with shift - show the selection rectangle: - //if (m_hover_id == -1) - // m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect); - } else { - // If there is no selection and no hovering, add new point - if (m_hover_id == -1 && !shift_down && !alt_down) - add_connector(connectors, mouse_position); - //m_ldown_mouse_position = mouse_position; - } - return true; - } - else if (action == SLAGizmoEventType::LeftUp) { - if (m_hover_id == -1 && !shift_down && !alt_down) - unselect_all_connectors(); - - is_selection_changed(alt_down, shift_down); - return true; - } - else if (action == SLAGizmoEventType::RightDown) { - if (m_hover_id < c_connectors_group_id) - return false; - - unselect_all_connectors(); - select_connector(m_hover_id - c_connectors_group_id, true); - return delete_selected_connectors(); - } - else if (action == SLAGizmoEventType::RightUp) { - // catch right click event - return true; - } - - return false; -} - -bool GLGizmoAdvancedCut::on_key(wxKeyEvent &evt) -{ - bool ctrl_down = evt.GetModifiers() & wxMOD_CONTROL; - - if (evt.GetKeyCode() == WXK_DELETE) { - return delete_selected_connectors(); - } - else if (ctrl_down - && (evt.GetKeyCode() == 'A' || evt.GetKeyCode() == 'a')) - { - select_all_connectors(); - return true; - } - return false; -} - -std::string GLGizmoAdvancedCut::get_tooltip() const -{ - return ""; -} - -BoundingBoxf3 GLGizmoAdvancedCut::bounding_box() const -{ - BoundingBoxf3 ret; - const Selection & selection = m_parent.get_selection(); - const Selection::IndicesList &idxs = selection.get_volume_idxs(); - for (unsigned int i : idxs) { - const GLVolume *volume = selection.get_volume(i); - // respect just to the solid parts for FFF and ignore pad and supports for SLA - if (!volume->is_modifier && !volume->is_sla_pad() && !volume->is_sla_support()) ret.merge(volume->transformed_convex_hull_bounding_box()); - } - return ret; -} - -bool GLGizmoAdvancedCut::is_looking_forward() const -{ - const Camera &camera = wxGetApp().plater()->get_camera(); - const double dot = camera.get_dir_forward().dot(m_cut_plane_normal); - return dot < 0.05; -} - -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoAdvancedCut::unproject_on_cut_plane(const Vec2d &mouse_pos, Vec3d &pos, Vec3d &pos_world) -{ - const float sla_shift = m_c->selection_info()->get_sla_shift(); - - const ModelObject * mo = m_c->selection_info()->model_object(); - const ModelInstance *mi = mo->instances[m_c->selection_info()->get_active_instance()]; - const Camera & camera = wxGetApp().plater()->get_camera(); - - // Calculate intersection with the clipping plane. - const ClippingPlane *cp = m_c->object_clipper()->get_clipping_plane(); - Vec3d point; - Vec3d direction; - Vec3d hit; - CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction); - Vec3d normal = -cp->get_normal().cast(); - double den = normal.dot(direction); - if (den != 0.) { - double t = (-cp->get_offset() - normal.dot(point)) / den; - hit = (point + t * direction); - } else - return false; - - if (!m_c->object_clipper()->is_projection_inside_cut(hit)) - return false; - - // recalculate hit to object's local position - Vec3d hit_d = hit; - hit_d -= mi->get_offset(); - hit_d[Z] -= sla_shift; - - // Return both the point and the facet normal. - pos = hit_d; - pos_world = hit; - - return true; -} - -void GLGizmoAdvancedCut::update_plane_points() -{ - Vec3d plane_center = get_plane_center(); - - std::array plane_points_rot; - for (int i = 0; i < plane_points_rot.size(); i++) { - plane_points_rot[i] = m_cut_plane_points[i] - plane_center; - } - - if (m_rotation(0) > EPSILON) { - rotate_x_3d(plane_points_rot, m_rotation(0)); - m_rotate_cmds.emplace(m_rotate_cmds.begin(), m_rotation(0), X); - } - if (m_rotation(1) > EPSILON) { - rotate_y_3d(plane_points_rot, m_rotation(1)); - m_rotate_cmds.emplace(m_rotate_cmds.begin(), m_rotation(1), Y); - } - if (m_rotation(2) > EPSILON) { - rotate_z_3d(plane_points_rot, m_rotation(2)); - m_rotate_cmds.emplace(m_rotate_cmds.begin(), m_rotation(2), Z); - } - - Vec3d plane_normal = calc_plane_normal(plane_points_rot); - if (m_movement == 0 && m_height_delta != 0) - m_movement = plane_normal(2) * m_height_delta;// plane_normal.dot(Vec3d(0, 0, m_height_delta)) - for (int i = 0; i < plane_points_rot.size(); i++) { - m_cut_plane_points[i] = plane_points_rot[i] + plane_center + plane_normal * m_movement; - } - - //m_current_base_rotation += m_rotation; - m_rotation.setZero(); - m_movement = 0.0; - m_height_delta = 0; -} - -std::array GLGizmoAdvancedCut::get_plane_points() const -{ - return m_cut_plane_points; -} - -std::array GLGizmoAdvancedCut::get_plane_points_world_coord() const -{ - std::array plane_world_coord = m_cut_plane_points; - - const Selection& selection = m_parent.get_selection(); - const BoundingBoxf3& box = selection.get_bounding_box(); - Vec3d object_offset = box.center(); - - for (Vec3d& point : plane_world_coord) { - point += object_offset; - } - - return plane_world_coord; -} - -void GLGizmoAdvancedCut::reset_cut_plane() -{ - const Selection& selection = m_parent.get_selection(); - const BoundingBoxf3& box = selection.get_bounding_box(); - const float max_x = box.size()(0) / 2.0 + Margin; - const float min_x = -max_x; - const float max_y = box.size()(1) / 2.0 + Margin; - const float min_y = -max_y; - - m_cut_plane_points[0] = { min_x, min_y, 0 }; - m_cut_plane_points[1] = { max_x, min_y, 0 }; - m_cut_plane_points[2] = { max_x, max_y, 0 }; - m_cut_plane_points[3] = { min_x, max_y, 0 }; - m_movement = 0.0; - m_height = box.size()[2] / 2.0; - m_height_delta = 0; - m_rotation.setZero(); - //m_current_base_rotation.setZero(); - m_rotate_cmds.clear(); - - m_buffered_movement = 0.0; - m_buffered_height = m_height; - m_buffered_rotation.setZero(); -} - -void GLGizmoAdvancedCut::reset_all() -{ - reset_cut_plane(); - - m_keep_upper = true; - m_keep_lower = true; - m_cut_to_parts = false; - m_place_on_cut_upper = true; - m_place_on_cut_lower = false; - m_rotate_upper = false; - m_rotate_lower = false; -} - -bool GLGizmoAdvancedCut::on_init() -{ - if (!GLGizmoRotate3D::on_init()) - return false; - - - // initiate info shortcuts - const wxString ctrl = GUI::shortkey_ctrl_prefix(); - const wxString alt = GUI::shortkey_alt_prefix(); - const wxString shift = _L("Shift+"); - - m_shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add connector"))); - m_shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove connector"))); - m_shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move connector"))); - m_shortcuts.push_back(std::make_pair(shift + _L("Left click"), _L("Add connector to selection"))); - m_shortcuts.push_back(std::make_pair(alt + _L("Left click"), _L("Remove connector from selection"))); - m_shortcuts.push_back(std::make_pair(ctrl + "A", _L("Select all connectors"))); - - init_connector_shapes(); - return true; -} - -std::string GLGizmoAdvancedCut::on_get_name() const -{ - return (_L_CONTEXT("Cut", "Cut tool")).ToUTF8().data(); -} - -void GLGizmoAdvancedCut::on_load(cereal::BinaryInputArchive &ar) -{ - ar(m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_connectors_editing, - m_cut_plane_points[0], m_cut_plane_points[1], m_cut_plane_points[2], m_cut_plane_points[3]); - - m_parent.request_extra_frame(); -} - -void GLGizmoAdvancedCut::on_save(cereal::BinaryOutputArchive &ar) const -{ - ar(m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_connectors_editing, - m_cut_plane_points[0], m_cut_plane_points[1], m_cut_plane_points[2], m_cut_plane_points[3]); -} - -void GLGizmoAdvancedCut::on_set_state() -{ - GLGizmoRotate3D::on_set_state(); - - // Reset m_cut_z on gizmo activation - if (get_state() == On) { - m_connectors_editing = false; - reset_cut_plane(); - } - else if (get_state() == Off) { - clear_selection(); - m_c->object_clipper()->release(); - } -} - -bool GLGizmoAdvancedCut::on_is_activable() const -{ - const Selection& selection = m_parent.get_selection(); - return selection.is_single_full_instance() && !selection.is_wipe_tower(); -} - -CommonGizmosDataID GLGizmoAdvancedCut::on_get_requirements() const -{ - return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::ObjectClipper)); -} - -void GLGizmoAdvancedCut::on_start_dragging() -{ - if (m_hover_id == X || m_hover_id == Y || m_hover_id == Z) { - m_gizmos[m_hover_id].start_dragging(); - } else if (m_hover_id == c_connectors_group_id - 1) { - const Selection& selection = m_parent.get_selection(); - const BoundingBoxf3& box = selection.get_bounding_box(); - m_start_movement = m_movement; - m_start_height = m_height; - m_drag_pos = m_move_grabber.center; - } -} - -void GLGizmoAdvancedCut::on_stop_dragging() -{ - if (m_hover_id == X || m_hover_id == Y || m_hover_id == Z) { - m_gizmos[m_hover_id].stop_dragging(); - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Rotate cut plane"); - } else if (m_hover_id == c_connectors_group_id - 1) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move cut plane"); - } else if (m_hover_id >= c_connectors_group_id) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move connector"); - } -} - -void GLGizmoAdvancedCut::on_dragging(const UpdateData &data) -{ - GLGizmoRotate3D::on_dragging(data); - - Vec3d rotation; - for (int i = 0; i < 3; i++) - { - rotation(i) = m_gizmos[i].get_angle(); - if (rotation(i) < 0) - rotation(i) = 2*PI + rotation(i); - } - - m_rotation = rotation; - //m_move_grabber.angles = m_current_base_rotation + m_rotation; - - if (m_hover_id == m_group_id) { - double move = calc_projection(data.mouse_ray); - set_movement(m_start_movement + move); - Vec3d plane_normal = get_plane_normal(); - m_height = m_start_height + plane_normal(2) * move; - } - - // dragging connectors - if (m_connectors_editing && m_hover_id >= c_connectors_group_id) { - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - Vec3d pos; - Vec3d pos_world; - - if (unproject_on_cut_plane(data.mouse_pos.cast(), pos, pos_world)) { - connectors[m_hover_id - c_connectors_group_id].pos = pos; - } - } -} - -void GLGizmoAdvancedCut::on_render() -{ - update_clipper(); - if (m_connectors_editing) { - render_connectors(); - } - - // render_clipper_cut for get the cut plane result - render_clipper_cut(); - - if(!m_connectors_editing) { - check_conflict_for_all_connectors(); - render_cut_plane_and_grabbers(); - } - - render_cut_line(); -} -/* -void GLGizmoAdvancedCut::on_render_for_picking() -{ - GLGizmoRotate3D::on_render_for_picking(); - - glsafe(::glDisable(GL_DEPTH_TEST)); - - BoundingBoxf3 box = m_parent.get_selection().get_bounding_box(); -#if ENABLE_FIXED_GRABBER - float mean_size = (float)(GLGizmoBase::Grabber::FixedGrabberSize); -#else - float mean_size = (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0); -#endif - - m_move_grabber.color = picking_color_component(0); - GLShaderProgram *shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - const Camera &camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_move_grabber.render_for_picking(mean_size); - - shader->stop_using(); - } - - glsafe(::glEnable(GL_DEPTH_TEST)); - auto inst_id = m_c->selection_info()->get_active_instance(); - if (inst_id < 0) - return; - - const ModelObject *mo = m_c->selection_info()->model_object(); - const ModelInstance *mi = mo->instances[inst_id]; - const Vec3d & instance_offset = mi->get_offset(); - const double sla_shift = double(m_c->selection_info()->get_sla_shift()); - - const CutConnectors &connectors = mo->cut_connectors; - for (int i = 0; i < connectors.size(); ++i) { - CutConnector connector = connectors[i]; - Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); - float height = connector.height; - - if (connector.attribs.type == CutConnectorType::Dowel && connector.attribs.style == CutConnectorStyle::Prizm) { - pos -= height * m_cut_plane_normal; - height *= 2; - } else if (!is_looking_forward()) - pos -= 0.05 * m_cut_plane_normal; - - Transform3d translate_tf = Transform3d::Identity(); - translate_tf.translate(pos); - - Transform3d scale_tf = Transform3d::Identity(); - scale_tf.scale(Vec3f(connector.radius, connector.radius, height).cast()); - - const Transform3d model_matrix = translate_tf * m_rotate_matrix * scale_tf; - - ColorRGBA color = picking_color_component(i+1); - render_connector_model(m_shapes[connectors[i].attribs], color, model_matrix, true); - } -} -*/ -void GLGizmoAdvancedCut::on_render_input_window(float x, float y, float bottom_limit) -{ - GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); - ImGuiWrapper::push_toolbar_style(m_parent.get_scale()); - GizmoImguiBegin(on_get_name(), - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); - - if (m_connectors_editing) { - init_connectors_input_window_data(); - render_connectors_input_window(x, y, bottom_limit); - } - else - render_cut_plane_input_window(x, y, bottom_limit); - - render_input_window_warning(); - - GizmoImguiEnd(); - ImGuiWrapper::pop_toolbar_style(); -} - -void GLGizmoAdvancedCut::show_tooltip_information(float x, float y) -{ - float caption_max = 0.f; - for (const auto& short_cut : m_shortcuts) { - caption_max = std::max(caption_max, m_imgui->calc_text_size(short_cut.first).x); - } - - ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP); - ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER); - - caption_max += m_imgui->calc_text_size(": ").x + 35.f; - - float font_size = ImGui::GetFontSize(); - ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y}); - ImGui::ImageButton3(normal_id, hover_id, button_size); - - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip2(ImVec2(x, y)); - auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { - m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); - ImGui::SameLine(caption_max); - m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); - }; - - for (const auto& short_cut : m_shortcuts) - draw_text_with_caption(short_cut.first + ": ", short_cut.second); - ImGui::EndTooltip(); - } - ImGui::PopStyleVar(2); -} - -void GLGizmoAdvancedCut::set_movement(double movement) const -{ - m_movement = movement; -} - -void GLGizmoAdvancedCut::perform_cut(const Selection& selection) -{ - if (!can_perform_cut()) - return; - - const int instance_idx = selection.get_instance_idx(); - const int object_idx = selection.get_object_idx(); - - wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoAdvancedCut: Invalid object selection"); - - // m_cut_z is the distance from the bed. Subtract possible SLA elevation. - const GLVolume* first_glvolume = selection.get_first_volume(); - - // perform cut - { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Cut by Plane"); - - ModelObject *mo = wxGetApp().plater()->model().objects[object_idx]; - const bool has_connectors = !mo->cut_connectors.empty(); - - bool create_dowels_as_separate_object = false; - // update connectors pos as offset of its center before cut performing - apply_connectors_in_model(mo, create_dowels_as_separate_object); - - apply_connectors_in_model(cut_mo, dowels_count); - - wxBusyCursor wait; - - ModelObjectCutAttributes attributes = only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) | - only_if(has_connectors ? true : m_keep_lower, ModelObjectCutAttribute::KeepLower) | - only_if(has_connectors ? false : m_cut_to_parts, ModelObjectCutAttribute::CutToParts) | - only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) | - only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) | - only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) | only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) | - only_if(dowels_count > 0, ModelObjectCutAttribute::CreateDowels) | - only_if(!has_connectors && !cut_with_groove && cut_mo->cut_id.id().invalid(), ModelObjectCutAttribute::InvalidateCutInfo); - - // update cut_id for the cut object in respect to the attributes - update_object_cut_id(cut_mo->cut_id, attributes, dowels_count); - - Cut cut(cut_mo, instance_idx, get_cut_matrix(selection), attributes); - cut.set_offset_for_two_part = true; - const ModelObjectPtrs &new_objects = cut_by_contour ? cut.perform_by_contour(m_part_selection->get_cut_parts(), dowels_count) : - cut_with_groove ? cut.perform_with_groove(m_groove, m_rotate_matrix) : - cut.perform_with_plane(); - // fix_non_manifold_edges - { - bool is_showed_dialog = false; - bool user_fix_model = false; - for (size_t i = 0; i < new_objects.size(); i++) { - for (size_t j = 0; j < new_objects[i]->volumes.size(); j++) { - if (its_num_open_edges(new_objects[i]->volumes[j]->mesh().its) > 0) { - if (!is_showed_dialog) { - is_showed_dialog = true; - MessageDialog dlg(nullptr, _L("Non-manifold edges be caused by cut tool: do you want to fix now\?"), "", wxYES | wxNO); - int ret = dlg.ShowModal(); - if (ret == wxID_YES) { - user_fix_model = true; - } - } - if (!user_fix_model) { - break; - } - // model_name - std::vector succes_models; - // model_name failing reason - std::vector> failed_models; - auto plater = wxGetApp().plater(); - auto fix_and_update_progress = [this, plater](ModelObject *model_object, const int vol_idx, const string &model_name, ProgressDialog &progress_dlg, - std::vector &succes_models, std::vector> &failed_models) { - wxString msg = _L("Repairing model object"); - msg += ": " + from_u8(model_name) + "\n"; - std::string res; - if (!fix_model_with_cgal_gui(*model_object, vol_idx, progress_dlg, msg, res)) return false; - return true; - }; - ProgressDialog progress_dlg(_L("Repairing model object"), "", 100, find_toplevel_parent(plater), wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT, true); - - auto model_name = new_objects[i]->name; - if (!fix_and_update_progress(new_objects[i], j, model_name, progress_dlg, succes_models, failed_models)) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "run fix_and_update_progress error"; - }; - }; - } - } - } - // set offset for new_objects - - // save cut_id to post update synchronization - const CutObjectBase cut_id = cut_mo->cut_id; - - // update cut results on plater and in the model - plater->apply_cut_object_to_model(object_idx, new_objects); - - } - } -} - -bool GLGizmoAdvancedCut::can_perform_cut() const -{ - if (m_has_invalid_connector || (!m_keep_upper && !m_keep_lower) || m_connectors_editing) - return false; - - return true; - //const auto clipper = m_c->object_clipper(); - //return clipper && clipper->has_valid_contour(); -} - -void GLGizmoAdvancedCut::apply_connectors_in_model(ModelObject *mo, bool &create_dowels_as_separate_object) -{ - clear_selection(); - - for (CutConnector &connector : mo->cut_connectors) { - connector.rotation_m = m_rotate_matrix; - - if (connector.attribs.type == CutConnectorType::Dowel) { - if (connector.attribs.style == CutConnectorStyle::Prizm) connector.height *= 2; - create_dowels_as_separate_object = true; - } else { - // culculate shift of the connector center regarding to the position on the cut plane - Vec3d shifted_center = m_cut_plane_center + Vec3d::UnitZ(); - shifted_center = rotate_vec3d_around_vec3d_with_rotate_matrix(shifted_center, m_cut_plane_center, m_rotate_matrix); - Vec3d norm = (shifted_center - m_cut_plane_center).normalized(); - connector.pos += norm * 0.5 * double(connector.height); - } - } - - mo->apply_cut_connectors(_u8L("Connector")); -} - -bool GLGizmoAdvancedCut::is_selection_changed(bool alt_down, bool shift_down) -{ - if (m_hover_id >= c_connectors_group_id) { - if (alt_down) - select_connector(m_hover_id - c_connectors_group_id, false); - else { - if (!shift_down) unselect_all_connectors(); - select_connector(m_hover_id - c_connectors_group_id, true); - } - return true; - } - return false; -} - -void GLGizmoAdvancedCut::select_connector(int idx, bool select) -{ - m_selected[idx] = select; - if (select) - ++m_selected_count; - else - --m_selected_count; -} - -Vec3d GLGizmoAdvancedCut::calc_plane_normal(const std::array& plane_points) const -{ - Vec3d v01 = plane_points[1] - plane_points[0]; - Vec3d v12 = plane_points[2] - plane_points[1]; - - Vec3d plane_normal = v01.cross(v12); - plane_normal.normalize(); - return plane_normal; -} - -Vec3d GLGizmoAdvancedCut::calc_plane_center(const std::array& plane_points) const -{ - Vec3d plane_center; - plane_center.setZero(); - for (const Vec3d& point : plane_points) - plane_center = plane_center + point; - - return plane_center / (float)m_cut_plane_points.size(); -} - -double GLGizmoAdvancedCut::calc_projection(const Linef3& mouse_ray) const -{ - Vec3d mouse_dir = mouse_ray.unit_vector(); - Vec3d inters = mouse_ray.a + (m_drag_pos - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; - Vec3d inters_vec = inters - m_drag_pos; - - Vec3d plane_normal = get_plane_normal(); - return inters_vec.dot(plane_normal); -} - -Vec3d GLGizmoAdvancedCut::get_plane_normal() const -{ - return calc_plane_normal(m_cut_plane_points); -} - -Vec3d GLGizmoAdvancedCut::get_plane_center() const -{ - return calc_plane_center(m_cut_plane_points); -} - -void GLGizmoAdvancedCut::finish_rotation() -{ - for (int i = 0; i < 3; i++) { - m_gizmos[i].set_angle(0.); - } - - update_plane_points(); -} - -void GLGizmoAdvancedCut::put_connectors_on_cut_plane(const Vec3d &cp_normal, double cp_offset) -{ - ModelObject *mo = m_c->selection_info()->model_object(); - if (CutConnectors &connectors = mo->cut_connectors; !connectors.empty()) { - const float sla_shift = m_c->selection_info()->get_sla_shift(); - const Vec3d &instance_offset = mo->instances[m_c->selection_info()->get_active_instance()]->get_offset(); - - for (auto &connector : connectors) { - // convert connetor pos to the world coordinates - Vec3d pos = connector.pos + instance_offset; - pos[Z] += sla_shift; - // scalar distance from point to plane along the normal - double distance = -cp_normal.dot(pos) + cp_offset; - // move connector - connector.pos += distance * cp_normal; - } - } -} - -void GLGizmoAdvancedCut::update_clipper() -{ - BoundingBoxf3 box = bounding_box(); - double radius = box.radius(); - Vec3d plane_center = m_cut_plane_center; - - Vec3d begin, end = begin = plane_center; - begin[Z] = box.center().z() - radius; - end[Z] = box.center().z() + radius; - - double phi; - Vec3d rotation_axis; - Matrix3d rotation_matrix; - Geometry::rotation_from_two_vectors(Vec3d::UnitZ(), m_cut_plane_normal, rotation_axis, phi, &rotation_matrix); - - m_rotate_matrix.setIdentity(); - m_rotate_matrix = rotation_matrix * m_rotate_matrix; - - begin = rotate_vec3d_around_vec3d_with_rotate_matrix(begin, plane_center, m_rotate_matrix); - end = rotate_vec3d_around_vec3d_with_rotate_matrix(end, plane_center, m_rotate_matrix); - - Vec3d normal = end - begin; - - if (!is_looking_forward()) { - end = begin = plane_center; - begin[Z] = box.center().z() + radius; - end[Z] = box.center().z() - radius; - - begin = rotate_vec3d_around_vec3d_with_rotate_matrix(begin, plane_center, m_rotate_matrix); - end = rotate_vec3d_around_vec3d_with_rotate_matrix(end, plane_center, m_rotate_matrix); - - // recalculate normal for clipping plane, if camera is looking downward to cut plane - normal = end - begin; - if (normal == Vec3d::Zero()) - return; - } - - // calculate normal and offset for clipping plane - double dist = (plane_center - begin).norm(); - dist = std::clamp(dist, 0.0001, normal.norm()); - normal.normalize(); - const double offset = normal.dot(begin) + dist; - - m_c->object_clipper()->set_range_and_pos(normal, offset, dist); - - put_connectors_on_cut_plane(normal, offset); -} - -void GLGizmoAdvancedCut::render_cut_plane_and_grabbers() -{ - const Selection & selection = m_parent.get_selection(); - const BoundingBoxf3 &box = selection.get_bounding_box(); - // box center is the coord of object in the world coordinate - Vec3d object_offset = box.center(); - // plane points is in object coordinate - Vec3d plane_center = get_plane_center(); - - m_cut_plane_center = object_offset + plane_center; - - // rotate plane - std::array plane_points_rot; - { - for (int i = 0; i < plane_points_rot.size(); i++) { - plane_points_rot[i] = m_cut_plane_points[i] - plane_center; - } - - if (m_rotation(0) > EPSILON) - rotate_x_3d(plane_points_rot, m_rotation(0)); - if (m_rotation(1) > EPSILON) - rotate_y_3d(plane_points_rot, m_rotation(1)); - if (m_rotation(2) > EPSILON) - rotate_z_3d(plane_points_rot, m_rotation(2)); - - for (int i = 0; i < plane_points_rot.size(); i++) { - plane_points_rot[i] += plane_center; - } - } - - // move plane - Vec3d plane_normal_rot = calc_plane_normal(plane_points_rot); - m_cut_plane_normal = plane_normal_rot; - for (int i = 0; i < plane_points_rot.size(); i++) { - plane_points_rot[i] += plane_normal_rot * m_movement; - } - - // transfer from object coordindate to the world coordinate - for (Vec3d& point : plane_points_rot) { - point += object_offset; - } - - glsafe(::glEnable(GL_DEPTH_TEST)); - glsafe(::glDisable(GL_CULL_FACE)); - glsafe(::glEnable(GL_BLEND)); - glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - - GLShaderProgram *shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - - // draw plane - { - 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_vertices(6); - - // vertices - for (const Vec3d &point : plane_points_rot) { - init_data.add_vertex((Vec3f)point.cast()); - } - - // indices - init_data.add_triangle(0, 1, 2); - init_data.add_triangle(2, 3, 0); - - m_plane.init_from(std::move(init_data)); - } - const Camera &camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - m_plane.render(); - - glsafe(::glEnable(GL_CULL_FACE)); - glsafe(::glDisable(GL_BLEND)); - - // Draw the grabber and the connecting line - Vec3d plane_center_rot = calc_plane_center(plane_points_rot); - m_move_grabber.center = plane_center_rot + plane_normal_rot * Offset; - // m_move_grabber.angles = m_current_base_rotation + m_rotation; - - { - m_grabber_connection.reset(); - - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 }; - init_data.color = ColorRGBA::YELLOW(); - init_data.reserve_vertices(2); - init_data.reserve_vertices(2); - - // vertices - init_data.add_vertex((Vec3f)plane_center_rot.cast()); - init_data.add_vertex((Vec3f)m_move_grabber.center.cast()); - - // indices - init_data.add_line(0, 1); - - m_grabber_connection.init_from(std::move(init_data)); - } - - glsafe(::glDisable(GL_DEPTH_TEST)); - // ORCA: OpenGL Core Profile -#if !SLIC3R_OPENGL_ES - if (!OpenGLManager::get_gl_info().is_core_profile()) { - glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); - glLineStipple(1, 0x0FFF); - glEnable(GL_LINE_STIPPLE); - } -#endif // !SLIC3R_OPENGL_ES - m_grabber_connection.render(); -#if !SLIC3R_OPENGL_ES - if (!OpenGLManager::get_gl_info().is_core_profile()) - glDisable(GL_LINE_STIPPLE); -#endif // !SLIC3R_OPENGL_ES - - shader->stop_using(); - } - - { - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - // std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_move_grabber.color); - // m_move_grabber.color = GrabberColor; - // m_move_grabber.hover_color = GrabberHoverColor; - // m_move_grabber.render(m_hover_id == get_group_id(), (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); - bool hover = (m_hover_id == m_group_id); - ColorRGBA render_color; - if (hover) { - render_color = GrabberHoverColor; - } - else - render_color = GrabberColor; - - PickingModel &cube = m_move_grabber.get_cube(); - // BBS set to fixed size grabber - // float fullsize = 2 * (dragging ? get_dragging_half_size(size) : get_half_size(size)); - float fullsize = 8.0f; - if (GLGizmoBase::INV_ZOOM > 0) { - fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; - } - - cube.model.set_color(render_color); - - const Transform3d trafo_matrix = Geometry::assemble_transform(m_move_grabber.center) * m_rotate_matrix * - Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), fullsize * Vec3d::Ones()); - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - shader->set_uniform("view_model_matrix", view_matrix * trafo_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - cube.model.render(); - shader->stop_using(); - } - - // Should be placed at last, because GLGizmoRotate3D clears depth buffer - set_center(m_cut_plane_center); - GLGizmoRotate3D::on_render(); -} - -void GLGizmoAdvancedCut::render_connectors() -{ - ::glEnable(GL_DEPTH_TEST); - - const ModelObject *mo = m_c->selection_info()->model_object(); - auto inst_id = m_c->selection_info()->get_active_instance(); - if (inst_id < 0) - return; - - const CutConnectors &connectors = mo->cut_connectors; - if (connectors.size() != m_selected.size()) { - clear_selection(); - m_selected.resize(connectors.size(), false); - } - - const ModelInstance *mi = mo->instances[inst_id]; - const Vec3d & instance_offset = mi->get_offset(); - const double sla_shift = double(m_c->selection_info()->get_sla_shift()); - - m_has_invalid_connector = false; - m_info_stats.invalidate(); - - ColorRGBA render_color = CONNECTOR_DEF_COLOR; - for (size_t i = 0; i < connectors.size(); ++i) { - const CutConnector &connector = connectors[i]; - - float height = connector.height; - // recalculate connector position to world position - Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); - - // First decide about the color of the point. - const bool conflict_connector = is_conflict_for_connector(i, connectors, pos); - if (conflict_connector) { - m_has_invalid_connector = true; - render_color = CONNECTOR_ERR_COLOR; - } else // default connector color - render_color = connector.attribs.type == CutConnectorType::Dowel ? DOWEL_COLOR : PLAG_COLOR; - - if (!m_connectors_editing) - render_color = CONNECTOR_ERR_COLOR; - else if (size_t(m_hover_id - 4) == i) - render_color = conflict_connector ? HOVERED_ERR_COLOR : connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR; - else if (m_selected[i]) - render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR; - - const Camera &camera = wxGetApp().plater()->get_camera(); - if (connector.attribs.type == CutConnectorType::Dowel && connector.attribs.style == CutConnectorStyle::Prizm) { - pos -= height * m_cut_plane_normal; - height *= 2; - } else if (!is_looking_forward()) - pos -= 0.05 * m_cut_plane_normal; - - Transform3d translate_tf = Transform3d::Identity(); - translate_tf.translate(pos); - - Transform3d scale_tf = Transform3d::Identity(); - scale_tf.scale(Vec3f(connector.radius, connector.radius, height).cast()); - - const Transform3d model_matrix = translate_tf * m_rotate_matrix * scale_tf; - - render_connector_model(m_shapes[connector.attribs], render_color, model_matrix); - } -} - -void GLGizmoAdvancedCut::render_clipper_cut() -{ - glsafe(::glEnable(GL_DEPTH_TEST)); - m_c->object_clipper()->render_cut(); - glsafe(::glDisable(GL_DEPTH_TEST)); -} - -void GLGizmoAdvancedCut::render_cut_line() -{ - if (!cut_line_processing() || m_cut_line_end == Vec3d::Zero()) - return; - - glsafe(::glDisable(GL_DEPTH_TEST)); - - GLShaderProgram *shader = wxGetApp().get_shader("flat"); - if (shader != nullptr) { - shader->start_using(); - - { - m_cut_line.reset(); - - GLModel::Geometry init_data; - init_data.format = {GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3}; - init_data.color = ColorRGBA::GREEN(); - init_data.reserve_vertices(2); - init_data.reserve_vertices(2); - - // vertices - init_data.add_vertex((Vec3f) m_cut_line_begin.cast()); - init_data.add_vertex((Vec3f) m_cut_line_end.cast()); - - // indices - init_data.add_line(0, 1); - - m_cut_line.init_from(std::move(init_data)); - } - const Camera &camera = wxGetApp().plater()->get_camera(); - shader->set_uniform("view_model_matrix", camera.get_view_matrix()); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - - // ORCA: OpenGL Core Profile -#if !SLIC3R_OPENGL_ES - if (!OpenGLManager::get_gl_info().is_core_profile()) { - glEnable(GL_LINE_STIPPLE); - glLineStipple(1, 0x0FFF); - } -#endif // !SLIC3R_OPENGL_ES - m_cut_line.render(); -#if !SLIC3R_OPENGL_ES - if (!OpenGLManager::get_gl_info().is_core_profile()) - glDisable(GL_LINE_STIPPLE); -#endif // !SLIC3R_OPENGL_ES - - shader->stop_using(); - } -} - -void GLGizmoAdvancedCut::render_connector_model(GLModel &model, const ColorRGBA &color, Transform3d model_matrix, bool for_picking) -{ - GLShaderProgram *shader = nullptr; - if (for_picking) - shader = wxGetApp().get_shader("flat"); - else - shader = wxGetApp().get_shader("gouraud_light"); - if (shader) { - shader->start_using(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - shader->set_uniform("projection_matrix", camera.get_projection_matrix()); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - - model.set_color(color); - model.render(); - - shader->stop_using(); - } -} - -void GLGizmoAdvancedCut::clear_selection() -{ - m_selected.clear(); - m_selected_count = 0; -} - -void GLGizmoAdvancedCut::init_connector_shapes() -{ - for (const CutConnectorType &type : {CutConnectorType::Dowel, CutConnectorType::Plug}) - for (const CutConnectorStyle &style : {CutConnectorStyle::Frustum, CutConnectorStyle::Prizm}) - for (const CutConnectorShape &shape : {CutConnectorShape::Circle, CutConnectorShape::Hexagon, CutConnectorShape::Square, CutConnectorShape::Triangle}) { - const CutConnectorAttributes attribs = {type, style, shape}; - const indexed_triangle_set its = ModelObject::get_connector_mesh(attribs); - m_shapes[attribs].init_from(its); - } -} - -void GLGizmoAdvancedCut::set_connectors_editing(bool connectors_editing) -{ - m_connectors_editing = connectors_editing; - // todo: zhimin need a better method - // after change render mode, need update for scene - on_render(); -} - -void GLGizmoAdvancedCut::reset_connectors() -{ - m_c->selection_info()->model_object()->cut_connectors.clear(); - clear_selection(); -} - -void GLGizmoAdvancedCut::update_connector_shape() -{ - CutConnectorAttributes attribs = {m_connector_type, CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id)}; - - const indexed_triangle_set its = ModelObject::get_connector_mesh(attribs); - m_connector_mesh.clear(); - m_connector_mesh = TriangleMesh(its); -} - -void GLGizmoAdvancedCut::apply_selected_connectors(std::function apply_fn) -{ - for (size_t idx = 0; idx < m_selected.size(); idx++) - if (m_selected[idx]) - apply_fn(idx); -} - -void GLGizmoAdvancedCut::select_all_connectors() -{ - std::fill(m_selected.begin(), m_selected.end(), true); - m_selected_count = int(m_selected.size()); -} - -void GLGizmoAdvancedCut::unselect_all_connectors() -{ - std::fill(m_selected.begin(), m_selected.end(), false); - m_selected_count = 0; - validate_connector_settings(); -} - -void GLGizmoAdvancedCut::validate_connector_settings() -{ - if (m_connector_depth_ratio < 0.f) - m_connector_depth_ratio = 3.f; - if (m_connector_depth_ratio_tolerance < 0.f) - m_connector_depth_ratio_tolerance = 0.1f; - if (m_connector_size < 0.f) - m_connector_size = 2.5f; - if (m_connector_size_tolerance < 0.f) - m_connector_size_tolerance = 0.f; - - if (m_connector_type == CutConnectorType::Undef) - m_connector_type = CutConnectorType::Plug; - if (m_connector_style == size_t(CutConnectorStyle::Undef)) - m_connector_style = size_t(CutConnectorStyle::Prizm); - if (m_connector_shape_id == size_t(CutConnectorShape::Undef)) - m_connector_shape_id = size_t(CutConnectorShape::Circle); -} - -bool GLGizmoAdvancedCut::add_connector(CutConnectors &connectors, const Vec2d &mouse_position) -{ - if (!m_connectors_editing) - return false; - - Vec3d pos; - Vec3d pos_world; - if (unproject_on_cut_plane(mouse_position.cast(), pos, pos_world)) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Add connector"); - unselect_all_connectors(); - - connectors.emplace_back(pos, m_rotate_matrix, m_connector_size * 0.5f, m_connector_depth_ratio, m_connector_size_tolerance, m_connector_depth_ratio_tolerance, - CutConnectorAttributes(CutConnectorType(m_connector_type), CutConnectorStyle(m_connector_style), CutConnectorShape(m_connector_shape_id))); - m_selected.push_back(true); - m_selected_count = 1; - assert(m_selected.size() == connectors.size()); - m_parent.set_as_dirty(); - - return true; - } - return false; -} - -bool GLGizmoAdvancedCut::delete_selected_connectors() -{ - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - if (connectors.empty()) - return false; - - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Delete connector"); - - // remove connectors - for (int i = int(connectors.size()) - 1; i >= 0; i--) - if (m_selected[i]) connectors.erase(connectors.begin() + i); - // remove selections - m_selected.erase(std::remove_if(m_selected.begin(), m_selected.end(), - [](const auto &selected) { - return selected;}), - m_selected.end()); - - m_selected_count = 0; - - assert(m_selected.size() == connectors.size()); - m_parent.set_as_dirty(); - return true; -} - -bool GLGizmoAdvancedCut::is_outside_of_cut_contour(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos) -{ - // check if connector pos is out of clipping plane - if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos)) { - m_info_stats.outside_cut_contour++; - return true; - } - - // check if connector bottom contour is out of clipping plane - const CutConnector & cur_connector = connectors[idx]; - const CutConnectorShape shape = CutConnectorShape(cur_connector.attribs.shape); - const int sectorCount = shape == CutConnectorShape::Triangle ? 3 : - shape == CutConnectorShape::Square ? 4 : - shape == CutConnectorShape::Circle ? 60: // supposably, 60 points are enough for conflict detection - shape == CutConnectorShape::Hexagon ? 6 : 1 ; - - indexed_triangle_set mesh; - auto & vertices = mesh.vertices; - vertices.reserve(sectorCount + 1); - - float fa = 2 * PI / sectorCount; - auto vec = Eigen::Vector2f(0, cur_connector.radius); - for (float angle = 0; angle < 2.f * PI; angle += fa) { - Vec2f p = Eigen::Rotation2Df(angle) * vec; - vertices.emplace_back(Vec3f(p(0), p(1), 0.f)); - } - - Transform3d transform = Transform3d::Identity(); - transform.translate(cur_pos); - its_transform(mesh, transform * m_rotate_matrix); - - for (auto vertex : vertices) { - if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(vertex.cast())) { - m_info_stats.outside_cut_contour++; - return true; - } - } - - return false; -} - -bool GLGizmoAdvancedCut::is_conflict_for_connector(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos) -{ - if (is_outside_of_cut_contour(idx, connectors, cur_pos)) - return true; - - const CutConnector &cur_connector = connectors[idx]; - - Transform3d translate_tf = Transform3d::Identity(); - translate_tf.translate(cur_pos); - Transform3d scale_tf = Transform3d::Identity(); - scale_tf.scale(Vec3f(cur_connector.radius, cur_connector.radius, cur_connector.height).cast()); - const Transform3d matrix = translate_tf * m_rotate_matrix * scale_tf; - - const BoundingBoxf3 cur_tbb = m_shapes[cur_connector.attribs].get_bounding_box().transformed(matrix); - - // check if connector's bounding box is inside the object's bounding box - if (!bounding_box().contains(cur_tbb)) { - m_info_stats.outside_bb++; - return true; - } - - // check if connectors are overlapping - for (size_t i = 0; i < connectors.size(); ++i) { - if (i == idx) continue; - const CutConnector &connector = connectors[i]; - - if ((connector.pos - cur_connector.pos).norm() < double(connector.radius + cur_connector.radius)) { - m_info_stats.is_overlap = true; - return true; - } - } - - return false; -} - -void GLGizmoAdvancedCut::check_conflict_for_all_connectors() -{ - const ModelObject *mo = m_c->selection_info()->model_object(); - auto inst_id = m_c->selection_info()->get_active_instance(); - if (inst_id < 0) - return; - - const CutConnectors &connectors = mo->cut_connectors; - const ModelInstance *mi = mo->instances[inst_id]; - const Vec3d & instance_offset = mi->get_offset(); - const double sla_shift = double(m_c->selection_info()->get_sla_shift()); - - m_has_invalid_connector = false; - m_info_stats.invalidate(); - - for (size_t i = 0; i < connectors.size(); ++i) { - const CutConnector &connector = connectors[i]; - - Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); - - // First decide about the color of the point. - const bool conflict_connector = is_conflict_for_connector(i, connectors, pos); - if (conflict_connector) { - m_has_invalid_connector = true; - } - } -} - -void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float bottom_limit) -{ - // float unit_size = m_imgui->get_style_scaling() * 48.0f; - float space_size = m_imgui->get_style_scaling() * 8; - float movement_cap = m_imgui->calc_text_size(_L("Movement:")).x; - float rotate_cap = m_imgui->calc_text_size(_L("Rotate")).x; - float caption_size = std::max(movement_cap, rotate_cap) + 2 * space_size; - bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; - unsigned int current_active_id = ImGui::GetActiveID(); - - Vec3d rotation = {Geometry::rad2deg(m_buffered_rotation(0)), Geometry::rad2deg(m_buffered_rotation(1)), Geometry::rad2deg(m_buffered_rotation(2))}; - char buf[3][64]; - float buf_size[3]; - float vec_max = 0, unit_size = 0; - for (int i = 0; i < 3; i++) { - ImGui::DataTypeFormatString(buf[i], IM_ARRAYSIZE(buf[i]), ImGuiDataType_Double, (void *) &rotation[i], "%.2f"); - buf_size[i] = ImGui::CalcTextSize(buf[i]).x; - vec_max = std::max(buf_size[i], vec_max); - } - - float buf_size_max = ImGui::CalcTextSize("-100.00").x; - if (vec_max < buf_size_max) { - unit_size = buf_size_max + ImGui::GetStyle().FramePadding.x * 2.0f; - } else { - unit_size = vec_max + ImGui::GetStyle().FramePadding.x * 2.0f; - } - - ImGui::PushItemWidth(caption_size); - ImGui::Dummy(ImVec2(caption_size, -1)); - ImGui::SameLine(caption_size + 1 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::TextAlignCenter("X"); - ImGui::SameLine(caption_size + 1 * unit_size + 2 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::TextAlignCenter("Y"); - ImGui::SameLine(caption_size + 2 * unit_size + 3 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::TextAlignCenter("Z"); - - ImGui::AlignTextToFramePadding(); - - // Rotation input box - ImGui::PushItemWidth(caption_size); - m_imgui->text(_L("Rotation") + " "); - ImGui::SameLine(caption_size + 1 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::BBLInputDouble("##cut_rotation_x", &rotation[0], 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(caption_size + 1 * unit_size + 2 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::BBLInputDouble("##cut_rotation_y", &rotation[1], 0.0f, 0.0f, "%.2f"); - ImGui::SameLine(caption_size + 2 * unit_size + 3 * space_size); - ImGui::PushItemWidth(unit_size); - ImGui::BBLInputDouble("##cut_rotation_z", &rotation[2], 0.0f, 0.0f, "%.2f"); - if (current_active_id != m_last_active_id) { - if (std::abs(Geometry::rad2deg(m_rotation(0)) - m_buffered_rotation(0)) > EPSILON || std::abs(Geometry::rad2deg(m_rotation(1)) - m_buffered_rotation(1)) > EPSILON || - std::abs(Geometry::rad2deg(m_rotation(2)) - m_buffered_rotation(2)) > EPSILON) { - m_rotation = m_buffered_rotation; - m_buffered_rotation.setZero(); - update_plane_points(); - m_parent.post_event(SimpleEvent(wxEVT_PAINT)); - } - } else { - m_buffered_rotation(0) = Geometry::deg2rad(rotation(0)); - m_buffered_rotation(1) = Geometry::deg2rad(rotation(1)); - m_buffered_rotation(2) = Geometry::deg2rad(rotation(2)); - } - - ImGui::Separator(); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4.0f, 10.0f)); - // Movement input box - double movement = m_movement; - ImGui::PushItemWidth(caption_size); - ImGui::AlignTextToFramePadding(); - m_imgui->text(_L("Movement") + " "); - ImGui::SameLine(caption_size + 1 * space_size); - ImGui::PushItemWidth(3 * unit_size + 2 * space_size); - ImGui::BBLInputDouble("##cut_movement", &movement, 0.0f, 0.0f, "%.2f"); - if (current_active_id != m_last_active_id) { - if (std::abs(m_buffered_movement - m_movement) > EPSILON) { - m_movement = m_buffered_movement; - m_buffered_movement = 0.0; - - // update absolute height - Vec3d plane_normal = get_plane_normal(); - m_height_delta = plane_normal(2) * m_movement; - m_height += m_height_delta; - m_buffered_height = m_height; - - update_plane_points(); - m_parent.post_event(SimpleEvent(wxEVT_PAINT)); - } - } else { - m_buffered_movement = movement; - } - - // height input box - double height = m_height; - ImGui::PushItemWidth(caption_size); - ImGui::AlignTextToFramePadding(); - // only allow setting height when cut plane is horizontal - Vec3d plane_normal = get_plane_normal(); - m_imgui->disabled_begin(std::abs(plane_normal(0)) > EPSILON || std::abs(plane_normal(1)) > EPSILON); - m_imgui->text(_L("Height") + " "); - ImGui::SameLine(caption_size + 1 * space_size); - ImGui::PushItemWidth(3 * unit_size + 2 * space_size); - ImGui::BBLInputDouble("##cut_height", &height, 0.0f, 0.0f, "%.2f"); - if (current_active_id != m_last_active_id) { - if (std::abs(m_buffered_height - m_height) > EPSILON) { - m_height_delta = m_buffered_height - m_height; - m_height = m_buffered_height; - update_plane_points(); - m_parent.post_event(SimpleEvent(wxEVT_PAINT)); - } - } else { - m_buffered_height = height; - } - ImGui::PopStyleVar(1); - m_imgui->disabled_end(); - - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - const bool has_connectors = !connectors.empty(); - - m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_cut_to_parts); - if (m_imgui->button(has_connectors ? _L("Edit connectors") : _L("Add connectors"))) set_connectors_editing(true); - m_imgui->disabled_end(); - - ImGui::Separator(); - - float label_width = 0; - for (const wxString& label : {_L("Upper part"), _L("Lower part")}) { - const float width = m_imgui->calc_text_size(label).x + m_imgui->scaled(1.5f); - if (label_width < width) - label_width = width; - } - - auto render_part_action_line = [this, label_width, &connectors](const wxString &label, const wxString &suffix, bool &keep_part, bool &place_on_cut_part, bool &rotate_part) { - bool keep = true; - ImGui::AlignTextToFramePadding(); - m_imgui->text(label); - - ImGui::SameLine(label_width); - - m_imgui->disabled_begin(!connectors.empty() || m_cut_to_parts); - m_imgui->bbl_checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep); - m_imgui->disabled_end(); - - ImGui::SameLine(); - - m_imgui->disabled_begin(!keep_part || m_cut_to_parts); - if (m_imgui->bbl_checkbox(_L("Place on cut") + suffix, place_on_cut_part)) - rotate_part = false; - ImGui::SameLine(); - if (m_imgui->bbl_checkbox(_L("Flip") + suffix, rotate_part)) - place_on_cut_part = false; - m_imgui->disabled_end(); - }; - - m_imgui->text(_L("After cut") + ": "); - render_part_action_line( _L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper); - render_part_action_line( _L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower); - - m_imgui->disabled_begin(has_connectors); - m_imgui->bbl_checkbox(_L("Cut to parts"), m_cut_to_parts); - if (m_cut_to_parts) { - m_keep_upper = true; - m_keep_lower = true; - } - m_imgui->disabled_end(); - -#if 0 - // Auto segment input - ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0); - m_imgui->checkbox(_L("Auto Segment"), m_do_segment); - m_imgui->disabled_begin(!m_do_segment); - ImGui::InputDouble("smoothing_alpha", &m_segment_smoothing_alpha, 0.0f, 0.0f, "%.2f"); - m_segment_smoothing_alpha = std::max(0.1, std::min(100.0, m_segment_smoothing_alpha)); - ImGui::InputInt("segment number", &m_segment_number); - m_segment_number = std::max(1, m_segment_number); - m_imgui->disabled_end(); - - ImGui::Separator(); -#endif - - // Cut button - m_imgui->disabled_begin(!can_perform_cut()); - if (m_imgui->button(_L("Perform cut"))) - perform_cut(m_parent.get_selection()); - m_imgui->disabled_end(); - ImGui::SameLine(); - const bool reset_clicked = m_imgui->button(_L("Reset")); - if (reset_clicked) { reset_all(); } - - m_last_active_id = current_active_id; -} - -void GLGizmoAdvancedCut::init_connectors_input_window_data() -{ - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - - float connectors_cap = m_imgui->calc_text_size(_L("Connectors")).x; - float type_cap = m_imgui->calc_text_size(_L("Type")).x; - float style_cap = m_imgui->calc_text_size(_L("Style")).x; - float shape_cap = m_imgui->calc_text_size(_L("Shape")).x; - float depth_ratio_cap = m_imgui->calc_text_size(_L("Depth ratio")).x; - float size_cap = m_imgui->calc_text_size(_L("Size")).x; - float max_lable_size = std::max(std::max(std::max(connectors_cap, type_cap), std::max(style_cap, shape_cap)), std::max(depth_ratio_cap, size_cap)); - - m_label_width = double(max_lable_size + 3 + ImGui::GetStyle().WindowPadding.x); - m_control_width = m_imgui->get_font_size() * 9.f; - - m_editing_window_width = 1.45 * m_control_width + 11; - - if (m_connectors_editing && m_selected_count > 0) { - float depth_ratio {UndefFloat}; - float depth_ratio_tolerance {UndefFloat}; - float radius {UndefFloat}; - float radius_tolerance {UndefFloat}; - CutConnectorType type{CutConnectorType::Undef}; - CutConnectorStyle style{CutConnectorStyle::Undef}; - CutConnectorShape shape{CutConnectorShape::Undef}; - - bool is_init = false; - for (size_t idx = 0; idx < m_selected.size(); idx++) - if (m_selected[idx]) { - const CutConnector &connector = connectors[idx]; - if (!is_init) { - depth_ratio = connector.height; - depth_ratio_tolerance = connector.height_tolerance; - radius = connector.radius; - radius_tolerance = connector.radius_tolerance; - type = connector.attribs.type; - style = connector.attribs.style; - shape = connector.attribs.shape; - - if (m_selected_count == 1) break; - is_init = true; - } else { - if (!is_approx(depth_ratio, connector.height)) - depth_ratio = UndefFloat; - if (!is_approx(depth_ratio_tolerance, connector.height_tolerance)) - depth_ratio_tolerance = UndefFloat; - if (!is_approx(radius, connector.radius)) - radius = UndefFloat; - if (!is_approx(radius_tolerance, connector.radius_tolerance)) - radius_tolerance = UndefFloat; - - if (type != connector.attribs.type) - type = CutConnectorType::Undef; - if (style != connector.attribs.style) - style = CutConnectorStyle::Undef; - if (shape != connector.attribs.shape) - shape = CutConnectorShape::Undef; - } - } - - m_connector_depth_ratio = depth_ratio; - m_connector_depth_ratio_tolerance = depth_ratio_tolerance; - m_connector_size = 2.f * radius; - m_connector_size_tolerance = radius_tolerance; - m_connector_type = type; - m_connector_style = size_t(style); - m_connector_shape_id = size_t(shape); - } -} - -void GLGizmoAdvancedCut::render_connectors_input_window(float x, float y, float bottom_limit) -{ - CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors; - - // update when change input window - m_imgui->set_requires_extra_frame(); - - ImGui::AlignTextToFramePadding(); - m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, _L("Connectors")); - - m_imgui->disabled_begin(connectors.empty()); - ImGui::SameLine(m_label_width); - if (render_reset_button("connectors", _u8L("Remove connectors"))) - reset_connectors(); - m_imgui->disabled_end(); - - m_imgui->text(_L("Type")); - ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.00f, 0.00f, 0.00f, 1.00f)); - bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug); - type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel); - if (type_changed) - apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.type = CutConnectorType(m_connector_type); }); - ImGui::PopStyleColor(1); - - std::vector connector_styles = {_u8L("Prizm"), _u8L("Frustum")}; - std::vector connector_shapes = { _u8L("Triangle"), _u8L("Square"), _u8L("Hexagon"), _u8L("Circle") }; - - m_imgui->disabled_begin(m_connector_type == CutConnectorType::Dowel); - if (type_changed && m_connector_type == CutConnectorType::Dowel) { - m_connector_style = size_t(CutConnectorStyle::Prizm); - apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); - } - - ImGuiWrapper::push_combo_style(m_parent.get_scale()); - if (render_combo(_u8L("Style"), connector_styles, m_connector_style)) - apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); }); - m_imgui->disabled_end(); - ImGuiWrapper::pop_combo_style(); - - ImGuiWrapper::push_combo_style(m_parent.get_scale()); - if (render_combo(_u8L("Shape"), connector_shapes, m_connector_shape_id)) - apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); }); - ImGuiWrapper::pop_combo_style(); - - if (render_slider_double_input(_u8L("Depth ratio"), m_connector_depth_ratio, m_connector_depth_ratio_tolerance)) - apply_selected_connectors([this, &connectors](size_t idx) { - if (m_connector_depth_ratio > 0) - connectors[idx].height = m_connector_depth_ratio; - if (m_connector_depth_ratio_tolerance >= 0) - connectors[idx].height_tolerance = m_connector_depth_ratio_tolerance; - }); - - if (render_slider_double_input(_u8L("Size"), m_connector_size, m_connector_size_tolerance)) - apply_selected_connectors([this, &connectors](size_t idx) { - if (m_connector_size > 0) - connectors[idx].radius = 0.5f * m_connector_size; - if (m_connector_size_tolerance >= 0) - connectors[idx].radius_tolerance = m_connector_size_tolerance; - }); - - ImGui::Separator(); - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); - float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; - show_tooltip_information(x, get_cur_y); - - float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); - - ImGui::SameLine(); - if (m_imgui->button(_L("Confirm connectors"))) { - unselect_all_connectors(); - set_connectors_editing(false); - } - - ImGui::SameLine(m_label_width + m_editing_window_width - m_imgui->calc_text_size(_L("Cancel")).x - m_imgui->get_style_scaling() * 8); - - if (m_imgui->button(_L("Cancel"))) { - reset_connectors(); - set_connectors_editing(false); - } - - ImGui::PopStyleVar(2); -} - -void GLGizmoAdvancedCut::render_input_window_warning() const -{ - if (m_has_invalid_connector) { - wxString out = /*wxString(ImGui::WarningMarkerSmall)*/ _L("Warning") + ": " + _L("Invalid connectors detected") + ":"; - if (m_info_stats.outside_cut_contour > size_t(0)) - out += "\n - " + std::to_string(m_info_stats.outside_cut_contour) + - (m_info_stats.outside_cut_contour == 1 ? _L("connector is out of cut contour") : _L("connectors are out of cut contour")); - if (m_info_stats.outside_bb > size_t(0)) - out += "\n - " + std::to_string(m_info_stats.outside_bb) + - (m_info_stats.outside_bb == 1 ? _L("connector is out of object") : _L("connectors is out of object")); - if (m_info_stats.is_overlap) - out += "\n - " + _L("Some connectors are overlapped"); - m_imgui->text(out); - } - if (!m_keep_upper && !m_keep_lower) m_imgui->text(/*wxString(ImGui::WarningMarkerSmall)*/_L("Warning") + ": " + _L("Invalid state. \nNo one part is selected for keep after cut")); -} - -bool GLGizmoAdvancedCut::render_reset_button(const std::string &label_id, const std::string &tooltip) const -{ - const ImGuiStyle &style = ImGui::GetStyle(); - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {1, style.ItemSpacing.y}); - - ImGui::PushStyleColor(ImGuiCol_Button, {0.25f, 0.25f, 0.25f, 0.0f}); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, {0.4f, 0.4f, 0.4f, 1.0f}); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, {0.4f, 0.4f, 0.4f, 1.0f}); - - bool revert = m_imgui->button(wxString(ImGui::RevertBtn)); - - ImGui::PopStyleColor(3); - - if (ImGui::IsItemHovered()) - m_imgui->tooltip(tooltip.c_str(), ImGui::GetFontSize() * 20.0f); - - ImGui::PopStyleVar(); - - return revert; -} - -bool GLGizmoAdvancedCut::render_connect_type_radio_button(CutConnectorType type) -{ - ImGui::SameLine(type == CutConnectorType::Plug ? m_label_width : 2 * m_label_width); - ImGui::PushItemWidth(m_control_width); - - wxString radio_name; - switch (type) { - case CutConnectorType::Plug: - radio_name = _L("Plug"); - break; - case CutConnectorType::Dowel: - radio_name = _L("Dowel"); - break; - default: - break; - } - - if (m_imgui->radio_button(radio_name, m_connector_type == type)) { - m_connector_type = type; - update_connector_shape(); - return true; - } - return false; -} - -bool GLGizmoAdvancedCut::render_combo(const std::string &label, const std::vector &lines, size_t &selection_idx) -{ - ImGui::AlignTextToFramePadding(); - m_imgui->text(label); - ImGui::SameLine(m_label_width); - ImGui::PushItemWidth(m_editing_window_width); - - size_t selection_out = selection_idx; - - const char* selected_str = (selection_idx >= 0 && selection_idx < int(lines.size())) ? lines[selection_idx].c_str() : ""; - if (ImGui::BBLBeginCombo(("##" + label).c_str(), selected_str, 0)) { - for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) { - ImGui::PushID(int(line_idx)); - if (ImGui::Selectable("", line_idx == selection_idx)) - selection_out = line_idx; - - ImGui::SameLine(); - ImGui::Text("%s", lines[line_idx].c_str()); - ImGui::PopID(); - } - - ImGui::EndCombo(); - } - - bool is_changed = selection_idx != selection_out; - selection_idx = selection_out; - - if (is_changed) update_connector_shape(); - - return is_changed; -} - -bool GLGizmoAdvancedCut::render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in) -{ - // -------- [ ] -------- [ ] - // slider_with + item_in_gap + first_input_width + item_out_gap + slider_with + item_in_gap + second_input_width - double slider_with = 0.24 * m_editing_window_width; // m_control_width * 0.35; - double item_in_gap = 0.01 * m_editing_window_width; - double item_out_gap = 0.04 * m_editing_window_width; - double first_input_width = 0.37 * m_editing_window_width; - double second_input_width = 0.37 * m_editing_window_width; -#ifdef __APPLE__ - first_input_width = 0.5 * m_editing_window_width; - second_input_width = 0.5 * m_editing_window_width; -#endif - ImGui::AlignTextToFramePadding(); - m_imgui->text(label); - ImGui::SameLine(m_label_width); - ImGui::PushItemWidth(slider_with); - - double left_width = m_label_width + slider_with + item_in_gap; - - bool m_imperial_units = false; - - float value = value_in; - if (m_imperial_units) value *= float(units_mm_to_in); - float old_val = value; - - constexpr float UndefMinVal = -0.1f; - - const BoundingBoxf3 bbox = bounding_box(); - float mean_size = float((bbox.size().x() + bbox.size().y() + bbox.size().z()) / 9.0); - float min_size = value_in < 0.f ? UndefMinVal : 2.f; - if (m_imperial_units) { - mean_size *= float(units_mm_to_in); - min_size *= float(units_mm_to_in); - } - std::string format = value_in < 0.f ? " " : m_imperial_units ? "%.4f " + _u8L_CONTEXT("in", "inches") : "%.2f " + _u8L("mm"); - - m_imgui->bbl_slider_float_style(("##" + label).c_str(), &value, min_size, mean_size, format.c_str()); - - ImGui::SameLine(left_width); - ImGui::PushItemWidth(first_input_width); - ImGui::BBLDragFloat(("##input_" + label).c_str(), &value, 0.05f, min_size, mean_size, format.c_str()); - - value_in = value * float(m_imperial_units ? units_in_to_mm : 1.0); - - left_width += (first_input_width + item_out_gap); - ImGui::SameLine(left_width); - ImGui::PushItemWidth(slider_with); - - float tolerance = tolerance_in; - if (m_imperial_units) - tolerance *= float(units_mm_to_in); - float old_tolerance = tolerance; - //std::string format_t = tolerance_in < 0.f ? " " : "%.f %%"; - float min_tolerance = tolerance_in < 0.f ? UndefMinVal : 0.f; - - m_imgui->bbl_slider_float_style(("##tolerance_" + label).c_str(), &tolerance, min_tolerance, 2.f, format.c_str(), 1.f, true, _L("Tolerance")); - - left_width += (slider_with + item_in_gap); - ImGui::SameLine(left_width); - ImGui::PushItemWidth(second_input_width); - ImGui::BBLDragFloat(("##tolerance_input_" + label).c_str(), &tolerance, 0.05f, min_tolerance, 2.f, format.c_str()); - - tolerance_in = tolerance * float(m_imperial_units ? units_in_to_mm : 1.0); - - return !is_approx(old_val, value) || !is_approx(old_tolerance, tolerance); -} - -bool GLGizmoAdvancedCut::cut_line_processing() const -{ - return m_cut_line_begin != Vec3d::Zero(); -} - -void GLGizmoAdvancedCut::discard_cut_line_processing() -{ - m_cut_line_begin = m_cut_line_end = Vec3d::Zero(); -} - -bool GLGizmoAdvancedCut::process_cut_line(SLAGizmoEventType action, const Vec2d &mouse_position) -{ - const Camera &camera = wxGetApp().plater()->get_camera(); - - Vec3d pt; - Vec3d dir; - CameraUtils::ray_from_screen_pos(camera, mouse_position, pt, dir); - dir.normalize(); - pt += dir; // Move the pt along dir so it is not clipped. - - if (action == SLAGizmoEventType::LeftDown && !cut_line_processing()) { - m_cut_line_begin = pt; - m_cut_line_end = pt; - return true; - } - - if (cut_line_processing()) { - m_cut_line_end = pt; - if (action == SLAGizmoEventType::LeftDown || action == SLAGizmoEventType::LeftUp) { - Vec3d line_dir = m_cut_line_end - m_cut_line_begin; - if (line_dir.norm() < 3.0) - return true; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Cut by line"); - - Vec3d cross_dir = line_dir.cross(dir).normalized(); - Eigen::Quaterniond q; - Transform3d m = Transform3d::Identity(); - m.matrix().block(0, 0, 3, 3) = q.setFromTwoVectors(m_cut_plane_normal, cross_dir).toRotationMatrix(); - - m_rotate_matrix = m; - - const ModelObject * mo = m_c->selection_info()->model_object(); - const ModelInstance *mi = mo->instances[m_c->selection_info()->get_active_instance()]; - Vec3d plane_center = get_plane_center(); - - auto update_plane_after_line_cut = [this](const Vec3d &deta_plane_center, const Transform3d& rotate_matrix) { - Vec3d plane_center = get_plane_center(); - - std::array plane_points_rot; - for (int i = 0; i < plane_points_rot.size(); i++) { - plane_points_rot[i] = m_cut_plane_points[i] - plane_center; - } - - for (uint32_t i = 0; i < plane_points_rot.size(); ++i) { - plane_points_rot[i] = rotate_matrix * plane_points_rot[i]; - } - - for (int i = 0; i < plane_points_rot.size(); i++) { - m_cut_plane_points[i] = plane_points_rot[i] + plane_center + deta_plane_center; - } - }; - - update_plane_after_line_cut(cross_dir * (cross_dir.dot(pt - m_cut_plane_center)), m_rotate_matrix); - - discard_cut_line_processing(); - } else if (action == SLAGizmoEventType::Dragging) - this->set_dirty(); - return true; - } - return false; -} - -} // namespace GUI -} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp deleted file mode 100644 index d791663ea9..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp +++ /dev/null @@ -1,222 +0,0 @@ -#ifndef slic3r_GLGizmoAdvancedCut_hpp_ -#define slic3r_GLGizmoAdvancedCut_hpp_ - -#include "GLGizmoBase.hpp" -#include "GLGizmoRotate.hpp" -#include "libslic3r/Model.hpp" - -namespace Slic3r { -enum class CutConnectorType : int; -class ModelVolume; -struct CutConnectorAttributes; - -namespace GUI { -enum class SLAGizmoEventType : unsigned char; - -class GLGizmoAdvancedCut : public GLGizmoRotate3D -{ -struct Rotate_data { - double angle; - Axis ax; - - Rotate_data(double an, Axis a) - : angle(an), ax(a) - { - } -}; -private: - static const double Offset; - static const double Margin; - static const ColorRGBA GrabberColor; - static const ColorRGBA GrabberHoverColor; - - mutable double m_movement; - mutable double m_height; // height of cut plane to heatbed - mutable double m_height_delta; // height of cut plane to heatbed - double m_start_movement; - double m_start_height; - - Vec3d m_rotation; - //Vec3d m_current_base_rotation; - std::vector m_rotate_cmds; - - Vec3d m_buffered_rotation; - double m_buffered_movement; - double m_buffered_height; - - Vec3d m_drag_pos; - - bool m_keep_upper; - bool m_keep_lower; - bool m_cut_to_parts; - bool m_place_on_cut_upper{true}; - bool m_place_on_cut_lower{false}; - bool m_rotate_upper{false}; - bool m_rotate_lower{false}; - GLModel m_plane; - GLModel m_grabber_connection; - GLModel m_cut_line; - - bool m_do_segment; - double m_segment_smoothing_alpha; - int m_segment_number; - - std::array m_cut_plane_points; - - mutable Grabber m_move_grabber; - - unsigned int m_last_active_id; - - bool m_connectors_editing{false}; - bool m_show_shortcuts{false}; - - std::vector> m_shortcuts; - double m_label_width{150.0}; - double m_control_width{ 200.0 }; - double m_editing_window_width; - - CutConnectorType m_connector_type; - size_t m_connector_style; - size_t m_connector_shape_id; - - float m_connector_depth_ratio{3.f}; - float m_connector_depth_ratio_tolerance{0.1f}; - - float m_connector_size{2.5f}; - float m_connector_size_tolerance{0.f}; - - TriangleMesh m_connector_mesh; - bool m_has_invalid_connector{false}; - - // remember the connectors which is selected - mutable std::vector m_selected; - int m_selected_count{0}; - - Vec3d m_cut_plane_center{Vec3d::Zero()}; - Vec3d m_cut_plane_normal{Vec3d::UnitZ()}; - - Vec3d m_cut_line_begin{Vec3d::Zero()}; - Vec3d m_cut_line_end{Vec3d::Zero()}; - - Transform3d m_rotate_matrix{Transform3d::Identity()}; - - std::map m_shapes; - - struct InvalidConnectorsStatistics - { - unsigned int outside_cut_contour; - unsigned int outside_bb; - bool is_overlap; - - void invalidate() - { - outside_cut_contour = 0; - outside_bb = 0; - is_overlap = false; - } - } m_info_stats; - - //GLSelectionRectangle m_selection_rectangle; - -public: - GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - - bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down); - bool on_key(wxKeyEvent &evt); - - double get_movement() const { return m_movement; } - void set_movement(double movement) const; - void finish_rotation(); - std::string get_tooltip() const override; - - BoundingBoxf3 bounding_box() const; - //BoundingBoxf3 transformed_bounding_box(const Vec3d &plane_center, bool revert_move = false) const; - - bool is_looking_forward() const; - - bool unproject_on_cut_plane(const Vec2d &mouse_pos, Vec3d &pos, Vec3d &pos_world); - - virtual bool apply_clipping_plane() { return m_connectors_editing; } - - void data_changed(bool is_serializing) override; - -protected: - bool on_init() override; - void on_load(cereal::BinaryInputArchive &ar) override; - void on_save(cereal::BinaryOutputArchive &ar) const override; - std::string on_get_name() const override; - void on_set_state() override; - bool on_is_activable() const override; - CommonGizmosDataID on_get_requirements() const override; - void on_start_dragging() override; - void on_stop_dragging() override; - void on_dragging(const UpdateData& data) override; - void on_render() override; - virtual void on_render_input_window(float x, float y, float bottom_limit); - - void show_tooltip_information(float x, float y); - -private: - void perform_cut(const Selection& selection); - bool can_perform_cut() const; - void apply_connectors_in_model(ModelObject *mo, bool &create_dowels_as_separate_object); - - bool is_selection_changed(bool alt_down, bool shift_down); - void select_connector(int idx, bool select); - - double calc_projection(const Linef3& mouse_ray) const; - Vec3d calc_plane_normal(const std::array& plane_points) const; - Vec3d calc_plane_center(const std::array& plane_points) const; - Vec3d get_plane_normal() const; - Vec3d get_plane_center() const; - void update_plane_points(); - std::array get_plane_points() const; - std::array get_plane_points_world_coord() const; - void reset_cut_plane(); - void reset_all(); - - // update the connectors position so that the connectors are on the cut plane - void put_connectors_on_cut_plane(const Vec3d &cp_normal, double cp_offset); - void update_clipper(); - // on render - void render_cut_plane_and_grabbers(); - void render_connectors(); - void render_clipper_cut(); - void render_cut_line(); - void render_connector_model(GLModel &model, const ColorRGBA& color, Transform3d model_matrix, bool for_picking = false); - - void clear_selection(); - void init_connector_shapes(); - void set_connectors_editing(bool connectors_editing); - void reset_connectors(); - void update_connector_shape(); - void apply_selected_connectors(std::function apply_fn); - void select_all_connectors(); - void unselect_all_connectors(); - void validate_connector_settings(); - bool add_connector(CutConnectors &connectors, const Vec2d &mouse_position); - bool delete_selected_connectors(); - bool is_outside_of_cut_contour(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos); - bool is_conflict_for_connector(size_t idx, const CutConnectors &connectors, const Vec3d cur_pos); - void check_conflict_for_all_connectors(); - - // render input window - void render_cut_plane_input_window(float x, float y, float bottom_limit); - void init_connectors_input_window_data(); - void render_connectors_input_window(float x, float y, float bottom_limit); - void render_input_window_warning() const; - bool render_reset_button(const std::string &label_id, const std::string &tooltip) const; - bool render_connect_type_radio_button(CutConnectorType type); - - bool render_combo(const std::string &label, const std::vector &lines, size_t &selection_idx); - bool render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in); - - bool cut_line_processing() const; - void discard_cut_line_processing(); - bool process_cut_line(SLAGizmoEventType action, const Vec2d &mouse_position); -}; - -} // namespace GUI -} // namespace Slic3r - -#endif // slic3r_GLGizmoAdvancedCut_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp deleted file mode 100644 index 1cec89387b..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "GLGizmoFaceDetector.hpp" - -#include "libslic3r/Model.hpp" -#include "libslic3r/SLA/IndexedMesh.hpp" -#include "libslic3r/FaceDetector.hpp" - -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/ImGuiWrapper.hpp" -#include "slic3r/GUI/Plater.hpp" - -#include - -#ifdef __WINDOWS__ -#include -#include -#endif - -namespace Slic3r { - -namespace GUI { - -bool GLGizmoFaceDetector::on_init() -{ - return true; -} - -std::string GLGizmoFaceDetector::on_get_name() const -{ - return (_L("Face recognition") + " [P]").ToUTF8().data(); -} - -void GLGizmoFaceDetector::on_render() -{ - if (model.is_initialized()) { - model.set_color({0.f, 0.f, 1.f, 0.4f}); - model.render(); - } -} - -void GLGizmoFaceDetector::on_render_input_window(float x, float y, float bottom_limit) -{ -#if 0 - if (!m_c->selection_info() || !m_c->selection_info()->model_object()) - return; - - const float approx_height = m_imgui->scaled(14.0f); - y = std::min(y, bottom_limit - approx_height); - //BBS: GUI refactor: move gizmo to the right -#if BBS_TOOLBAR_ON_TOP - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always, 0.5f, 0.0f); -#else - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always, 1.0f, 0.0f); -#endif - - ImGuiWrapper::push_toolbar_style(); - m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - - ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150); - ImGui::InputDouble("Sample interval", &m_sample_interval, 0.0f, 0.0f, "%.2f"); - - bool btn_clicked = m_imgui->button(_L("Perform Recognition")); - if (btn_clicked) { - perform_recognition(m_parent.get_selection()); - } - - m_imgui->end(); - ImGuiWrapper::pop_toolbar_style(); -#endif -} - -void GLGizmoFaceDetector::on_set_state() -{ - if (get_state() == On) { - model.reset(); - display_exterior_face(); - } -} - -bool GLGizmoFaceDetector::on_is_activable() const -{ - const Selection& selection = m_parent.get_selection(); - return selection.is_single_full_instance() && !selection.is_wipe_tower(); -} - -void GLGizmoFaceDetector::perform_recognition(const Selection& selection) -{ - ModelObject* mo = m_c->selection_info()->model_object(); - //FaceDetector face_detector(mo, m_sample_interval); - - //face_detector.detect_exterior_face(); -} - -void GLGizmoFaceDetector::display_exterior_face() -{ - int cnt = 0; - model.reset(); - - GLModel::Geometry init_data; - init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; - - const ModelObjectPtrs& objects = wxGetApp().model().objects; - for (ModelObject* mo : objects) { - const ModelInstance* mi = mo->instances[0]; - Transform3d inst_transfo = mi->get_matrix(); - for (ModelVolume* mv : mo->volumes) { - TriangleMesh mesh_temp = mv->mesh(); - mesh_temp.transform(mv->get_matrix() * inst_transfo); - indexed_triangle_set& mv_its = mesh_temp.its; - for (int facet_idx = 0; facet_idx < mv_its.indices.size(); facet_idx++) { - const stl_triangle_vertex_indices& facet_vert_idxs = mv_its.indices[facet_idx]; - if (mv_its.get_property(facet_idx).type != eExteriorAppearance) - continue; - - for (int i = 0; i < 3; ++i) { - init_data.add_vertex((Vec3f) mv_its.vertices[facet_vert_idxs[i]].cast(), Vec3f{0.0f, 0.0f, 1.0f}); - } - - init_data.add_uint_triangle(cnt, cnt + 1, cnt + 2); - cnt += 3; - } - } - } - model.init_from(std::move(init_data)); -} - -CommonGizmosDataID GLGizmoFaceDetector::on_get_requirements() const -{ - return CommonGizmosDataID::SelectionInfo; -} - -} // namespace GUI -} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp deleted file mode 100644 index c028a3f2b2..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef slic3r_GLGizmoFaceDetector_hpp_ -#define slic3r_GLGizmoFaceDetector_hpp_ - -#include "GLGizmoBase.hpp" -#include "slic3r/GUI/3DScene.hpp" - -namespace Slic3r { - -namespace GUI { - -class GLGizmoFaceDetector : public GLGizmoBase -{ -public: - GLGizmoFaceDetector(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) {} - -protected: - void on_render() override; - void on_render_for_picking() override {} - void on_render_input_window(float x, float y, float bottom_limit) override; - std::string on_get_name() const override; - void on_set_state() override; - bool on_is_activable() const override; - CommonGizmosDataID on_get_requirements() const override; - -private: - bool on_init() override; - void perform_recognition(const Selection& selection); - void display_exterior_face(); - - GUI::GLModel model; - double m_sample_interval = {0.5}; -}; - -} // namespace GUI -} // namespace Slic3r - - -#endif // slic3r_GLGizmoFaceDetector_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp deleted file mode 100644 index e5c6502452..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ /dev/null @@ -1,872 +0,0 @@ -#include "GLGizmoHollow.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Camera.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" - -#include - -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/GUI_ObjectSettings.hpp" -#include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "libslic3r/PresetBundle.hpp" - -#include "libslic3r/Model.hpp" - - -namespace Slic3r { -namespace GUI { - -GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) -{ -} - - -bool GLGizmoHollow::on_init() -{ - m_desc["enable"] = _(L("Hollow this object")); - m_desc["preview"] = _(L("Preview hollowed and drilled model")); - m_desc["offset"] = _(L("Offset")) + ": "; - m_desc["quality"] = _(L("Quality")) + ": "; - m_desc["closing_distance"] = _(L("Closing distance")) + ": "; - m_desc["hole_diameter"] = _(L("Hole diameter")) + ": "; - m_desc["hole_depth"] = _(L("Hole depth")) + ": "; - m_desc["remove_selected"] = _(L("Remove selected holes")); - m_desc["remove_all"] = _(L("Remove all holes")); - m_desc["clipping_of_view"] = _(L("Clipping of view"))+ ": "; - m_desc["reset_direction"] = _(L("Reset direction")); - m_desc["show_supports"] = _(L("Show supports")); - - return true; -} - -void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) -{ - if (! m_c->selection_info()) - return; - - const ModelObject* mo = m_c->selection_info()->model_object(); - if (m_state == On && mo) { - if (m_old_mo_id != mo->id()) { - reload_cache(); - m_old_mo_id = mo->id(); - } - if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) - m_holes_in_drilled_mesh = mo->sla_drain_holes; - } -} - - - -void GLGizmoHollow::on_render() -{ - if (!m_cylinder.is_initialized()) - m_cylinder.init_from(its_make_cylinder(1.0, 1.0)); - - const Selection& selection = m_parent.get_selection(); - const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); - - // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off - if (m_state == On - && (sel_info->model_object() != selection.get_model()->objects[selection.get_object_idx()] - || sel_info->get_active_instance() != selection.get_instance_idx())) { - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); - return; - } - - glsafe(::glEnable(GL_BLEND)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - if (selection.is_from_single_instance()) - render_points(selection, false); - - m_selection_rectangle.render(m_parent); - m_c->object_clipper()->render_cut(); - m_c->supports_clipper()->render_cut(); - - glsafe(::glDisable(GL_BLEND)); -} - -void GLGizmoHollow::render_points(const Selection& selection, bool picking) -{ - GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - - shader->start_using(); - ScopeGuard guard([shader]() { shader->stop_using(); }); - - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); - const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * vol->get_instance_transformation().get_matrix(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - - shader->set_uniform("projection_matrix", projection_matrix); - - ColorRGBA render_color; - const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - const size_t cache_size = drain_holes.size(); - - for (size_t i = 0; i < cache_size; ++i) { - const sla::DrainHole& drain_hole = drain_holes[i]; - const bool point_selected = m_selected[i]; - - if (is_mesh_point_clipped(drain_hole.pos.cast())) - continue; - - // First decide about the color of the point. - if (picking) - render_color = picking_color_component(i); - else { - if (size_t(m_hover_id) == i) - render_color = ColorRGBA::CYAN(); - else if (m_c->hollowed_mesh() && - i < m_c->hollowed_mesh()->get_drainholes().size() && - m_c->hollowed_mesh()->get_drainholes()[i].failed) { - render_color = { 1.0f, 0.0f, 0.0f, 0.5f }; - } - 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); - } - - m_cylinder.set_color(render_color); - - // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast()) * instance_scaling_matrix_inverse; - - if (vol->is_left_handed()) - glFrontFace(GL_CW); - - // Matrices set, we can render the point mark now. - Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); - const Eigen::AngleAxisd aa(q); - const Transform3d model_matrix = instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * - Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.render(); - - if (vol->is_left_handed()) - glFrontFace(GL_CCW); - } -} - -bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const -{ - if (m_c->object_clipper()->get_position() == 0.) - return false; - - auto sel_info = m_c->selection_info(); - int active_inst = m_c->selection_info()->get_active_instance(); - const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; - const Transform3d& trafo = mi->get_transformation().get_matrix(); - - Vec3d transformed_point = trafo * point; - transformed_point(2) += sel_info->get_sla_shift(); - return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); -} - - - -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) -{ - if (! m_c->raycaster()->raycaster()) - return false; - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = volume->get_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); - - double clp_dist = m_c->object_clipper()->get_position(); - const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); - - // The raycaster query - Vec3f hit; - Vec3f normal; - if (m_c->raycaster()->raycaster()->unproject_on_mesh( - mouse_pos, - trafo.get_matrix(), - camera, - hit, - normal, - clp_dist != 0. ? clp : nullptr)) - { - if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) { - // in this case the raycaster sees the hollowed and drilled mesh. - // if the point lies on the surface created by the hole, we want - // to ignore it. - for (const sla::DrainHole& hole : m_holes_in_drilled_mesh) { - sla::DrainHole outer(hole); - outer.radius *= 1.001f; - outer.height *= 1.001f; - if (outer.is_inside(hit)) - return false; - } - } - - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit, normal); - return true; - } - else - return false; -} - -// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. -// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is -// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo -// 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) -{ - ModelObject* mo = m_c->selection_info()->model_object(); - int active_inst = m_c->selection_info()->get_active_instance(); - - - // left down with shift - show the selection rectangle: - if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { - if (m_hover_id == -1) { - if (shift_down || alt_down) { - m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); - } - } - else { - if (m_selected[m_hover_id]) - unselect_point(m_hover_id); - else { - if (!alt_down) - select_point(m_hover_id); - } - } - - return true; - } - - // left down without selection rectangle - place point on the mesh: - if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_dragging() && !shift_down) { - // If any point is in hover state, this should initiate its move - return control back to GLCanvas: - if (m_hover_id != -1) - return false; - - // If there is some selection, don't add new point and deselect everything instead. - if (m_selection_empty) { - std::pair pos_and_normal; - if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Add drainage hole"); - - mo->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() == mo->sla_drain_holes.size()); - m_parent.set_as_dirty(); - m_wait_for_up_event = true; - } - else - return false; - } - else - select_point(NoPoints); - - return true; - } - - // left up with selection rectangle - select points inside the rectangle: - if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { - // Is this a selection or deselection rectangle? - GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); - - // First collect positions of all the points in world coordinates. - Geometry::Transformation trafo = mo->instances[active_inst]->get_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); - std::vector points; - for (unsigned int i=0; isla_drain_holes.size(); ++i) - points.push_back(trafo.get_matrix() * mo->sla_drain_holes[i].pos.cast()); - - // Now ask the rectangle which of the points are inside. - std::vector points_inside; - std::vector points_idxs = m_selection_rectangle.stop_dragging(m_parent, points); - for (size_t idx : points_idxs) - points_inside.push_back(points[idx].cast()); - - // Only select/deselect points that are actually visible - for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs( - trafo, wxGetApp().plater()->get_camera(), points_inside, - m_c->object_clipper()->get_clipping_plane())) - { - if (rectangle_status == GLSelectionRectangle::Deselect) - unselect_point(points_idxs[idx]); - else - select_point(points_idxs[idx]); - } - return true; - } - - // left up with no selection rectangle - if (action == SLAGizmoEventType::LeftUp) { - if (m_wait_for_up_event) { - m_wait_for_up_event = false; - } - return true; - } - - // dragging the selection rectangle: - if (action == SLAGizmoEventType::Dragging) { - if (m_wait_for_up_event) - return true; // point has been placed and the button not released yet - // this prevents GLCanvas from starting scene rotation - - if (m_selection_rectangle.is_dragging()) { - m_selection_rectangle.dragging(mouse_position); - return true; - } - - return false; - } - - if (action == SLAGizmoEventType::Delete) { - // delete key pressed - delete_selected_points(); - return true; - } - - if (action == SLAGizmoEventType::RightDown) { - if (m_hover_id != -1) { - select_point(NoPoints); - select_point(m_hover_id); - delete_selected_points(); - return true; - } - return false; - } - - if (action == SLAGizmoEventType::SelectAll) { - select_point(AllPoints); - return true; - } - - if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); - return true; - } - - if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::max(0., pos - 0.01); - m_c->object_clipper()->set_position(pos, true); - return true; - } - - if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); - return true; - } - - return false; -} - -void GLGizmoHollow::delete_selected_points() -{ - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Delete drainage hole"); - sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - - for (unsigned int idx=0; idxselection_info()->model_object()->sla_drain_holes; - - if (m_hover_id != -1) { - std::pair pos_and_normal; - if (! unproject_on_mesh(data.mouse_pos.cast(), pos_and_normal)) - return; - drain_holes[m_hover_id].pos = pos_and_normal.first; - drain_holes[m_hover_id].normal = -pos_and_normal.second; - } -} - - -void GLGizmoHollow::hollow_mesh(bool postpone_error_messages) -{ - wxGetApp().CallAfter([this, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_hollowing( - *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - - -std::vector> -GLGizmoHollow::get_config_options(const std::vector& keys) const -{ - std::vector> out; - const ModelObject* mo = m_c->selection_info()->model_object(); - - if (! mo) - return out; - - const DynamicPrintConfig& object_cfg = mo->config.get(); - const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; - std::unique_ptr default_cfg = nullptr; - - for (const std::string& key : keys) { - if (object_cfg.has(key)) - out.emplace_back(object_cfg.option(key), &object_cfg.def()->options.at(key)); // at() needed for const map - else - if (print_cfg.has(key)) - out.emplace_back(print_cfg.option(key), &print_cfg.def()->options.at(key)); - else { // we must get it from defaults - if (default_cfg == nullptr) - default_cfg.reset(DynamicPrintConfig::new_from_defaults_keys(keys)); - out.emplace_back(default_cfg->option(key), &default_cfg->def()->options.at(key)); - } - } - - return out; -} - - -void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit) -{ - ModelObject* mo = m_c->selection_info()->model_object(); - if (! mo) - return; - - 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. - - ConfigOptionMode current_mode = wxGetApp().get_mode(); - - std::vector opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"}; - auto opts = get_config_options(opts_keys); - auto* offset_cfg = static_cast(opts[0].first); - float offset = offset_cfg->value; - double offset_min = opts[0].second->min; - double offset_max = opts[0].second->max; - - auto* quality_cfg = static_cast(opts[1].first); - float quality = quality_cfg->value; - double quality_min = opts[1].second->min; - double quality_max = opts[1].second->max; - ConfigOptionMode quality_mode = opts[1].second->mode; - - auto* closing_d_cfg = static_cast(opts[2].first); - float closing_d = closing_d_cfg->value; - double closing_d_min = opts[2].second->min; - double closing_d_max = opts[2].second->max; - ConfigOptionMode closing_d_mode = opts[2].second->mode; - - m_desc["offset"] = _(opts[0].second->label) + ":"; - m_desc["quality"] = _(opts[1].second->label) + ":"; - m_desc["closing_distance"] = _(opts[2].second->label) + ":"; - - -RENDER_AGAIN: - const float approx_height = m_imgui->scaled(20.0f); - y = std::min(y, bottom_limit - approx_height); - m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - - m_imgui->begin(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 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(0.5f); - - const float settings_sliders_left = - std::max(std::max({m_imgui->calc_text_size(m_desc.at("offset")).x, - m_imgui->calc_text_size(m_desc.at("quality")).x, - m_imgui->calc_text_size(m_desc.at("closing_distance")).x, - m_imgui->calc_text_size(m_desc.at("hole_diameter")).x, - m_imgui->calc_text_size(m_desc.at("hole_depth")).x}) + m_imgui->scaled(0.5f), clipping_slider_left); - - const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f); - const float minimal_slider_width = m_imgui->scaled(4.f); - - const float button_preview_width = m_imgui->calc_button_size(m_desc.at("preview")).x; - - float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left}); - window_width = std::max(window_width, button_preview_width); - - if (m_imgui->button(m_desc["preview"])) - hollow_mesh(); - - bool config_changed = false; - - ImGui::Separator(); - - { - auto opts = get_config_options({"hollowing_enable"}); - m_enable_hollowing = static_cast(opts[0].first)->value; - if (m_imgui->checkbox(m_desc["enable"], m_enable_hollowing)) { - mo->config.set("hollowing_enable", m_enable_hollowing); - wxGetApp().obj_list()->update_and_show_object_settings_item(); - config_changed = true; - } - } - - m_imgui->disabled_begin(! m_enable_hollowing); - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("offset")); - ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - ImGui::PushItemWidth(window_width - settings_sliders_left); - m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm", 1.0f, true, _L(opts[0].second->tooltip)); - - bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider - bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider - bool slider_released =m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider - - if (current_mode >= quality_mode) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("quality")); - ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f", 1.0f, true, _L(opts[1].second->tooltip)); - - slider_clicked |= m_imgui->get_last_slider_status().clicked; - slider_edited |= m_imgui->get_last_slider_status().edited; - slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; - } - - if (current_mode >= closing_d_mode) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("closing_distance")); - ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm", 1.0f, true, _L(opts[2].second->tooltip)); - - slider_clicked |= m_imgui->get_last_slider_status().clicked; - slider_edited |= m_imgui->get_last_slider_status().edited; - slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; - } - - if (slider_clicked) { - m_offset_stash = offset; - m_quality_stash = quality; - m_closing_d_stash = closing_d; - } - if (slider_edited || slider_released) { - if (slider_released) { - mo->config.set("hollowing_min_thickness", m_offset_stash); - mo->config.set("hollowing_quality", m_quality_stash); - mo->config.set("hollowing_closing_distance", m_closing_d_stash); - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Hollowing parameter change"); - } - mo->config.set("hollowing_min_thickness", offset); - mo->config.set("hollowing_quality", quality); - mo->config.set("hollowing_closing_distance", closing_d); - if (slider_released) { - wxGetApp().obj_list()->update_and_show_object_settings_item(); - config_changed = true; - } - } - - m_imgui->disabled_end(); - - bool force_refresh = false; - bool remove_selected = false; - bool remove_all = false; - - ImGui::Separator(); - - float diameter_upper_cap = 60.; - if (m_new_hole_radius * 2.f > diameter_upper_cap) - m_new_hole_radius = diameter_upper_cap / 2.f; - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("hole_diameter")); - ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x); - ImGui::PushItemWidth(window_width - diameter_slider_left); - - float diam = 2.f * m_new_hole_radius; - m_imgui->slider_float("##hole_diameter", &diam, 1.f, 25.f, "%.1f mm", 1.f, false); - // Let's clamp the value (which could have been entered by keyboard) to a larger range - // than the slider. This allows entering off-scale values and still protects against - //complete non-sense. - diam = std::clamp(diam, 0.1f, diameter_upper_cap); - m_new_hole_radius = diam / 2.f; - bool clicked = m_imgui->get_last_slider_status().clicked; - bool edited = m_imgui->get_last_slider_status().edited; - bool deactivated = m_imgui->get_last_slider_status().deactivated_after_edit; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["hole_depth"]); - ImGui::SameLine(diameter_slider_left, m_imgui->get_item_spacing().x); - m_imgui->slider_float("##hole_depth", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false); - // Same as above: - m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f); - - clicked |= m_imgui->get_last_slider_status().clicked; - edited |= m_imgui->get_last_slider_status().edited; - deactivated |= m_imgui->get_last_slider_status().deactivated_after_edit;; - - // Following is a nasty way to: - // - 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 - if (! m_selection_empty) { - if (clicked) { - m_holes_stash = mo->sla_drain_holes; - } - if (edited) { - for (size_t idx=0; idxsla_drain_holes[idx].radius = m_new_hole_radius; - mo->sla_drain_holes[idx].height = m_new_hole_height; - } - } - if (deactivated) { - // momentarily restore the old value to take snapshot - sla::DrainHoles new_holes = mo->sla_drain_holes; - mo->sla_drain_holes = m_holes_stash; - float backup_rad = m_new_hole_radius; - float backup_hei = m_new_hole_height; - for (size_t i=0; isla_drain_holes = new_holes; - } - } - - 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(mo->sla_drain_holes.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(""); - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); - }); - } - } - - ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); - ImGui::PushItemWidth(window_width - settings_sliders_left); - float clp_dist = m_c->object_clipper()->get_position(); - if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) - m_c->object_clipper()->set_position(clp_dist, true); - - // make sure supports are shown/hidden as appropriate - bool show_sups = m_c->instances_hider()->are_supports_shown(); - if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) { - m_c->instances_hider()->show_supports(show_sups); - force_refresh = true; - } - - m_imgui->end(); - - - if (remove_selected || remove_all) { - force_refresh = false; - m_parent.set_as_dirty(); - - if (remove_all) { - select_point(AllPoints); - delete_selected_points(); - } - if (remove_selected) - delete_selected_points(); - - if (first_run) { - first_run = false; - goto RENDER_AGAIN; - } - } - - if (force_refresh) - m_parent.set_as_dirty(); - - if (config_changed) - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); -} - -bool GLGizmoHollow::on_is_activable() const -{ - const Selection& selection = m_parent.get_selection(); - - if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA - || !selection.is_from_single_instance()) - return false; - - // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. - const Selection::IndicesList& list = selection.get_volume_idxs(); - for (const auto& idx : list) - if (selection.get_volume(idx)->is_outside && selection.get_volume(idx)->composite_id.volume_id >= 0) - return false; - - return true; -} - -bool GLGizmoHollow::on_is_selectable() const -{ - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA); -} - -std::string GLGizmoHollow::on_get_name() const -{ - return _u8L("Hollow and drill"); -} - - -CommonGizmosDataID GLGizmoHollow::on_get_requirements() const -{ - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::HollowedMesh) - | int(CommonGizmosDataID::ObjectClipper) - | int(CommonGizmosDataID::SupportsClipper)); -} - - -void GLGizmoHollow::on_set_state() -{ - if (m_state == m_old_state) - return; - - if (m_state == Off && m_old_state != Off) // the gizmo was just turned Off - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE)); - m_old_state = m_state; -} - - - -void GLGizmoHollow::on_start_dragging() -{ - if (m_hover_id != -1) { - select_point(NoPoints); - select_point(m_hover_id); - m_hole_before_drag = m_c->selection_info()->model_object()->sla_drain_holes[m_hover_id].pos; - } - else - m_hole_before_drag = Vec3f::Zero(); -} - - -void GLGizmoHollow::on_stop_dragging() -{ - sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - if (m_hover_id != -1) { - Vec3f backup = drain_holes[m_hover_id].pos; - - if (m_hole_before_drag != Vec3f::Zero() // some point was touched - && backup != m_hole_before_drag) // and it was moved, not just selected - { - drain_holes[m_hover_id].pos = m_hole_before_drag; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move drainage hole"); - drain_holes[m_hover_id].pos = backup; - } - } - m_hole_before_drag = Vec3f::Zero(); -} - - - -void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) -{ - ar(m_new_hole_radius, - m_new_hole_height, - m_selected, - m_selection_empty - ); -} - - - -void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const -{ - ar(m_new_hole_radius, - m_new_hole_height, - m_selected, - m_selection_empty - ); -} - - - -void GLGizmoHollow::select_point(int i) -{ - const sla::DrainHoles& drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - - if (i == AllPoints || i == NoPoints) { - m_selected.assign(m_selected.size(), i == AllPoints); - m_selection_empty = (i == NoPoints); - - if (i == AllPoints) { - m_new_hole_radius = drain_holes[0].radius; - m_new_hole_height = drain_holes[0].height; - } - } - else { - while (size_t(i) >= m_selected.size()) - m_selected.push_back(false); - m_selected[i] = true; - m_selection_empty = false; - m_new_hole_radius = drain_holes[i].radius; - m_new_hole_height = drain_holes[i].height; - } -} - - -void GLGizmoHollow::unselect_point(int i) -{ - m_selected[i] = false; - m_selection_empty = true; - for (const bool sel : m_selected) { - if (sel) { - m_selection_empty = false; - break; - } - } -} - -void GLGizmoHollow::reload_cache() -{ - m_selected.clear(); - m_selected.assign(m_c->selection_info()->model_object()->sla_drain_holes.size(), false); -} - - -void GLGizmoHollow::on_set_hover_id() -{ - if (int(m_c->selection_info()->model_object()->sla_drain_holes.size()) <= m_hover_id) - m_hover_id = -1; -} - - - - -} // namespace GUI -} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp deleted file mode 100644 index e60ece0d52..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef slic3r_GLGizmoHollow_hpp_ -#define slic3r_GLGizmoHollow_hpp_ - -#include "GLGizmoBase.hpp" -#include "slic3r/GUI/GLSelectionRectangle.hpp" - -#include -#include -#include - -#include - - -namespace Slic3r { - -class ConfigOption; -class ConfigOptionDef; - -namespace GUI { - -enum class SLAGizmoEventType : unsigned char; - -class GLGizmoHollow : public GLGizmoBase -{ -private: - bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); - - -public: - GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - virtual ~GLGizmoHollow() = default; - void set_sla_support_data(ModelObject* model_object, const Selection& selection); - bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); - void delete_selected_points(); - bool is_selection_rectangle_dragging() const { - return m_selection_rectangle.is_dragging(); - } - -private: - bool on_init() override; - void on_update(const UpdateData& data) override; - void on_render() override; - - void render_points(const Selection& selection, bool picking = false); - void hollow_mesh(bool postpone_error_messages = false); - bool unsaved_changes() const; - - ObjectID m_old_mo_id = -1; - - GLModel m_cylinder; - - float m_new_hole_radius = 2.f; // Size of a new hole. - float m_new_hole_height = 6.f; - mutable std::vector m_selected; // which holes are currently selected - - bool m_enable_hollowing = true; - - // Stashes to keep data for undo redo. Is taken after the editing - // is done, the data are updated continuously. - float m_offset_stash = 3.0f; - float m_quality_stash = 0.5f; - float m_closing_d_stash = 2.f; - Vec3f m_hole_before_drag = Vec3f::Zero(); - sla::DrainHoles m_holes_in_drilled_mesh; - - sla::DrainHoles m_holes_stash; - - // This map holds all translated description texts, so they can be easily referenced during layout calculations - // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. - std::map m_desc; - - GLSelectionRectangle m_selection_rectangle; - - bool m_wait_for_up_event = false; - bool m_selection_empty = true; - EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - - std::vector> get_config_options(const std::vector& keys) const; - bool is_mesh_point_clipped(const Vec3d& point) const; - - // Methods that do the model_object and editing cache synchronization, - // editing mode selection, etc: - enum { - AllPoints = -2, - NoPoints, - }; - void select_point(int i); - void unselect_point(int i); - void reload_cache(); - -protected: - void on_set_state() override; - void on_set_hover_id() override; - void on_start_dragging() override; - void on_stop_dragging() override; - void on_render_input_window(float x, float y, float bottom_limit) override; - virtual CommonGizmosDataID on_get_requirements() const override; - - std::string on_get_name() const override; - bool on_is_activable() const override; - bool on_is_selectable() const override; - void on_load(cereal::BinaryInputArchive& ar) override; - void on_save(cereal::BinaryOutputArchive& ar) const override; -}; - - - -} // namespace GUI -} // namespace Slic3r - -#endif // slic3r_GLGizmoHollow_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp deleted file mode 100644 index 49818e8e11..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ /dev/null @@ -1,1236 +0,0 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. -#include "GLGizmoSlaSupports.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Camera.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "slic3r/GUI/MainFrame.hpp" -#include "slic3r/Utils/UndoRedo.hpp" - -#include - -#include -#include -#include - -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/GUI.hpp" -#include "slic3r/GUI/GUI_ObjectSettings.hpp" -#include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "slic3r/GUI/NotificationManager.hpp" -#include "slic3r/GUI/MsgDialog.hpp" -#include "libslic3r/PresetBundle.hpp" -#include "libslic3r/SLAPrint.hpp" - - -namespace Slic3r { -namespace GUI { - -GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) -{ -} - - -bool GLGizmoSlaSupports::on_init() -{ - - m_desc["head_diameter"] = _L("Head diameter") + ": "; - m_desc["lock_supports"] = _L("Lock supports under new islands"); - m_desc["remove_selected"] = _L("Remove selected points"); - m_desc["remove_all"] = _L("Remove all points"); - m_desc["apply_changes"] = _L("Apply changes"); - m_desc["discard_changes"] = _L("Discard changes"); - m_desc["minimal_distance"] = _L("Minimal points distance") + ": "; - m_desc["points_density"] = _L("Support points density") + ": "; - m_desc["auto_generate"] = _L("Auto-generate points"); - m_desc["manual_editing"] = _L("Manual editing"); - m_desc["clipping_of_view"] = _L("Clipping of view")+ ": "; - m_desc["reset_direction"] = _L("Reset direction"); - - return true; -} - -void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection) -{ - if (! m_c->selection_info()) - return; - - ModelObject* mo = m_c->selection_info()->model_object(); - - if (m_state == On && mo && mo->id() != m_old_mo_id) { - disable_editing_mode(); - reload_cache(); - m_old_mo_id = mo->id(); - m_c->instances_hider()->show_supports(true); - } - - // If we triggered autogeneration before, check backend and fetch results if they are there - if (mo) { - if (mo->sla_points_status == sla::PointsStatus::Generating) - get_data_from_backend(); - } -} - - - -void GLGizmoSlaSupports::on_render() -{ - if (!m_cone.is_initialized()) - m_cone.init_from(its_make_cone(1.0, 1.0, double(PI) / 12.0)); - if (!m_sphere.is_initialized()) - m_sphere.init_from(its_make_sphere(1.0, double(PI) / 12.0)); - if (!m_cylinder.is_initialized()) - m_cylinder.init_from(its_make_cylinder(1.0, 1.0, double(PI) / 12.0)); - - ModelObject* mo = m_c->selection_info()->model_object(); - const Selection& selection = m_parent.get_selection(); - - // If current m_c->m_model_object does not match selection, ask GLCanvas3D to turn us off - if (m_state == On - && (mo != selection.get_model()->objects[selection.get_object_idx()] - || m_c->selection_info()->get_active_instance() != selection.get_instance_idx())) { - m_parent.post_event(SimpleEvent(EVT_GLCANVAS_RESETGIZMOS)); - return; - } - - glsafe(::glEnable(GL_BLEND)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - if (selection.is_from_single_instance()) - render_points(selection, false); - - m_selection_rectangle.render(m_parent); - m_c->object_clipper()->render_cut(); - m_c->supports_clipper()->render_cut(); - - glsafe(::glDisable(GL_BLEND)); -} - -void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) -{ - const size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); - - const bool has_points = (cache_size != 0); - const bool has_holes = (! m_c->hollowed_mesh()->get_hollowed_mesh() - && ! m_c->selection_info()->model_object()->sla_drain_holes.empty()); - - if (! has_points && ! has_holes) - return; - - GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); - if (shader == nullptr) - return; - - shader->start_using(); - ScopeGuard guard([shader]() { shader->stop_using(); }); - - const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); - const Transform3d instance_matrix = Geometry::assemble_transform(m_c->selection_info()->get_sla_shift() * Vec3d::UnitZ()) * vol->get_instance_transformation().get_matrix(); - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Transform3d& view_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - - shader->set_uniform("projection_matrix", projection_matrix); - - ColorRGBA render_color; - 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; - - if (is_mesh_point_clipped(support_point.pos.cast())) - continue; - - // First decide about the color of the point. - if (picking) - render_color = picking_color_component(i); - else { - if (size_t(m_hover_id) == i && m_editing_mode) // ignore hover state unless editing mode is active - render_color = { 0.f, 1.f, 1.f, 1.f }; - else { // neigher hover nor picking - bool supports_new_island = m_lock_unique_islands && support_point.is_new_island; - if (m_editing_mode) { - if (point_selected) - render_color = { 1.f, 0.3f, 0.3f, 1.f}; - else - if (supports_new_island) - render_color = { 0.3f, 0.3f, 1.f, 1.f }; - else - render_color = { 0.7f, 0.7f, 0.7f, 1.f }; - } - else - render_color = { 0.5f, 0.5f, 0.5f, 1.f }; - } - } - - m_cone.set_color(render_color); - m_sphere.set_color(render_color); - if (!picking) - shader->set_uniform("emission_factor", 0.5f); - - // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. - const Transform3d support_matrix = Geometry::assemble_transform(support_point.pos.cast()) * instance_scaling_matrix_inverse; - - 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_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal); - - Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast()); - const Eigen::AngleAxisd aa(q); - const double cone_radius = 0.25; // mm - const double cone_height = 0.75; - const Transform3d model_matrix = instance_matrix * support_matrix * Transform3d(aa.toRotationMatrix()) * - Geometry::assemble_transform((cone_height + support_point.head_front_radius * RenderPointScale) * Vec3d::UnitZ(), - Vec3d(PI, 0.0, 0.0), Vec3d(cone_radius, cone_radius, cone_height)); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cone.render(); - } - - const double radius = (double)support_point.head_front_radius * RenderPointScale; - const Transform3d model_matrix = instance_matrix * support_matrix * - Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), radius * Vec3d::Ones()); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_sphere.render(); - - if (vol->is_left_handed()) - glFrontFace(GL_CCW); - } - - // Now render the drain holes: - if (has_holes && ! picking) { - render_color = { 0.7f, 0.7f, 0.7f, 0.7f }; - m_cylinder.set_color(render_color); - shader->set_uniform("emission_factor", 0.5f); - for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) { - if (is_mesh_point_clipped(drain_hole.pos.cast())) - continue; - - const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast()) * instance_scaling_matrix_inverse; - - if (vol->is_left_handed()) - glFrontFace(GL_CW); - - // Matrices set, we can render the point mark now. - Eigen::Quaterniond q; - q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast()); - const Eigen::AngleAxisd aa(q); - const Transform3d model_matrix = instance_matrix * hole_matrix * Transform3d(aa.toRotationMatrix()) * - Geometry::assemble_transform(-drain_hole.height * Vec3d::UnitZ(), Vec3d::Zero(), Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); - - shader->set_uniform("view_model_matrix", view_matrix * model_matrix); - const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); - shader->set_uniform("view_normal_matrix", view_normal_matrix); - m_cylinder.render(); - - if (vol->is_left_handed()) - glFrontFace(GL_CCW); - } - } -} - - - -bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const -{ - if (m_c->object_clipper()->get_position() == 0.) - return false; - - auto sel_info = m_c->selection_info(); - int active_inst = m_c->selection_info()->get_active_instance(); - const ModelInstance* mi = sel_info->model_object()->instances[active_inst]; - const Transform3d& trafo = mi->get_transformation().get_matrix(); - - Vec3d transformed_point = trafo * point; - transformed_point(2) += sel_info->get_sla_shift(); - return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); -} - - - -// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal -// Return false if no intersection was found, true otherwise. -bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal) -{ - if (! m_c->raycaster()->raycaster()) - return false; - - const Camera& camera = wxGetApp().plater()->get_camera(); - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Geometry::Transformation trafo = volume->get_instance_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); - - double clp_dist = m_c->object_clipper()->get_position(); - const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane(); - - // The raycaster query - Vec3f hit; - Vec3f normal; - if (m_c->raycaster()->raycaster()->unproject_on_mesh( - mouse_pos, - trafo.get_matrix(), - camera, - hit, - normal, - clp_dist != 0. ? clp : nullptr)) - { - // Check whether the hit is in a hole - bool in_hole = false; - // In case the hollowed and drilled mesh is available, we can allow - // placing points in holes, because they should never end up - // on surface that's been drilled away. - if (! m_c->hollowed_mesh()->get_hollowed_mesh()) { - sla::DrainHoles drain_holes = m_c->selection_info()->model_object()->sla_drain_holes; - for (const sla::DrainHole& hole : drain_holes) { - if (hole.is_inside(hit)) { - in_hole = true; - break; - } - } - } - if (! in_hole) { - // Return both the point and the facet normal. - pos_and_normal = std::make_pair(hit, normal); - return true; - } - } - - return false; -} - -// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event. -// The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is -// aware that the event was reacted to and stops trying to make different sense of it. If the gizmo -// concludes that the event was not intended for it, it should return false. -bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) -{ - ModelObject* mo = m_c->selection_info()->model_object(); - int active_inst = m_c->selection_info()->get_active_instance(); - - 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) { - if (shift_down || alt_down) { - m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::Select : GLSelectionRectangle::Deselect); - } - } - else { - if (m_editing_cache[m_hover_id].selected) - unselect_point(m_hover_id); - else { - if (!alt_down) - select_point(m_hover_id); - } - } - - return true; - } - - // left down without selection rectangle - place point on the mesh: - if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle.is_dragging() && !shift_down) { - // If any point is in hover state, this should initiate its move - return control back to GLCanvas: - if (m_hover_id != -1) - return false; - - // If there is some selection, don't add new point and deselect everything instead. - if (m_selection_empty) { - std::pair pos_and_normal; - if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Add support point"); - 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_parent.set_as_dirty(); - m_wait_for_up_event = true; - } - else - return false; - } - else - select_point(NoPoints); - - return true; - } - - // left up with selection rectangle - select points inside the rectangle: - if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle.is_dragging()) { - // Is this a selection or deselection rectangle? - GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); - - // First collect positions of all the points in world coordinates. - Geometry::Transformation trafo = mo->instances[active_inst]->get_transformation(); - trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift())); - std::vector points; - for (unsigned int i=0; i()); - - // Now ask the rectangle which of the points are inside. - std::vector points_inside; - std::vector points_idxs = m_selection_rectangle.stop_dragging(m_parent, points); - for (size_t idx : points_idxs) - points_inside.push_back(points[idx].cast()); - - // Only select/deselect points that are actually visible. We want to check not only - // the point itself, but also the center of base of its cone, so the points don't hide - // under every miniature irregularity on the model. Remember the actual number and - // append the cone bases. - size_t orig_pts_num = points_inside.size(); - for (size_t idx : points_idxs) - points_inside.emplace_back((trafo.get_matrix().cast() * (m_editing_cache[idx].support_point.pos + m_editing_cache[idx].normal)).cast()); - - for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs( - trafo, wxGetApp().plater()->get_camera(), points_inside, - m_c->object_clipper()->get_clipping_plane())) - { - if (idx >= orig_pts_num) // this is a cone-base, get index of point it belongs to - idx -= orig_pts_num; - if (rectangle_status == GLSelectionRectangle::Deselect) - unselect_point(points_idxs[idx]); - else - select_point(points_idxs[idx]); - } - return true; - } - - // left up with no selection rectangle - if (action == SLAGizmoEventType::LeftUp) { - if (m_wait_for_up_event) { - m_wait_for_up_event = false; - } - return true; - } - - // dragging the selection rectangle: - if (action == SLAGizmoEventType::Dragging) { - if (m_wait_for_up_event) - return true; // point has been placed and the button not released yet - // this prevents GLCanvas from starting scene rotation - - if (m_selection_rectangle.is_dragging()) { - m_selection_rectangle.dragging(mouse_position); - return true; - } - - return false; - } - - if (action == SLAGizmoEventType::Delete) { - // delete key pressed - delete_selected_points(); - return true; - } - - if (action == SLAGizmoEventType::ApplyChanges) { - editing_mode_apply_changes(); - return true; - } - - if (action == SLAGizmoEventType::DiscardChanges) { - ask_about_changes_call_after([this](){ editing_mode_apply_changes(); }, - [this](){ editing_mode_discard_changes(); }); - return true; - } - - if (action == SLAGizmoEventType::RightDown) { - if (m_hover_id != -1) { - select_point(NoPoints); - select_point(m_hover_id); - delete_selected_points(); - return true; - } - return false; - } - - if (action == SLAGizmoEventType::SelectAll) { - select_point(AllPoints); - return true; - } - } - - if (!m_editing_mode) { - if (action == SLAGizmoEventType::AutomaticGeneration) { - auto_generate(); - return true; - } - - if (action == SLAGizmoEventType::ManualEditing) { - switch_to_editing_mode(); - return true; - } - } - - if (action == SLAGizmoEventType::MouseWheelUp && control_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::min(1., pos + 0.01); - m_c->object_clipper()->set_position(pos, true); - return true; - } - - if (action == SLAGizmoEventType::MouseWheelDown && control_down) { - double pos = m_c->object_clipper()->get_position(); - pos = std::max(0., pos - 0.01); - m_c->object_clipper()->set_position(pos, true); - return true; - } - - if (action == SLAGizmoEventType::ResetClippingPlane) { - m_c->object_clipper()->set_position(-1., false); - return true; - } - - return false; -} - -void GLGizmoSlaSupports::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(), "Delete support point"); - - for (unsigned int idx=0; idx pos_and_normal; - if (! unproject_on_mesh(data.mouse_pos.cast(), 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; - } - } -} - -std::vector GLGizmoSlaSupports::get_config_options(const std::vector& keys) const -{ - std::vector out; - const ModelObject* mo = m_c->selection_info()->model_object(); - - if (! mo) - return out; - - const DynamicPrintConfig& object_cfg = mo->config.get(); - const DynamicPrintConfig& print_cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; - std::unique_ptr default_cfg = nullptr; - - for (const std::string& key : keys) { - if (object_cfg.has(key)) - out.push_back(object_cfg.option(key)); - else - if (print_cfg.has(key)) - out.push_back(print_cfg.option(key)); - else { // we must get it from defaults - if (default_cfg == nullptr) - default_cfg.reset(DynamicPrintConfig::new_from_defaults_keys(keys)); - out.push_back(default_cfg->option(key)); - } - } - - return out; -} - - - -/* -void GLGizmoSlaSupports::find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& idxs) const -{ - if (aabb->is_leaf()) { // this is a facet - // corner.dot(normal) - offset - idxs.push_back(aabb->m_primitive); - } - else { // not a leaf - using CornerType = Eigen::AlignedBox::CornerType; - bool sign = std::signbit(offset - normal.dot(aabb->m_box.corner(CornerType(0)))); - for (unsigned int i=1; i<8; ++i) - if (std::signbit(offset - normal.dot(aabb->m_box.corner(CornerType(i)))) != sign) { - find_intersecting_facets(aabb->m_left, normal, offset, idxs); - find_intersecting_facets(aabb->m_right, normal, offset, idxs); - } - } -} - - - -void GLGizmoSlaSupports::make_line_segments() const -{ - TriangleMeshSlicer tms(&m_c->m_model_object->volumes.front()->mesh); - Vec3f normal(0.f, 1.f, 1.f); - double d = 0.; - - std::vector lines; - find_intersections(&m_AABB, normal, d, lines); - ExPolygons expolys; - tms.make_expolygons_simple(lines, &expolys); - - SVG svg("slice_loops.svg", get_extents(expolys)); - svg.draw(expolys); - //for (const IntersectionLine &l : lines[i]) - // svg.draw(l, "red", 0); - //svg.draw_outline(expolygons, "black", "blue", 0); - svg.Close(); -} -*/ - - -void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit) -{ - static float last_y = 0.0f; - static float last_h = 0.0f; - - ModelObject* mo = m_c->selection_info()->model_object(); - - if (! mo) - return; - - 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)); - - m_imgui->begin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); - - // adjust window position to avoid overlap the view toolbar - float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always); - if ((last_h != win_h) || (last_y != y)) - { - // ask canvas for another frame to render the window in the correct position -#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - m_imgui->set_requires_extra_frame(); -#else - m_parent.request_extra_frame(); -#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT - if (last_h != win_h) - last_h = win_h; - if (last_y != y) - last_y = y; - } - - // 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); - const float minimal_slider_width = m_imgui->scaled(4.f); - const float buttons_width_approx = m_imgui->calc_text_size(m_desc.at("apply_changes")).x + m_imgui->calc_text_size(m_desc.at("discard_changes")).x + m_imgui->scaled(1.5f); - const float lock_supports_width_approx = m_imgui->calc_text_size(m_desc.at("lock_supports")).x + m_imgui->scaled(2.f); - - 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) { - - float diameter_upper_cap = static_cast(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; - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("head_diameter")); - ImGui::SameLine(diameter_slider_left); - ImGui::PushItemWidth(window_width - diameter_slider_left); - - // Following is a nasty way to: - // - 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; - m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); - if (m_imgui->get_last_slider_status().clicked) { - if (m_old_point_head_diameter == 0.f) - m_old_point_head_diameter = initial_value; - } - if (m_imgui->get_last_slider_status().edited) { - 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; - } - if (m_imgui->get_last_slider_status().deactivated_after_edit) { - // 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; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Change point head 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; - } - - bool changed = m_lock_unique_islands; - m_imgui->checkbox(m_desc.at("lock_supports"), m_lock_unique_islands); - force_refresh |= changed != m_lock_unique_islands; - - 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()); - remove_all = m_imgui->button(m_desc.at("remove_all")); - m_imgui->disabled_end(); - - m_imgui->text(" "); // vertical gap - - if (m_imgui->button(m_desc.at("apply_changes"))) { - editing_mode_apply_changes(); - force_refresh = true; - } - ImGui::SameLine(); - bool discard_changes = m_imgui->button(m_desc.at("discard_changes")); - if (discard_changes) { - editing_mode_discard_changes(); - force_refresh = true; - } - } - else { // not in editing mode: - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("minimal_distance")); - ImGui::SameLine(settings_sliders_left); - ImGui::PushItemWidth(window_width - settings_sliders_left); - - std::vector opts = get_config_options({"support_points_density_relative", "support_points_minimal_distance"}); - float density = static_cast(opts[0])->value; - float minimal_point_distance = static_cast(opts[1])->value; - - m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm"); - bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider - bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider - bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("points_density")); - ImGui::SameLine(settings_sliders_left); - - m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%"); - slider_clicked |= m_imgui->get_last_slider_status().clicked; - slider_edited |= m_imgui->get_last_slider_status().edited; - slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; - - 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) { - mo->config.set("support_points_minimal_distance", minimal_point_distance); - mo->config.set("support_points_density_relative", (int)density); - } - if (slider_released) { - mo->config.set("support_points_minimal_distance", m_minimal_point_distance_stash); - mo->config.set("support_points_density_relative", (int)m_density_stash); - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Support parameter change"); - mo->config.set("support_points_minimal_distance", minimal_point_distance); - mo->config.set("support_points_density_relative", (int)density); - wxGetApp().obj_list()->update_and_show_object_settings_item(); - } - - bool generate = m_imgui->button(m_desc.at("auto_generate")); - - if (generate) - auto_generate(); - - ImGui::Separator(); - if (m_imgui->button(m_desc.at("manual_editing"))) - switch_to_editing_mode(); - - m_imgui->disabled_begin(m_normal_cache.empty()); - remove_all = m_imgui->button(m_desc.at("remove_all")); - m_imgui->disabled_end(); - - // m_imgui->text(""); - // m_imgui->text(m_c->m_model_object->sla_points_status == sla::PointsStatus::NoPoints ? _(L("No points (will be autogenerated)")) : - // (m_c->m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? _(L("Autogenerated points (no modifications)")) : - // (m_c->m_model_object->sla_points_status == sla::PointsStatus::UserModified ? _(L("User-modified points")) : - // (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating ? _(L("Generation in progress...")) : "UNKNOWN STATUS")))); - } - - - // Following is rendered in both editing and non-editing mode: - ImGui::Separator(); - if (m_c->object_clipper()->get_position() == 0.f) { - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc.at("clipping_of_view")); - } - else { - if (m_imgui->button(m_desc.at("reset_direction"))) { - wxGetApp().CallAfter([this](){ - m_c->object_clipper()->set_position(-1., false); - }); - } - } - - ImGui::SameLine(clipping_slider_left); - ImGui::PushItemWidth(window_width - clipping_slider_left); - float clp_dist = m_c->object_clipper()->get_position(); - if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f")) - m_c->object_clipper()->set_position(clp_dist, true); - - - if (m_imgui->button("?")) { - wxGetApp().CallAfter([]() { - SlaGizmoHelpDialog help_dlg; - help_dlg.ShowModal(); - }); - } - - m_imgui->end(); - - if (remove_selected || remove_all) { - force_refresh = false; - m_parent.set_as_dirty(); - bool was_in_editing = m_editing_mode; - if (! was_in_editing) - switch_to_editing_mode(); - if (remove_all) { - select_point(AllPoints); - delete_selected_points(true); // true - delete regardless of locked status - } - if (remove_selected) - delete_selected_points(false); // leave locked points - if (! was_in_editing) - editing_mode_apply_changes(); - - if (first_run) { - first_run = false; - goto RENDER_AGAIN; - } - } - - if (force_refresh) - m_parent.set_as_dirty(); -} - -bool GLGizmoSlaSupports::on_is_activable() const -{ - const Selection& selection = m_parent.get_selection(); - - if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA - || !selection.is_from_single_instance()) - return false; - - // Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside. - const Selection::IndicesList& list = selection.get_volume_idxs(); - for (const auto& idx : list) - if (selection.get_volume(idx)->is_outside && selection.get_volume(idx)->composite_id.volume_id >= 0) - return false; - - return true; -} - -bool GLGizmoSlaSupports::on_is_selectable() const -{ - return (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA); -} - -std::string GLGizmoSlaSupports::on_get_name() const -{ - return _u8L("SLA Support Points"); -} - -CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const -{ - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::HollowedMesh) - | int(CommonGizmosDataID::ObjectClipper) - | int(CommonGizmosDataID::SupportsClipper)); -} - - - -void GLGizmoSlaSupports::ask_about_changes_call_after(std::function on_yes, std::function on_no) -{ - wxGetApp().CallAfter([on_yes, on_no]() { - // Following is called through CallAfter, because otherwise there was a problem - // on OSX with the wxMessageDialog being shown several times when clicked into. - MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually " - "edited support points?") + "\n",_L("Save support points?"), wxICON_QUESTION | wxYES | wxNO | wxCANCEL ); - int ret = dlg.ShowModal(); - if (ret == wxID_YES) - on_yes(); - else if (ret == wxID_NO) - on_no(); - }); -} - - -void GLGizmoSlaSupports::on_set_state() -{ - if (m_state == m_old_state) - return; - - if (m_state == On && m_old_state != On) { // the gizmo was just turned on - // 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(cfg.option("support_head_front_diameter"))->value; - } - if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off - bool will_ask = m_editing_mode && unsaved_changes() && on_is_activable(); - if (will_ask) { - ask_about_changes_call_after([this](){ editing_mode_apply_changes(); }, - [this](){ editing_mode_discard_changes(); }); - // refuse to be turned off so the gizmo is active when the CallAfter is executed - m_state = m_old_state; - } - else { - // we are actually shutting down - disable_editing_mode(); // so it is not active next time the gizmo opens - m_old_mo_id = -1; - } - } - m_old_state = m_state; -} - - - -void GLGizmoSlaSupports::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]; - } - else - m_point_before_drag = CacheEntry(); -} - - -void GLGizmoSlaSupports::on_stop_dragging() -{ - if (m_hover_id != -1) { - CacheEntry backup = m_editing_cache[m_hover_id]; - - 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 - { - m_editing_cache[m_hover_id] = m_point_before_drag; - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Move support point"); - m_editing_cache[m_hover_id] = backup; - } - } - m_point_before_drag = CacheEntry(); -} - - - -void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) -{ - ar(m_new_point_head_diameter, - m_normal_cache, - m_editing_cache, - m_selection_empty - ); -} - - - -void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const -{ - ar(m_new_point_head_diameter, - m_normal_cache, - m_editing_cache, - m_selection_empty - ); -} - - - -void GLGizmoSlaSupports::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_selection_empty = (i == NoPoints); - - if (i == AllPoints) - m_new_point_head_diameter = m_editing_cache[0].support_point.head_front_radius * 2.f; - } - else { - m_editing_cache[i].selected = true; - m_selection_empty = false; - m_new_point_head_diameter = m_editing_cache[i].support_point.head_front_radius * 2.f; - } -} - - -void GLGizmoSlaSupports::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_selection_empty = true; - for (const CacheEntry& ce : m_editing_cache) { - if (ce.selected) { - m_selection_empty = false; - break; - } - } -} - - - - -void GLGizmoSlaSupports::editing_mode_discard_changes() -{ - if (! m_editing_mode) { - std::cout << "DEBUGGING: editing_mode_discard_changes called when out of editing mode!" << std::endl; - std::abort(); - } - select_point(NoPoints); - disable_editing_mode(); -} - - - -void GLGizmoSlaSupports::editing_mode_apply_changes() -{ - // If there are no changes, don't touch the front-end. The data in the cache could have been - // taken from the backend and copying them to ModelObject would needlessly invalidate them. - disable_editing_mode(); // this leaves the editing mode undo/redo stack and must be done before the snapshot is taken - - if (unsaved_changes()) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Support points edit"); - - m_normal_cache.clear(); - for (const CacheEntry& ce : m_editing_cache) - m_normal_cache.push_back(ce.support_point); - - ModelObject* mo = m_c->selection_info()->model_object(); - mo->sla_points_status = sla::PointsStatus::UserModified; - mo->sla_support_points.clear(); - mo->sla_support_points = m_normal_cache; - - reslice_SLA_supports(); - } -} - - - -void GLGizmoSlaSupports::reload_cache() -{ - const ModelObject* mo = m_c->selection_info()->model_object(); - m_normal_cache.clear(); - if (mo->sla_points_status == sla::PointsStatus::AutoGenerated || mo->sla_points_status == sla::PointsStatus::Generating) - get_data_from_backend(); - else - for (const sla::SupportPoint& point : mo->sla_support_points) - m_normal_cache.emplace_back(point); -} - - -bool GLGizmoSlaSupports::has_backend_supports() const -{ - const ModelObject* mo = m_c->selection_info()->model_object(); - if (! mo) - return false; - - // find SlaPrintObject with this ID - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == mo->id()) - return po->is_step_done(slaposSupportPoints); - } - return false; -} - -void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const -{ - wxGetApp().CallAfter([this, postpone_error_messages]() { - wxGetApp().plater()->reslice_SLA_supports( - *m_c->selection_info()->model_object(), postpone_error_messages); - }); -} - -void GLGizmoSlaSupports::get_data_from_backend() -{ - if (! has_backend_supports()) - return; - ModelObject* mo = m_c->selection_info()->model_object(); - - // find the respective SLAPrintObject, we need a pointer to it - for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { - if (po->model_object()->id() == mo->id()) { - m_normal_cache.clear(); - const std::vector& points = po->get_support_points(); - auto mat = po->trafo().inverse().cast(); - for (unsigned int i=0; isla_points_status = sla::PointsStatus::AutoGenerated; - break; - } - } - - // We don't copy the data into ModelObject, as this would stop the background processing. -} - - - -void GLGizmoSlaSupports::auto_generate() -{ - //wxMessageDialog dlg(GUI::wxGetApp().plater(), - MessageDialog dlg(GUI::wxGetApp().plater(), - _L("Autogeneration will erase all manually edited points.") + "\n\n" + - _L("Are you sure you want to do it?") + "\n", - _L("Warning"), wxICON_WARNING | wxYES | wxNO); - - ModelObject* mo = m_c->selection_info()->model_object(); - - if (mo->sla_points_status != sla::PointsStatus::UserModified || m_normal_cache.empty() || dlg.ShowModal() == wxID_YES) { - Plater::TakeSnapshot snapshot(wxGetApp().plater(), "Autogenerate support points"); - wxGetApp().CallAfter([this]() { reslice_SLA_supports(); }); - mo->sla_points_status = sla::PointsStatus::Generating; - } -} - - - -void GLGizmoSlaSupports::switch_to_editing_mode() -{ - wxGetApp().plater()->enter_gizmos_stack(); - m_editing_mode = true; - m_editing_cache.clear(); - for (const sla::SupportPoint& sp : m_normal_cache) - m_editing_cache.emplace_back(sp); - select_point(NoPoints); - - m_c->instances_hider()->show_supports(false); - m_parent.set_as_dirty(); -} - - -void GLGizmoSlaSupports::disable_editing_mode() -{ - if (m_editing_mode) { - m_editing_mode = false; - wxGetApp().plater()->leave_gizmos_stack(); - m_c->instances_hider()->show_supports(true); - m_parent.set_as_dirty(); - } - wxGetApp().plater()->get_notification_manager()->close_notification_of_type(NotificationType::QuitSLAManualMode); -} - - - -bool GLGizmoSlaSupports::unsaved_changes() const -{ - if (m_editing_cache.size() != m_normal_cache.size()) - return true; - - for (size_t i=0; iSetFont(font); - - auto vsizer = new wxBoxSizer(wxVERTICAL); - auto gridsizer = new wxFlexGridSizer(2, 5, 15); - auto hsizer = new wxBoxSizer(wxHORIZONTAL); - - hsizer->AddSpacer(20); - hsizer->Add(vsizer); - hsizer->AddSpacer(20); - - vsizer->AddSpacer(20); - vsizer->Add(note_text, 1, wxALIGN_CENTRE_HORIZONTAL); - vsizer->AddSpacer(20); - vsizer->Add(gridsizer); - vsizer->AddSpacer(20); - - std::vector> shortcuts; - shortcuts.push_back(std::make_pair(_L("Left click"), _L("Add point"))); - shortcuts.push_back(std::make_pair(_L("Right click"), _L("Remove point"))); - shortcuts.push_back(std::make_pair(_L("Drag"), _L("Move point"))); - shortcuts.push_back(std::make_pair(ctrl+_L("Left click"), _L("Add point to selection"))); - shortcuts.push_back(std::make_pair(alt+_L("Left click"), _L("Remove point from selection"))); - shortcuts.push_back(std::make_pair(shift+_L("Drag"), _L("Select by rectangle"))); - shortcuts.push_back(std::make_pair(alt+_(L("Drag")), _L("Deselect by rectangle"))); - shortcuts.push_back(std::make_pair(ctrl+"A", _L("Select all points"))); - shortcuts.push_back(std::make_pair(_L"Del", _L("Remove selected points"))); - shortcuts.push_back(std::make_pair(ctrl+_L("Mouse wheel"), _L("Move clipping plane"))); - shortcuts.push_back(std::make_pair("R", _L("Reset clipping plane"))); - shortcuts.push_back(std::make_pair(_L_CONTEXT("Enter", "Keyboard Shortcut"), _L("Apply changes"))); - shortcuts.push_back(std::make_pair(_L_CONTEXT("Esc", "Keyboard Shortcut"), _L("Discard changes"))); - shortcuts.push_back(std::make_pair("M", _L("Switch to editing mode"))); - shortcuts.push_back(std::make_pair("A", _L("Auto-generate points"))); - - for (const auto& pair : shortcuts) { - auto shortcut = new wxStaticText(this, wxID_ANY, pair.first); - auto desc = new wxStaticText(this, wxID_ANY, pair.second); - shortcut->SetFont(bold_font); - desc->SetFont(font); - gridsizer->Add(shortcut, -1, wxALIGN_CENTRE_VERTICAL); - gridsizer->Add(desc, -1, wxALIGN_CENTRE_VERTICAL); - } - - SetSizer(hsizer); - hsizer->SetSizeHints(this); -} - - - -} // namespace GUI -} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp deleted file mode 100644 index e4e7b8241f..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef slic3r_GLGizmoSlaSupports_hpp_ -#define slic3r_GLGizmoSlaSupports_hpp_ - -#include "GLGizmoBase.hpp" -#include "slic3r/GUI/GLSelectionRectangle.hpp" - -#include "libslic3r/SLA/SupportPoint.hpp" -#include "libslic3r/ObjectID.hpp" -#include - -#include - - -namespace Slic3r { - -class ConfigOption; - -namespace GUI { - -enum class SLAGizmoEventType : unsigned char; - -class GLGizmoSlaSupports : public GLGizmoBase -{ -private: - - bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair& pos_and_normal); - - const float RenderPointScale = 1.f; - - class CacheEntry { - public: - CacheEntry() : - support_point(sla::SupportPoint()), selected(false), normal(Vec3f::Zero()) {} - - CacheEntry(const sla::SupportPoint& point, bool sel = false, const Vec3f& norm = Vec3f::Zero()) : - support_point(point), selected(sel), normal(norm) {} - - bool operator==(const CacheEntry& rhs) const { - return (support_point == rhs.support_point); - } - - bool operator!=(const CacheEntry& rhs) const { - return ! ((*this) == rhs); - } - - sla::SupportPoint support_point; - bool selected; // whether the point is selected - Vec3f normal; - - template - void serialize(Archive & ar) - { - ar(support_point, selected, normal); - } - }; - -public: - GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - virtual ~GLGizmoSlaSupports() = default; - void set_sla_support_data(ModelObject* model_object, const Selection& selection); - bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); - void delete_selected_points(bool force = false); - //ClippingPlane get_sla_clipping_plane() const; - - bool is_in_editing_mode() const { return m_editing_mode; } - bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); } - bool has_backend_supports() const; - void reslice_SLA_supports(bool postpone_error_messages = false) const; - - bool wants_enter_leave_snapshots() const override { return true; } - std::string get_gizmo_entering_text() const override { return "Entering SLA support points"; } - std::string get_gizmo_leaving_text() const override { return "Leaving SLA support points"; } - -private: - bool on_init() override; - void on_update(const UpdateData& data) override; - void on_render() override; - - void render_points(const Selection& selection, bool picking = false); - bool unsaved_changes() const; - - bool m_lock_unique_islands = false; - bool m_editing_mode = false; // Is editing mode active? - float m_new_point_head_diameter; // Size of a new point. - CacheEntry m_point_before_drag; // undo/redo - so we know what state was edited - float m_old_point_head_diameter = 0.; // the same - float m_minimal_point_distance_stash = 0.f; // and again - float m_density_stash = 0.f; // and again - mutable std::vector m_editing_cache; // a support point and whether it is currently selected - std::vector m_normal_cache; // to restore after discarding changes or undo/redo - ObjectID m_old_mo_id; - - GLModel m_cone; - GLModel m_cylinder; - GLModel m_sphere; - - // This map holds all translated description texts, so they can be easily referenced during layout calculations - // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. - std::map m_desc; - - GLSelectionRectangle m_selection_rectangle; - - bool m_wait_for_up_event = false; - bool m_selection_empty = true; - EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) - - std::vector get_config_options(const std::vector& keys) const; - bool is_mesh_point_clipped(const Vec3d& point) const; - bool is_point_in_hole(const Vec3f& pt) const; - //void find_intersecting_facets(const igl::AABB* aabb, const Vec3f& normal, double offset, std::vector& out) const; - - // Methods that do the model_object and editing cache synchronization, - // editing mode selection, etc: - enum { - AllPoints = -2, - NoPoints, - }; - void select_point(int i); - void unselect_point(int i); - void editing_mode_apply_changes(); - void editing_mode_discard_changes(); - void reload_cache(); - void get_data_from_backend(); - void auto_generate(); - void switch_to_editing_mode(); - void disable_editing_mode(); - void ask_about_changes_call_after(std::function on_yes, std::function on_no); - -protected: - void on_set_state() override; - void on_set_hover_id() override - - { - if (! m_editing_mode || (int)m_editing_cache.size() <= m_hover_id) - m_hover_id = -1; - } - void on_start_dragging() override; - void on_stop_dragging() override; - void on_render_input_window(float x, float y, float bottom_limit) override; - - std::string on_get_name() const override; - bool on_is_activable() const override; - bool on_is_selectable() const override; - virtual CommonGizmosDataID on_get_requirements() const override; - void on_load(cereal::BinaryInputArchive& ar) override; - void on_save(cereal::BinaryOutputArchive& ar) const override; -}; - - -class SlaGizmoHelpDialog : public wxDialog -{ -public: - SlaGizmoHelpDialog(); -}; - -} // namespace GUI -} // namespace Slic3r - -#endif // slic3r_GLGizmoSlaSupports_hpp_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp deleted file mode 100644 index 9ae979eeef..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp +++ /dev/null @@ -1,1680 +0,0 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. -#include "GLGizmoText.hpp" -#include "slic3r/GUI/GLCanvas3D.hpp" -#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" -#include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/ImGuiWrapper.hpp" -#include "slic3r/GUI/GUI_ObjectList.hpp" -#include "slic3r/GUI/Plater.hpp" -#include "libslic3r/ClipperUtils.hpp" -#include "libslic3r/Geometry/ConvexHull.hpp" -#include "libslic3r/Model.hpp" - -#include "libslic3r/Shape/TextShape.hpp" - -#include - -#include - -#include - -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif -#include -#include "libslic3r/SVG.hpp" -#include -#include "wx/fontenum.h" - -namespace Slic3r { -namespace GUI { - -static const double PI = 3.141592653589793238; -static const wxColour FONT_TEXTURE_BG = wxColour(0, 0, 0, 0); -static const wxColour FONT_TEXTURE_FG = *wxWHITE; -static const int FONT_SIZE = 12; -static const float SELECTABLE_INNER_OFFSET = 8.0f; - -static std::vector font_black_list = { -#ifdef _WIN32 - "MT Extra", - "Marlett", - "Symbol", - "Webdings", - "Wingdings", - "Wingdings 2", - "Wingdings 3", -#endif -}; - -static const wxFontEncoding font_encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; - -#ifdef _WIN32 -static bool load_hfont(void *hfont, DWORD &dwTable, DWORD &dwOffset, size_t &size, HDC hdc = nullptr) -{ - bool del_hdc = false; - if (hdc == nullptr) { - del_hdc = true; - hdc = ::CreateCompatibleDC(NULL); - if (hdc == NULL) return false; - } - - // To retrieve the data from the beginning of the file for TrueType - // Collection files specify 'ttcf' (0x66637474). - dwTable = 0x66637474; - dwOffset = 0; - - ::SelectObject(hdc, hfont); - size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0); - if (size == GDI_ERROR) { - // HFONT is NOT TTC(collection) - dwTable = 0; - size = ::GetFontData(hdc, dwTable, dwOffset, NULL, 0); - } - - if (size == 0 || size == GDI_ERROR) { - if (del_hdc) ::DeleteDC(hdc); - return false; - } - return true; -} -#endif // _WIN32 - -bool can_load(const wxFont &font) -{ -#ifdef _WIN32 - DWORD dwTable = 0, dwOffset = 0; - size_t size = 0; - void* hfont = font.GetHFONT(); - if (!load_hfont(hfont, dwTable, dwOffset, size)) - return false; - return hfont != nullptr; -#elif defined(__APPLE__) - return true; -#elif defined(__linux__) - return true; -#endif - return false; -} - -std::vector init_face_names() -{ - std::vector valid_font_names; - wxArrayString facenames = wxFontEnumerator::GetFacenames(font_encoding); - std::vector bad_fonts; - - // validation lambda - auto is_valid_font = [coding = font_encoding, bad = bad_fonts](const wxString &name) { - if (name.empty()) - return false; - - // vertical font start with @, we will filter it out - // Not sure if it is only in Windows so filtering is on all platforms - if (name[0] == '@') - return false; - - // previously detected bad font - auto it = std::lower_bound(bad.begin(), bad.end(), name); - if (it != bad.end() && *it == name) - return false; - - wxFont wx_font(wxFontInfo().FaceName(name).Encoding(coding)); - // Faster chech if wx_font is loadable but not 100% - // names could contain not loadable font - if (!wx_font.IsOk()) - return false; - - if (!can_load(wx_font)) - return false; - - return true; - }; - - std::sort(facenames.begin(), facenames.end()); - for (const wxString &name : facenames) { - if (is_valid_font(name)) { - valid_font_names.push_back(name.ToStdString()); - } - else { - bad_fonts.emplace_back(name); - } - } - assert(std::is_sorted(bad_fonts.begin(), bad_fonts.end())); - - for (auto iter = font_black_list.begin(); iter != font_black_list.end(); ++iter) { - valid_font_names.erase(std::remove(valid_font_names.begin(), valid_font_names.end(), *iter), valid_font_names.end()); - } - - return valid_font_names; -} - -class Line_3D -{ -public: - Line_3D(Vec3d i_a, Vec3d i_b) : a(i_a), b(i_b) {} - - double length() { return (b - a).cast().norm(); } - - Vec3d vector() - { - Vec3d new_vec = b - a; - new_vec.normalize(); - return new_vec; - } - - void reverse() { std::swap(this->a, this->b); } - - Vec3d a; - Vec3d b; -}; - -class Polygon_3D -{ -public: - Polygon_3D(const std::vector &points) : m_points(points) {} - - std::vector get_lines() - { - std::vector lines; - lines.reserve(m_points.size()); - if (m_points.size() > 2) { - for (int i = 0; i < m_points.size() - 1; ++i) { lines.push_back(Line_3D(m_points[i], m_points[i + 1])); } - lines.push_back(Line_3D(m_points.back(), m_points.front())); - } - return lines; - } - std::vector m_points; -}; - -// for debug -void export_regions_to_svg(const Point &point, const Polygons &polylines) -{ - std::string path = "D:/svg_profiles/text_poly.svg"; - //BoundingBox bbox = get_extents(polylines); - SVG svg(path.c_str()); - svg.draw(polylines, "green"); - svg.draw(point, "red", 5e6); -} - -int preNUm(unsigned char byte) -{ - unsigned char mask = 0x80; - int num = 0; - for (int i = 0; i < 8; i++) { - if ((byte & mask) == mask) { - mask = mask >> 1; - num++; - } else { - break; - } - } - return num; -} - -// https://www.jianshu.com/p/a83d398e3606 -bool get_utf8_sub_strings(char *data, int len, std::vector &out_strs) -{ - out_strs.clear(); - std::string str = std::string(data); - - int num = 0; - int i = 0; - while (i < len) { - if ((data[i] & 0x80) == 0x00) { - out_strs.emplace_back(str.substr(i, 1)); - i++; - continue; - } else if ((num = preNUm(data[i])) > 2) { - int start = i; - i++; - for (int j = 0; j < num - 1; j++) { - if ((data[i] & 0xc0) != 0x80) { return false; } - i++; - } - out_strs.emplace_back(str.substr(start, i - start)); - } else { - return false; - } - } - return true; -} - -/////////////////////// -/// GLGizmoText start -GLGizmoText::GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) - : GLGizmoBase(parent, icon_filename, sprite_id) -{ -} - -GLGizmoText::~GLGizmoText() -{ - for (int i = 0; i < m_textures.size(); i++) { - if (m_textures[i].texture != nullptr) - delete m_textures[i].texture; - } -} - -bool GLGizmoText::on_init() -{ - m_avail_font_names = init_face_names(); - - //m_avail_font_names = init_occt_fonts(); - update_font_texture(); - m_scale = m_imgui->get_font_size(); - - m_grabbers.push_back(Grabber()); - - reset_text_info(); - - m_desc["font"] = _L("Font"); - m_desc["size"] = _L("Size"); - m_desc["thickness"] = _L("Thickness"); - m_desc["text_gap"] = _L("Text Gap"); - m_desc["angle"] = _L("Angle"); - m_desc["embeded_depth"] = _L("Embedded depth"); - m_desc["input_text"] = _L("Input text"); - - m_desc["surface"] = _L("Surface"); - m_desc["horizontal_text"] = _L("Horizontal text"); - - m_desc["rotate_text_caption"] = _L("Shift+") + _L("Mouse move up or down"); - m_desc["rotate_text"] = _L("Rotate text"); - - return true; -} - -void GLGizmoText::update_font_texture() -{ - m_font_names.clear(); - for (int i = 0; i < m_textures.size(); i++) { - if (m_textures[i].texture != nullptr) - delete m_textures[i].texture; - } - m_combo_width = 0.0f; - m_combo_height = 0.0f; - m_textures.clear(); - m_textures.reserve(m_avail_font_names.size()); - for (int i = 0; i < m_avail_font_names.size(); i++) - { - GLTexture* texture = new GLTexture(); - auto face = wxString::FromUTF8(m_avail_font_names[i]); - auto retina_scale = m_parent.get_scale(); - wxFont font { (int)round(retina_scale * FONT_SIZE), wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, face }; - int w, h, hl; - if (texture->generate_texture_from_text(m_avail_font_names[i], font, w, h, hl, FONT_TEXTURE_BG, FONT_TEXTURE_FG)) { - //if (h < m_imgui->scaled(2.f)) { - TextureInfo info; - info.texture = texture; - info.w = w; - info.h = h; - info.hl = hl; - info.font_name = m_avail_font_names[i]; - m_textures.push_back(info); - m_combo_width = std::max(m_combo_width, static_cast(texture->m_original_width)); - m_font_names.push_back(info.font_name); - //} - } - } - m_combo_height = m_imgui->scaled(32.f / 15.f); -} - -bool GLGizmoText::is_mesh_point_clipped(const Vec3d &point, const Transform3d &trafo) const -{ - if (m_c->object_clipper()->get_position() == 0.) - return false; - - auto sel_info = m_c->selection_info(); - Vec3d transformed_point = trafo * point; - transformed_point(2) += sel_info->get_sla_shift(); - return m_c->object_clipper()->get_clipping_plane()->is_point_clipped(transformed_point); -} - -BoundingBoxf3 GLGizmoText::bounding_box() const -{ - BoundingBoxf3 ret; - const Selection & selection = m_parent.get_selection(); - const Selection::IndicesList &idxs = selection.get_volume_idxs(); - for (unsigned int i : idxs) { - const GLVolume *volume = selection.get_volume(i); - if (!volume->is_modifier) ret.merge(volume->transformed_convex_hull_bounding_box()); - } - return ret; -} - -bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down) -{ - std::string text = std::string(m_text); - if (text.empty()) - return true; - - const ModelObject * mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) - return true; - - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - const Camera & camera = wxGetApp().plater()->get_camera(); - - if (action == SLAGizmoEventType::Moving) { - if (shift_down && !alt_down && !control_down) { - float angle = m_rotate_angle + 0.5 * (m_mouse_position - mouse_position).y(); - if (angle == 0) - return true; - - while (angle < 0) - angle += 360; - - while (angle >= 360) - angle -= 360; - - m_rotate_angle = angle; - m_shift_down = true; - m_need_update_text = true; - } else { - m_shift_down = false; - m_origin_mouse_position = mouse_position; - } - m_mouse_position = mouse_position; - } - else if (action == SLAGizmoEventType::LeftDown) { - if (m_is_modify) - return false; - - Plater *plater = wxGetApp().plater(); - if (!plater || m_thickness <= 0) - return true; - - ModelObject *model_object = selection.get_model()->objects[m_object_idx]; - if (m_preview_text_volume_id > 0) { - model_object->delete_volume(m_preview_text_volume_id); - plater->update(); - m_preview_text_volume_id = -1; - } - - // Precalculate transformations of individual meshes. - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); } - } - - Vec3f normal = Vec3f::Zero(); - Vec3f hit = Vec3f::Zero(); - size_t facet = 0; - Vec3f closest_hit = Vec3f::Zero(); - Vec3f closest_normal = Vec3f::Zero(); - double closest_hit_squared_distance = std::numeric_limits::max(); - int closest_hit_mesh_id = -1; - - // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh - for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { - MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh_ptr()); - - if (mesh_raycaster.unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal, - m_c->object_clipper()->get_clipping_plane(), &facet)) { - // In case this hit is clipped, skip it. - if (is_mesh_point_clipped(hit.cast(), trafo_matrices[mesh_id])) - continue; - - // Is this hit the closest to the camera so far? - double hit_squared_distance = (camera.get_position() - trafo_matrices[mesh_id] * hit.cast()).squaredNorm(); - if (hit_squared_distance < closest_hit_squared_distance) { - closest_hit_squared_distance = hit_squared_distance; - closest_hit_mesh_id = mesh_id; - closest_hit = hit; - closest_normal = normal; - } - } - } - - if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero()) - return true; - - m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_normal}; - - m_is_modify = true; - generate_text_volume(false); - plater->update(); - } - - return true; -} - -bool GLGizmoText::on_mouse(const wxMouseEvent &mouse_event) -{ - // wxCoord == int --> wx/types.h - Vec2i32 mouse_coord(mouse_event.GetX(), mouse_event.GetY()); - Vec2d mouse_pos = mouse_coord.cast(); - bool control_down = mouse_event.CmdDown(); - - if (mouse_event.Moving()) { - gizmo_event(SLAGizmoEventType::Moving, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), control_down); - } - - // when control is down we allow scene pan and rotation even when clicking - // over some object - bool grabber_contains_mouse = (get_hover_id() != -1); - - if (mouse_event.LeftDown()) { - if ((!control_down || grabber_contains_mouse) && - gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, mouse_event.ShiftDown(), mouse_event.AltDown(), false)) - // the gizmo got the event and took some action, there is no need - // to do anything more - return true; - } - - return use_grabbers(mouse_event); -} - -void GLGizmoText::on_register_raycasters_for_picking() -{ - // the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account - m_parent.set_raycaster_gizmos_on_top(true); -} - -void GLGizmoText::on_unregister_raycasters_for_picking() { m_parent.set_raycaster_gizmos_on_top(false); } - -void GLGizmoText::on_set_state() -{ - if (m_state == EState::On) { - if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) { - ModelVolume *model_volume = get_selected_single_volume(m_object_idx, m_volume_idx); - if (model_volume) { - TextInfo text_info = model_volume->get_text_info(); - if (!text_info.m_text.empty()) { - load_from_text_info(text_info); - m_is_modify = true; - } - } - } - } - else if (m_state == EState::Off) { - reset_text_info(); - delete_temp_preview_text_volume(); - m_parent.use_slope(false); - m_parent.toggle_model_objects_visibility(true); - } -} - -CommonGizmosDataID GLGizmoText::on_get_requirements() const -{ - return CommonGizmosDataID( - int(CommonGizmosDataID::SelectionInfo) - | int(CommonGizmosDataID::InstancesHider) - | int(CommonGizmosDataID::Raycaster) - | int(CommonGizmosDataID::ObjectClipper)); -} - -std::string GLGizmoText::on_get_name() const -{ - return _u8L("Text shape"); -} - -bool GLGizmoText::on_is_activable() const -{ - // This is assumed in GLCanvas3D::do_rotate, do not change this - // without updating that function too. - if (m_parent.get_selection().is_single_full_instance()) - return true; - - int obejct_idx, volume_idx; - ModelVolume *model_volume = get_selected_single_volume(obejct_idx, volume_idx); - if (model_volume) - return !model_volume->get_text_info().m_text.empty(); - - return false; -} - -void GLGizmoText::on_render() -{ - glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - glsafe(::glEnable(GL_DEPTH_TEST)); - - std::string text = std::string(m_text); - if (text.empty()) { - delete_temp_preview_text_volume(); - return; - } - - ModelObject *mo = nullptr; - mo = m_c->selection_info()->model_object(); - - if (mo == nullptr) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - - if (mo == nullptr) { - BOOST_LOG_TRIVIAL(info) << boost::format("Text: selected object is null"); - return; - } - - // First check that the mouse pointer is on an object. - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[0]; - Plater *plater = wxGetApp().plater(); - if (!plater) - return; - - if (!m_is_modify || m_shift_down) { - const Camera &camera = wxGetApp().plater()->get_camera(); - // Precalculate transformations of individual meshes. - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - } - // Raycast and return if there's no hit. - Vec2d mouse_pos; - if (m_shift_down) { - if (m_is_modify) - mouse_pos = m_rr.mouse_position; - else - mouse_pos = m_origin_mouse_position; - } - else { - mouse_pos = m_parent.get_local_mouse_position(); - } - - bool position_changed = update_raycast_cache(mouse_pos, camera, trafo_matrices); - - if (m_rr.mesh_id == -1) { - delete_temp_preview_text_volume(); - return; - } - - if (!position_changed && !m_need_update_text && !m_shift_down) - return; - } - - if (m_is_modify && m_grabbers.size() == 1) { - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - } - } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - - float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize); - - m_grabbers[0].center = m_mouse_position_world; - m_grabbers[0].enabled = true; - - GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light"); - if (shader != nullptr) { - shader->start_using(); - shader->set_uniform("emission_factor", 0.1f); - render_grabbers(mean_size); - - shader->stop_using(); - } - } - - delete_temp_preview_text_volume(); - - if (m_is_modify && !m_need_update_text) - return; - - generate_text_volume(); - plater->update(); -} - -void GLGizmoText::on_dragging(const UpdateData &data) -{ - Vec2d mouse_pos = Vec2d(data.mouse_pos.x(), data.mouse_pos.y()); - const ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) return; - - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - const Camera & camera = wxGetApp().plater()->get_camera(); - - std::vector trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); } - } - - Vec3f normal = Vec3f::Zero(); - Vec3f hit = Vec3f::Zero(); - size_t facet = 0; - Vec3f closest_hit = Vec3f::Zero(); - Vec3f closest_normal = Vec3f::Zero(); - double closest_hit_squared_distance = std::numeric_limits::max(); - int closest_hit_mesh_id = -1; - - // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh - for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { - if (mesh_id == m_volume_idx) - continue; - - MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh_ptr()); - - if (mesh_raycaster.unproject_on_mesh(mouse_pos, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), - &facet)) { - // In case this hit is clipped, skip it. - if (is_mesh_point_clipped(hit.cast(), trafo_matrices[mesh_id])) continue; - - // Is this hit the closest to the camera so far? - double hit_squared_distance = (camera.get_position() - trafo_matrices[mesh_id] * hit.cast()).squaredNorm(); - if (hit_squared_distance < closest_hit_squared_distance) { - closest_hit_squared_distance = hit_squared_distance; - closest_hit_mesh_id = mesh_id; - closest_hit = hit; - closest_normal = normal; - } - } - } - - if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero()) return; - - if (closest_hit_mesh_id != -1) { - m_rr = {mouse_pos, closest_hit_mesh_id, closest_hit, closest_normal}; - m_need_update_text = true; - } -} - -void GLGizmoText::push_button_style(bool pressed) { - if (m_is_dark_mode) { - if (pressed) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f)); - } - else { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(45.f / 255.f, 45.f / 255.f, 49.f / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(45.f / 255.f, 45.f / 255.f, 49.f / 255.f, 1.f)); - } - } - else { - if (pressed) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f)); - } - else { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(238 / 255.f, 238 / 255.f, 238 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(238 / 255.f, 238 / 255.f, 238 / 255.f, 1.f)); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.f, 1.f, 1.f, 1.f)); - } - - } -} - -void GLGizmoText::pop_button_style() { - ImGui::PopStyleColor(4); -} - -void GLGizmoText::push_combo_style(const float scale) { - if (m_is_dark_mode) { - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG_DARK); - ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG_DARK); - ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); - } - else { - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale); - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG); - ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f)); - ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f)); - ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG); - ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f }); - } -} - -void GLGizmoText::pop_combo_style() -{ - ImGui::PopStyleVar(2); - ImGui::PopStyleColor(7); -} - -// BBS -void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit) -{ - if (m_imgui->get_font_size() != m_scale) { - m_scale = m_imgui->get_font_size(); - update_font_texture(); - } - if (m_textures.size() == 0) { - BOOST_LOG_TRIVIAL(info) << "GLGizmoText has no texture"; - return; - } - - const Selection &selection = m_parent.get_selection(); - if (selection.is_single_full_instance() || selection.is_single_full_object()) { - const GLVolume * gl_volume = selection.get_first_volume(); - int object_idx = gl_volume->object_idx(); - if (object_idx != m_object_idx || (object_idx == m_object_idx && m_volume_idx != -1)) { - m_object_idx = object_idx; - m_volume_idx = -1; - reset_text_info(); - } - } else if (selection.is_single_volume() || selection.is_single_modifier()) { - int object_idx, volume_idx; - ModelVolume *model_volume = get_selected_single_volume(object_idx, volume_idx); - if ((object_idx != m_object_idx || (object_idx == m_object_idx && volume_idx != m_volume_idx)) - && model_volume) { - TextInfo text_info = model_volume->get_text_info(); - load_from_text_info(text_info); - m_is_modify = true; - m_volume_idx = volume_idx; - m_object_idx = object_idx; - } - } - - const float win_h = ImGui::GetWindowHeight(); - y = std::min(y, bottom_limit - win_h); - GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f); - - static float last_y = 0.0f; - static float last_h = 0.0f; - - const float currt_scale = m_parent.get_scale(); - ImGuiWrapper::push_toolbar_style(currt_scale); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0,5.0) * currt_scale); - ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale); - GizmoImguiBegin("Text", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); - - const float space_size = m_imgui->get_style_scaling() * 8; - const std::array cap_array = std::array{ "font", "size", "thickness", "text_gap", "angle", "embeded_depth", "input_text" }; - float caption_size = 0.0f; - for (const auto &t : cap_array) { - caption_size = std::max(caption_size, m_imgui->calc_text_size(m_desc[t]).x); - } - caption_size += space_size + ImGui::GetStyle().WindowPadding.x; - - float input_text_size = m_imgui->scaled(10.0f); - float button_size = ImGui::GetFrameHeight(); - - ImVec2 selectable_size(std::max((input_text_size + ImGui::GetFrameHeight() * 2), m_combo_width + SELECTABLE_INNER_OFFSET * currt_scale), m_combo_height); - float list_width = selectable_size.x + ImGui::GetStyle().ScrollbarSize + 2 * currt_scale; - - float input_size = list_width - button_size * 2 - ImGui::GetStyle().ItemSpacing.x * 4; - - ImTextureID normal_B = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B); - ImTextureID normal_T = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T); - ImTextureID normal_B_dark = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_B_DARK); - ImTextureID normal_T_dark = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TEXT_T_DARK); - - // adjust window position to avoid overlap the view toolbar - if (last_h != win_h || last_y != y) { - // ask canvas for another frame to render the window in the correct position - m_imgui->set_requires_extra_frame(); - if (last_h != win_h) - last_h = win_h; - if (last_y != y) - last_y = y; - } - - ImGui::AlignTextToFramePadding(); - - m_imgui->text(m_desc["font"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(list_width); - push_combo_style(currt_scale); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * currt_scale); - - std::vector filtered_items_idx; - bool is_filtered = false; - if (m_imgui->bbl_combo_with_filter("##Combo_Font", m_font_names[m_curr_font_idx], m_font_names, &filtered_items_idx, &is_filtered, selectable_size.y)) { - int show_items_count = is_filtered ? filtered_items_idx.size() : m_textures.size(); - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(SELECTABLE_INNER_OFFSET, 0)* currt_scale); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0); - for (int i = 0; i < show_items_count; i++) - { - int idx = is_filtered ? filtered_items_idx[i] : i; - const bool is_selected = (idx == m_curr_font_idx); - ImTextureID icon_id = (ImTextureID)(intptr_t)(m_textures[idx].texture->get_id()); - ImVec4 tint_color = ImGui::GetStyleColorVec4(ImGuiCol_Text); - if (ImGui::BBLImageSelectable(icon_id, selectable_size, { (float)m_textures[idx].w, (float)m_textures[idx].h }, m_textures[idx].hl, tint_color, { 0, 0 }, { 1, 1 }, is_selected)) - { - m_curr_font_idx = idx; - m_font_name = m_textures[m_curr_font_idx].font_name; - ImGui::CloseCurrentPopup(); - m_need_update_text = true; - } - if (is_selected) { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::PopStyleVar(3); - ImGui::EndListBox(); - ImGui::EndPopup(); - } - - ImGui::PopStyleVar(2); - pop_combo_style(); - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["size"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(input_size); - if(ImGui::InputFloat("###font_size", &m_font_size, 0.0f, 0.0f, "%.2f")) - m_need_update_text = true; - if (m_font_size < 3.0f)m_font_size = 3.0f; - ImGui::SameLine(); - - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * currt_scale); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {1.0f * currt_scale, 1.0f * currt_scale }); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f * currt_scale); - push_button_style(m_bold); - if (ImGui::ImageButton(m_is_dark_mode ? normal_B_dark : normal_B, {button_size - 2 * ImGui::GetStyle().FramePadding.x, button_size - 2 * ImGui::GetStyle().FramePadding.y})) { - m_bold = !m_bold; - m_need_update_text = true; - } - pop_button_style(); - ImGui::SameLine(); - push_button_style(m_italic); - if (ImGui::ImageButton(m_is_dark_mode ? normal_T_dark : normal_T, {button_size - 2 * ImGui::GetStyle().FramePadding.x, button_size - 2 * ImGui::GetStyle().FramePadding.y})) { - m_italic = !m_italic; - m_need_update_text = true; - } - pop_button_style(); - ImGui::PopStyleVar(3); - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["thickness"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(list_width); - float old_value = m_thickness; - ImGui::InputFloat("###text_thickness", &m_thickness, 0.0f, 0.0f, "%.2f"); - if (m_thickness < 0.1f) - m_thickness = 0.1f; - if (old_value != m_thickness) - m_need_update_text = true; - - const float slider_icon_width = m_imgui->get_slider_icon_size().x; - const float slider_width = list_width - 1.5 * slider_icon_width - space_size; - const float drag_left_width = caption_size + slider_width + space_size; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["text_gap"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(slider_width); - if (m_imgui->bbl_slider_float_style("##text_gap", &m_text_gap, -100, 100, "%.2f", 1.0f, true)) - m_need_update_text = true; - ImGui::SameLine(drag_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - if (ImGui::BBLDragFloat("##text_gap_input", &m_text_gap, 0.05f, 0.0f, 0.0f, "%.2f")) - m_need_update_text = true; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["angle"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(slider_width); - if (m_imgui->bbl_slider_float_style("##angle", &m_rotate_angle, 0, 360, "%.2f", 1.0f, true)) - m_need_update_text = true; - ImGui::SameLine(drag_left_width); - ImGui::PushItemWidth(1.5 * slider_icon_width); - if (ImGui::BBLDragFloat("##angle_input", &m_rotate_angle, 0.05f, 0.0f, 0.0f, "%.2f")) - m_need_update_text = true; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["embeded_depth"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(list_width); - old_value = m_embeded_depth; - ImGui::InputFloat("###text_embeded_depth", &m_embeded_depth, 0.0f, 0.0f, "%.2f"); - if (m_embeded_depth < 0.f) - m_embeded_depth = 0.f; - if (old_value != m_embeded_depth) - m_need_update_text = true; - - ImGui::AlignTextToFramePadding(); - m_imgui->text(m_desc["input_text"]); - ImGui::SameLine(caption_size); - ImGui::PushItemWidth(list_width); - - if(ImGui::InputText("", m_text, sizeof(m_text))) - m_need_update_text = true; - - ImGui::Separator(); - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f)); - float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y; - show_tooltip_information(x, get_cur_y); - - float f_scale = m_parent.get_gizmos_manager().get_layout_scale(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f * f_scale)); - - ImGui::SameLine(caption_size); - ImGui::AlignTextToFramePadding(); - if (m_imgui->bbl_checkbox(m_desc["surface"], m_is_surface_text)) - m_need_update_text = true; - - ImGui::SameLine(); - ImGui::AlignTextToFramePadding(); - if (m_imgui->bbl_checkbox(m_desc["horizontal_text"], m_keep_horizontal)) - m_need_update_text = true; - - //ImGui::SameLine(); - //ImGui::AlignTextToFramePadding(); - //m_imgui->text(_L("Status") + ": "); - //float status_cap = m_imgui->calc_text_size(_L("Status:")).x + space_size + ImGui::GetStyle().WindowPadding.x; - //ImGui::SameLine(); - //m_imgui->text(m_is_modify ? _L("Modify") : _L("Add")); - - ImGui::PopStyleVar(2); - -#if 0 - ImGuiIO& io = ImGui::GetIO(); - ImFontAtlas* atlas = io.Fonts; - ImVec4 tint_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); - ImVec4 border_col = ImVec4(0.0f, 0.0f, 0.0f, 0.8f); - m_imgui->text(wxString("") << atlas->TexWidth << " * " << atlas->TexHeight); - ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); -#endif - - GizmoImguiEnd(); - ImGui::PopStyleVar(2); - ImGuiWrapper::pop_toolbar_style(); -} - -void GLGizmoText::show_tooltip_information(float x, float y) -{ - std::array info_array = std::array{"rotate_text"}; - float caption_max = 0.f; - for (const auto &t : info_array) { caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x); } - - ImTextureID normal_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP); - ImTextureID hover_id = m_parent.get_gizmos_manager().get_icon_texture_id(GLGizmosManager::MENU_ICON_NAME::IC_TOOLBAR_TOOLTIP_HOVER); - - caption_max += m_imgui->calc_text_size(": ").x + 35.f; - - float font_size = ImGui::GetFontSize(); - ImVec2 button_size = ImVec2(font_size * 1.8, font_size * 1.3); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, ImGui::GetStyle().FramePadding.y}); - ImGui::ImageButton3(normal_id, hover_id, button_size); - - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip2(ImVec2(x, y)); - auto draw_text_with_caption = [this, &caption_max](const wxString &caption, const wxString &text) { - m_imgui->text_colored(ImGuiWrapper::COL_ACTIVE, caption); - ImGui::SameLine(caption_max); - m_imgui->text_colored(ImGuiWrapper::COL_WINDOW_BG, text); - }; - - for (const auto &t : info_array) draw_text_with_caption(m_desc.at(t + "_caption") + ": ", m_desc.at(t)); - ImGui::EndTooltip(); - } - ImGui::PopStyleVar(2); -} - -void GLGizmoText::reset_text_info() -{ - m_font_name = ""; - m_font_size = 16.f; - m_curr_font_idx = 0; - m_bold = true; - m_italic = false; - m_thickness = 2.f; - strcpy(m_text, m_font_name.c_str()); - m_embeded_depth = 0.f; - m_rotate_angle = 0; - m_text_gap = 0.f; - m_is_surface_text = true; - m_keep_horizontal = false; - - m_is_modify = false; - m_grabbers[0].enabled = false; -} - -bool GLGizmoText::update_text_positions(const std::vector& texts) -{ - std::vector text_lengths; - for (int i = 0; i < texts.size(); ++i) { - std::string alpha; - if (texts[i] == " ") { - alpha = "i"; - } else { - alpha = texts[i]; - } - TextResult text_result; - load_text_shape(alpha.c_str(), m_font_name.c_str(), m_font_size, m_thickness + m_embeded_depth, m_bold, m_italic, text_result); - double half_x_length = text_result.text_width / 2; - text_lengths.emplace_back(half_x_length); - } - - int text_num = texts.size(); - m_position_points.clear(); - m_normal_points.clear(); - ModelObject *mo = m_c->selection_info()->model_object(); - if (m_is_modify) { - const Selection &selection = m_parent.get_selection(); - mo = selection.get_model()->objects[m_object_idx]; - } - if (mo == nullptr) - return false; - - const Selection & selection = m_parent.get_selection(); - const ModelInstance *mi = mo->instances[selection.get_instance_idx()]; - - // Precalculate transformations of individual meshes. - std::vector trafo_matrices; - std::vector rotate_trafo_matrices; - for (const ModelVolume *mv : mo->volumes) { - if (mv->is_model_part()) { - trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); - rotate_trafo_matrices.emplace_back(mi->get_transformation().get_matrix(true, false, true, true) * mv->get_matrix(true, false, true, true)); - } - } - - if (m_rr.mesh_id == -1) { - BOOST_LOG_TRIVIAL(info) << boost::format("Text: mrr_mesh_id is -1"); - return false; - } - - m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2)); - m_mouse_normal_world = rotate_trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.normal(0), m_rr.normal(1), m_rr.normal(2)); - - TriangleMesh slice_meshs; - int mesh_index = 0; - int volume_index = 0; - for (int i = 0; i < mo->volumes.size(); ++i) { - // skip the editing text volume - if (m_is_modify && m_volume_idx == i) - continue; - - ModelVolume *mv = mo->volumes[i]; - if (mv->is_model_part()) { - if (mesh_index == m_rr.mesh_id) { - volume_index = i; - } - TriangleMesh vol_mesh(mv->mesh()); - vol_mesh.transform(mv->get_matrix()); - slice_meshs.merge(vol_mesh); - mesh_index++; - } - } - - ModelVolume* volume = mo->volumes[volume_index]; - - Vec3d temp_position = m_mouse_position_world; - Vec3d temp_normal = m_mouse_normal_world; - - Vec3d cut_plane = Vec3d::UnitY(); - double epson = 1e-6; - if (!(abs(temp_normal.x()) <= epson && abs(temp_normal.y()) <= epson && abs(temp_normal.z()) > epson)) { // temp_normal != Vec3d::UnitZ() - Vec3d v_plane = temp_normal.cross(Vec3d::UnitZ()); - cut_plane = v_plane.cross(temp_normal); - } - - Transform3d rotate_trans; - rotate_trans.setIdentity(); - rotate_trans.rotate(Eigen::AngleAxisd(Geometry::deg2rad(m_rotate_angle), temp_normal)); - cut_plane = rotate_trans * cut_plane; - - m_cut_plane_dir = cut_plane; - - if (m_keep_horizontal && m_mouse_normal_world != Vec3d::UnitZ()) - m_cut_plane_dir = Vec3d::UnitZ(); - - if (!m_is_surface_text) { - m_position_points.resize(text_num); - m_normal_points.resize(text_num); - - Vec3d pos_dir = m_cut_plane_dir.cross(m_mouse_normal_world); - pos_dir.normalize(); - if (text_num % 2 == 1) { - m_position_points[text_num / 2] = m_mouse_position_world; - for (int i = 0; i < text_num / 2; ++i) { - double left_gap = text_lengths[text_num / 2 - i - 1] + m_text_gap + text_lengths[text_num / 2 - i]; - if (left_gap < 0) - left_gap = 0; - - double right_gap = text_lengths[text_num / 2 + i + 1] + m_text_gap + text_lengths[text_num / 2 + i]; - if (right_gap < 0) - right_gap = 0; - - m_position_points[text_num / 2 - 1 - i] = m_position_points[text_num / 2 - i] - left_gap * pos_dir; - m_position_points[text_num / 2 + 1 + i] = m_position_points[text_num / 2 + i] + right_gap * pos_dir; - } - } else { - for (int i = 0; i < text_num / 2; ++i) { - double left_gap = i == 0 ? (text_lengths[text_num / 2 - i - 1] + m_text_gap / 2) : - (text_lengths[text_num / 2 - i - 1] + m_text_gap + text_lengths[text_num / 2 - i]); - if (left_gap < 0) - left_gap = 0; - - double right_gap = i == 0 ? (text_lengths[text_num / 2 + i] + m_text_gap / 2) : - (text_lengths[text_num / 2 + i] + m_text_gap + text_lengths[text_num / 2 + i - 1]); - if (right_gap < 0) - right_gap = 0; - - if (i == 0) { - m_position_points[text_num / 2 - 1 - i] = m_mouse_position_world - left_gap * pos_dir; - m_position_points[text_num / 2 + i] = m_mouse_position_world + right_gap * pos_dir; - continue; - } - - m_position_points[text_num / 2 - 1 - i] = m_position_points[text_num / 2 - i] - left_gap * pos_dir; - m_position_points[text_num / 2 + i] = m_position_points[text_num / 2 + i - 1] + right_gap * pos_dir; - } - } - - for (int i = 0; i < text_num; ++i) { - m_normal_points[i] = m_mouse_normal_world; - } - - return true; - } - - double phi; - Vec3d rotation_axis; - Matrix3d rotation_matrix; - Geometry::rotation_from_two_vectors(m_cut_plane_dir, Vec3d::UnitZ(), rotation_axis, phi, &rotation_matrix); - if (abs(phi - PI) < 1e-6) { - Transform3d transform = Transform3d::Identity(); - transform.rotate(Eigen::AngleAxisd(phi, m_mouse_normal_world)); - rotation_matrix = transform.matrix().block<3, 3>(0, 0); - } - - Transform3d transfo1; - transfo1.setIdentity(); - transfo1.translate(-(mi->get_transformation().get_offset() + volume->get_transformation().get_offset())); - transfo1 = rotation_matrix * transfo1; - - Transform3d transfo2; - transfo2.setIdentity(); - transfo2.translate(mi->get_transformation().get_offset() + volume->get_transformation().get_offset()); - Transform3d transfo = transfo2 * transfo1; - - Vec3d click_point = transfo * temp_position; - - MeshSlicingParams slicing_params; - slicing_params.trafo = transfo * mi->get_transformation().get_matrix() /** volume->get_transformation().get_matrix()*/; - // for debug - // its_write_obj(slice_meshs.its, "D:/debug_files/mesh.obj"); - - // generate polygons - const Polygons temp_polys = slice_mesh(slice_meshs.its, click_point.z(), slicing_params); - - m_mouse_position_world = click_point; - m_mouse_normal_world = transfo * temp_normal; - - m_mouse_position_world.x() *= 1e6; - m_mouse_position_world.y() *= 1e6; - - // for debug - //export_regions_to_svg(Point(m_mouse_position_world.x(), m_mouse_position_world.y()), temp_polys); - - Polygons polys = union_(temp_polys); - - auto point_in_line_rectange = [](const Line &line, const Point &point, double& distance) { - distance = line.distance_to(point); - return distance < line.length() / 2; - }; - - int index = 0; - double min_distance = 1e12; - Polygon hit_ploy; - for (const Polygon poly : polys) { - if (poly.points.size() == 0) - continue; - - Lines lines = poly.lines(); - for (int i = 0; i < lines.size(); ++i) { - Line line = lines[i]; - double distance = min_distance; - if (point_in_line_rectange(line, Point(m_mouse_position_world.x(), m_mouse_position_world.y()), distance)) { - if (distance < min_distance) { - min_distance = distance; - index = i; - hit_ploy = poly; - } - } - } - } - - if (hit_ploy.points.size() == 0) { - BOOST_LOG_TRIVIAL(info) << boost::format("Text: the hit polygon is null"); - return false; - } - - auto make_trafo_for_slicing = [](const Transform3d &trafo) -> Transform3d { - auto t = trafo; - static constexpr const double s = 1. / SCALING_FACTOR; - t.prescale(Vec3d(s, s, 1.)); - return t.cast(); - }; - transfo = make_trafo_for_slicing(transfo); - Transform3d transfo_inv = transfo.inverse(); - std::vector new_points; - for (int i = 0; i < hit_ploy.points.size(); ++i) { - new_points.emplace_back(transfo_inv * Vec3d(hit_ploy.points[i].x(), hit_ploy.points[i].y(), click_point.z())); - } - m_mouse_position_world = transfo_inv * m_mouse_position_world; - - Polygon_3D new_polygon(new_points); - m_position_points.resize(text_num); - if (text_num % 2 == 1) { - m_position_points[text_num / 2] = Vec3d(m_mouse_position_world.x(), m_mouse_position_world.y(), m_mouse_position_world.z()); - - std::vector lines = new_polygon.get_lines(); - Line_3D line = lines[index]; - { - int index1 = index; - double left_length = (m_mouse_position_world - line.a).cast().norm(); - int left_num = text_num / 2; - while (left_num > 0) { - double gap_length = (text_lengths[left_num] + m_text_gap + text_lengths[left_num - 1]); - if (gap_length < 0) - gap_length = 0; - - while (gap_length > left_length) { - gap_length -= left_length; - if (index1 == 0) - index1 = lines.size() - 1; - else - --index1; - left_length = lines[index1].length(); - } - - Vec3d direction = lines[index1].vector(); - direction.normalize(); - double distance_to_a = (left_length - gap_length); - Line_3D new_line = lines[index1]; - - double norm_value = direction.cast().norm(); - double deta_x = distance_to_a * direction.x() / norm_value; - double deta_y = distance_to_a * direction.y() / norm_value; - double deta_z = distance_to_a * direction.z() / norm_value; - Vec3d new_pos = new_line.a + Vec3d(deta_x, deta_y, deta_z); - left_num--; - m_position_points[left_num] = new_pos; - left_length = distance_to_a; - } - } - - { - int index2 = index; - double right_length = (line.b - m_mouse_position_world).cast().norm(); - int right_num = text_num / 2; - while (right_num > 0) { - double gap_length = (text_lengths[text_num - right_num] + m_text_gap + text_lengths[text_num - right_num - 1]); - if (gap_length < 0) - gap_length = 0; - - while (gap_length > right_length) { - gap_length -= right_length; - if (index2 == lines.size() - 1) - index2 = 0; - else - ++index2; - right_length = lines[index2].length(); - } - - Line_3D line2 = lines[index2]; - line2.reverse(); - Vec3d direction = line2.vector(); - direction.normalize(); - double distance_to_b = (right_length - gap_length); - Line_3D new_line = lines[index2]; - - double norm_value = direction.cast().norm(); - double deta_x = distance_to_b * direction.x() / norm_value; - double deta_y = distance_to_b * direction.y() / norm_value; - double deta_z = distance_to_b * direction.z() / norm_value; - Vec3d new_pos = new_line.b + Vec3d(deta_x, deta_y, deta_z); - m_position_points[text_num - right_num] = new_pos; - right_length = distance_to_b; - right_num--; - } - } - } - else { - for (int i = 0; i < text_num / 2; ++i) { - std::vector lines = new_polygon.get_lines(); - Line_3D line = lines[index]; - { - int index1 = index; - double left_length = (m_mouse_position_world - line.a).cast().norm(); - int left_num = text_num / 2; - for (int i = 0; i < text_num / 2; ++i) { - double gap_length = 0; - if (i == 0) { - gap_length = m_text_gap / 2 + text_lengths[text_num / 2 - 1 - i]; - } - else { - gap_length = text_lengths[text_num / 2 - i] + m_text_gap + text_lengths[text_num / 2 - 1 - i]; - } - if (gap_length < 0) - gap_length = 0; - - while (gap_length > left_length) { - gap_length -= left_length; - if (index1 == 0) - index1 = lines.size() - 1; - else - --index1; - left_length = lines[index1].length(); - } - - Vec3d direction = lines[index1].vector(); - direction.normalize(); - double distance_to_a = (left_length - gap_length); - Line_3D new_line = lines[index1]; - - double norm_value = direction.cast().norm(); - double deta_x = distance_to_a * direction.x() / norm_value; - double deta_y = distance_to_a * direction.y() / norm_value; - double deta_z = distance_to_a * direction.z() / norm_value; - Vec3d new_pos = new_line.a + Vec3d(deta_x, deta_y,deta_z); - - m_position_points[text_num / 2 - 1 - i] = new_pos; - left_length = distance_to_a; - } - } - - { - int index2 = index; - double right_length = (line.b - m_mouse_position_world).cast().norm(); - int right_num = text_num / 2; - double gap_length = 0; - for (int i = 0; i < text_num / 2; ++i) { - double gap_length = 0; - if (i == 0) { - gap_length = m_text_gap / 2 + text_lengths[text_num / 2 + i]; - } else { - gap_length = text_lengths[text_num / 2 + i] + m_text_gap + text_lengths[text_num / 2 + i - 1]; - } - if (gap_length < 0) - gap_length = 0; - - while (gap_length > right_length) { - gap_length -= right_length; - if (index2 == lines.size() - 1) - index2 = 0; - else - ++index2; - right_length = lines[index2].length(); - } - - Line_3D line2 = lines[index2]; - line2.reverse(); - Vec3d direction = line2.vector(); - direction.normalize(); - double distance_to_b = (right_length - gap_length); - Line_3D new_line = lines[index2]; - - double norm_value = direction.cast().norm(); - double deta_x = distance_to_b * direction.x() / norm_value; - double deta_y = distance_to_b * direction.y() / norm_value; - double deta_z = distance_to_b * direction.z() / norm_value; - Vec3d new_pos = new_line.b + Vec3d(deta_x, deta_y, deta_z); - m_position_points[text_num / 2 + i] = new_pos; - right_length = distance_to_b; - } - } - } - } - - TriangleMesh mesh = slice_meshs; - std::vector mesh_values(m_position_points.size(), 1e9); - m_normal_points.resize(m_position_points.size()); - auto point_in_triangle_delete_area = [](const Vec3d &point, const Vec3d &point0, const Vec3d &point1, const Vec3d &point2) { - Vec3d p0_p = point - point0; - Vec3d p0_p1 = point1 - point0; - Vec3d p0_p2 = point2 - point0; - Vec3d p_p0 = point0 - point; - Vec3d p_p1 = point1 - point; - Vec3d p_p2 = point2 - point; - - double s = p0_p1.cross(p0_p2).norm(); - double s0 = p_p0.cross(p_p1).norm(); - double s1 = p_p1.cross(p_p2).norm(); - double s2 = p_p2.cross(p_p0).norm(); - - return abs(s0 + s1 + s2 - s); - }; - for (int i = 0; i < m_position_points.size(); ++i) { - for (auto indice : mesh.its.indices) { - stl_vertex stl_point0 = mesh.its.vertices[indice[0]]; - stl_vertex stl_point1 = mesh.its.vertices[indice[1]]; - stl_vertex stl_point2 = mesh.its.vertices[indice[2]]; - - Vec3d point0 = Vec3d(stl_point0[0], stl_point0[1], stl_point0[2]); - Vec3d point1 = Vec3d(stl_point1[0], stl_point1[1], stl_point1[2]); - Vec3d point2 = Vec3d(stl_point2[0], stl_point2[1], stl_point2[2]); - - point0 = mi->get_transformation().get_matrix() * point0; - point1 = mi->get_transformation().get_matrix() * point1; - point2 = mi->get_transformation().get_matrix() * point2; - - double abs_area = point_in_triangle_delete_area(m_position_points[i], point0, point1, point2); - if (mesh_values[i] > abs_area) { - mesh_values[i] = abs_area; - - Vec3d s1 = point1 - point0; - Vec3d s2 = point2 - point0; - m_normal_points[i] = s1.cross(s2); - m_normal_points[i].normalize(); - } - } - } - return true; -} - -TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &position, const Vec3d &normal, const Vec3d& text_up_dir) -{ - TextResult text_result; - load_text_shape(text_str, m_font_name.c_str(), m_font_size, m_thickness + m_embeded_depth, m_bold, m_italic, text_result); - TriangleMesh mesh = text_result.text_mesh; - - auto center = mesh.bounding_box().center(); - double mesh_offset = center.z(); - mesh.translate(-text_result.text_width / 2, -m_font_size / 4, -center.z()); - - double phi; - Vec3d rotation_axis; - Matrix3d rotation_matrix; - Geometry::rotation_from_two_vectors(Vec3d::UnitZ(), normal, rotation_axis, phi, &rotation_matrix); - mesh.rotate(phi, rotation_axis); - - auto project_on_plane = [](const Vec3d& dir, const Vec3d& plane_normal) -> Vec3d { - return dir - (plane_normal.dot(dir) * plane_normal.dot(plane_normal)) * plane_normal; - }; - - Vec3d old_text_dir = Vec3d::UnitY(); - old_text_dir = rotation_matrix * old_text_dir; - Vec3d new_text_dir = project_on_plane(text_up_dir, normal); - new_text_dir.normalize(); - Geometry::rotation_from_two_vectors(old_text_dir, new_text_dir, rotation_axis, phi, &rotation_matrix); - - if (abs(phi - PI) < EPSILON) - rotation_axis = normal; - - mesh.rotate(phi, rotation_axis); - - const Selection & selection = m_parent.get_selection(); - ModelObject * model_object = selection.get_model()->objects[m_object_idx]; - Geometry::Transformation instance_transformation = model_object->instances[0]->get_transformation(); - Vec3d offset = position - instance_transformation.get_offset(); - offset = offset + mesh_offset * normal; - offset = offset - m_embeded_depth * normal; - mesh.translate(offset.x(), offset.y(), offset.z()); - - return mesh; -} - -bool GLGizmoText::update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector &trafo_matrices) -{ - if (m_rr.mouse_position == mouse_position) { - return false; - } - - if (m_is_modify) - return false; - - Vec3f normal = Vec3f::Zero(); - Vec3f hit = Vec3f::Zero(); - size_t facet = 0; - Vec3f closest_hit = Vec3f::Zero(); - Vec3f closest_nromal = Vec3f::Zero(); - double closest_hit_squared_distance = std::numeric_limits::max(); - int closest_hit_mesh_id = -1; - - // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh - for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) { - if (m_preview_text_volume_id != -1 && mesh_id == int(trafo_matrices.size()) - 1) - continue; - - if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(), - &facet)) { - // In case this hit is clipped, skip it. - if (is_mesh_point_clipped(hit.cast(), trafo_matrices[mesh_id])) - continue; - - double hit_squared_distance = (camera.get_position() - trafo_matrices[mesh_id] * hit.cast()).squaredNorm(); - if (hit_squared_distance < closest_hit_squared_distance) { - closest_hit_squared_distance = hit_squared_distance; - closest_hit_mesh_id = mesh_id; - closest_hit = hit; - closest_nromal = normal; - } - } - } - - m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal}; - return true; -} - -void GLGizmoText::generate_text_volume(bool is_temp) -{ - std::string text = std::string(m_text); - if (text.empty()) - return; - - std::wstring_convert> str_cnv; - std::wstring ws = boost::nowide::widen(m_text); - std::vector alphas; - for (auto w : ws) { - alphas.push_back(str_cnv.to_bytes(w)); - } - - update_text_positions(alphas); - - if (m_position_points.size() == 0) - return; - - TriangleMesh mesh; - for (int i = 0; i < alphas.size(); ++i) { - TriangleMesh sub_mesh = get_text_mesh(alphas[i].c_str(), m_position_points[i], m_normal_points[i], m_cut_plane_dir); - mesh.merge(sub_mesh); - } - - if (mesh.empty()) - return; - - Plater *plater = wxGetApp().plater(); - if (!plater) - return; - - TextInfo text_info = get_text_info(); - if (m_is_modify && m_need_update_text) { - if (m_object_idx == -1 || m_volume_idx == -1) { - BOOST_LOG_TRIVIAL(error) << boost::format("Text: selected object_idx = %1%, volume_idx = %2%") % m_object_idx % m_volume_idx; - return; - } - - plater->take_snapshot("Modify Text"); - const Selection &selection = m_parent.get_selection(); - ModelObject * model_object = selection.get_model()->objects[m_object_idx]; - ModelVolume * model_volume = model_object->volumes[m_volume_idx]; - ModelVolume * new_model_volume = model_object->add_volume(std::move(mesh)); - new_model_volume->set_text_info(text_info); - new_model_volume->name = model_volume->name; - new_model_volume->set_type(model_volume->type()); - new_model_volume->config.apply(model_volume->config); - std::swap(model_object->volumes[m_volume_idx], model_object->volumes.back()); - model_object->delete_volume(model_object->volumes.size() - 1); - plater->update(); - } else { - if (m_need_update_text) - plater->take_snapshot("Add Text"); - ObjectList *obj_list = wxGetApp().obj_list(); - int volume_id = obj_list->load_mesh_part(mesh, "text_shape", text_info, is_temp); - m_preview_text_volume_id = is_temp ? volume_id : -1; - } - m_need_update_text = false; -} - -void GLGizmoText::delete_temp_preview_text_volume() -{ - const Selection &selection = m_parent.get_selection(); - if (m_preview_text_volume_id > 0) { - ModelObject *model_object = selection.get_model()->objects[m_object_idx]; - if (m_preview_text_volume_id < model_object->volumes.size()) { - Plater *plater = wxGetApp().plater(); - if (!plater) - return; - - model_object->delete_volume(m_preview_text_volume_id); - - plater->update(); - } - m_preview_text_volume_id = -1; - } -} - -TextInfo GLGizmoText::get_text_info() -{ - TextInfo text_info; - text_info.m_font_name = m_font_name; - text_info.m_font_size = m_font_size; - text_info.m_curr_font_idx = m_curr_font_idx; - text_info.m_bold = m_bold; - text_info.m_italic = m_italic; - text_info.m_thickness = m_thickness; - text_info.m_text = m_text; - text_info.m_rr = m_rr; - text_info.m_embeded_depth = m_embeded_depth; - text_info.m_rotate_angle = m_rotate_angle; - text_info.m_text_gap = m_text_gap; - text_info.m_is_surface_text = m_is_surface_text; - text_info.m_keep_horizontal = m_keep_horizontal; - return text_info; -} - -void GLGizmoText::load_from_text_info(const TextInfo &text_info) -{ - m_font_name = text_info.m_font_name; - m_font_size = text_info.m_font_size; - m_curr_font_idx = text_info.m_curr_font_idx; - m_bold = text_info.m_bold; - m_italic = text_info.m_italic; - m_thickness = text_info.m_thickness; - strcpy(m_text, text_info.m_text.c_str()); - m_rr = text_info.m_rr; - m_embeded_depth = text_info.m_embeded_depth; - m_rotate_angle = text_info.m_rotate_angle; - m_text_gap = text_info.m_text_gap; - m_is_surface_text = text_info.m_is_surface_text; - m_keep_horizontal = text_info.m_keep_horizontal; -} - -} // namespace GUI -} // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp b/src/slic3r/GUI/Gizmos/GLGizmoText.hpp deleted file mode 100644 index e187c72211..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmoText.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef slic3r_GLGizmoText_hpp_ -#define slic3r_GLGizmoText_hpp_ - -#include "GLGizmoBase.hpp" -#include "slic3r/GUI/3DScene.hpp" -#include "../GLTexture.hpp" -#include "../Camera.hpp" -#include "libslic3r/Model.hpp" - -namespace Slic3r { - -enum class ModelVolumeType : int; -class ModelVolume; - -namespace GUI { - -enum class SLAGizmoEventType : unsigned char; -class GLGizmoText : public GLGizmoBase -{ -private: - std::vector m_avail_font_names; - char m_text[1024] = { 0 }; - std::string m_font_name; - float m_font_size = 16.f; - int m_curr_font_idx = 0; - bool m_bold = true; - bool m_italic = false; - float m_thickness = 2.f; - float m_embeded_depth = 0.f; - float m_rotate_angle = 0; - float m_text_gap = 0.f; - bool m_is_surface_text = false; - bool m_keep_horizontal = false; - mutable RaycastResult m_rr; - - float m_combo_height = 0.0f; - float m_combo_width = 0.0f; - float m_scale; - - Vec2d m_mouse_position = Vec2d::Zero(); - Vec2d m_origin_mouse_position = Vec2d::Zero(); - bool m_shift_down = false; - - class TextureInfo { - public: - GLTexture* texture { nullptr }; - int h; - int w; - int hl; - - std::string font_name; - }; - - std::vector m_textures; - - std::vector m_font_names; - - bool m_is_modify = false; - bool m_need_update_text = false; - - int m_object_idx = -1; - int m_volume_idx = -1; - - int m_preview_text_volume_id = -1; - - Vec3d m_mouse_position_world = Vec3d::Zero(); - Vec3d m_mouse_normal_world = Vec3d::Zero(); - - Vec3d m_cut_plane_dir = Vec3d::UnitZ(); - - std::vector m_position_points; - std::vector m_normal_points; - - // This map holds all translated description texts, so they can be easily referenced during layout calculations - // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. - std::map m_desc; - -public: - GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); - ~GLGizmoText(); - - void update_font_texture(); - - bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down); - - bool on_mouse(const wxMouseEvent &mouse_event) override; - - bool is_mesh_point_clipped(const Vec3d &point, const Transform3d &trafo) const; - BoundingBoxf3 bounding_box() const; - -protected: - virtual bool on_init() override; - virtual std::string on_get_name() const override; - virtual bool on_is_activable() const override; - virtual void on_render() override; - virtual void on_dragging(const UpdateData &data) override; - void push_combo_style(const float scale); - void pop_combo_style(); - void push_button_style(bool pressed); - void pop_button_style(); - virtual void on_set_state() override; - virtual CommonGizmosDataID on_get_requirements() const override; - virtual void on_render_input_window(float x, float y, float bottom_limit); - virtual void on_register_raycasters_for_picking() override; - virtual void on_unregister_raycasters_for_picking() override; - - void show_tooltip_information(float x, float y); - -private: - ModelVolume *get_selected_single_volume(int& out_object_idx, int& out_volume_idx) const; - void reset_text_info(); - bool update_text_positions(const std::vector& texts); - TriangleMesh get_text_mesh(const char* text_str, const Vec3d &position, const Vec3d &normal, const Vec3d &text_up_dir); - - bool update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector &trafo_matrices); - void generate_text_volume(bool is_temp = true); - void delete_temp_preview_text_volume(); - - TextInfo get_text_info(); - void load_from_text_info(const TextInfo &text_info); -}; - -} // namespace GUI -} // namespace Slic3r - -#endif // slic3r_GLGizmoText_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/Gizmos/GLGizmos.hpp b/src/slic3r/GUI/Gizmos/GLGizmos.hpp deleted file mode 100644 index 1d1d036275..0000000000 --- a/src/slic3r/GUI/Gizmos/GLGizmos.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef slic3r_GLGizmos_hpp_ -#define slic3r_GLGizmos_hpp_ - -// this describes events being passed from GLCanvas3D to SlaSupport gizmo -namespace Slic3r { -namespace GUI { - -enum class SLAGizmoEventType : unsigned char { - LeftDown = 1, - LeftUp, - RightDown, - Dragging, - Delete, - SelectAll, - ShiftUp, - AltUp, - ApplyChanges, - DiscardChanges, - AutomaticGeneration, - ManualEditing, - MouseWheelUp, - MouseWheelDown, - ResetClippingPlane -}; - -} // namespace GUI -} // namespace Slic3r - -// BBS -#include "slic3r/GUI/Gizmos/GLGizmoMoveScale.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFlatten.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFuzzySkin.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" -// BBS -#include "slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" - -#endif //slic3r_GLGizmos_hpp_ diff --git a/src/slic3r/Utils/ProfileDescription.hpp b/src/slic3r/Utils/ProfileDescription.hpp deleted file mode 100644 index a048527ad7..0000000000 --- a/src/slic3r/Utils/ProfileDescription.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#ifndef _L -#define _L(s) Slic3r::I18N::translate(s) -#endif - -namespace ProfileDescrption { - const std::string PROFILE_DESCRIPTION_0 = _L("It has a small layer height. This results in almost negligible layer lines and high print quality. It is suitable for most printing cases."); - const std::string PROFILE_DESCRIPTION_1 = _L("Compared with the default profile of a 0.2 mm nozzle, it has lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in much higher print quality but a much longer print time."); - const std::string PROFILE_DESCRIPTION_2 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a slightly bigger layer height. This results in almost negligible layer lines and slightly shorter print time."); - const std::string PROFILE_DESCRIPTION_3 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a bigger layer height. This results in slightly visible layer lines but shorter print time."); - const std::string PROFILE_DESCRIPTION_4 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer height. This results in almost invisible layer lines and higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_5 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost invisible layer lines and much higher print quality but much longer print time."); - const std::string PROFILE_DESCRIPTION_6 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer height. This results in minimal layer lines and higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_7 = _L("Compared with the default profile of a 0.2 mm nozzle, it has a smaller layer lines, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in minimal layer lines and much higher print quality but much longer print time."); - const std::string PROFILE_DESCRIPTION_8 = _L("It has a normal layer height. This results in average layer lines and print quality. It is suitable for most printing cases."); - const std::string PROFILE_DESCRIPTION_9 = _L("Compared with the default profile of a 0.4 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time."); - const std::string PROFILE_DESCRIPTION_10 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but slightly shorter print time."); - const std::string PROFILE_DESCRIPTION_11 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but shorter print time."); - const std::string PROFILE_DESCRIPTION_12 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in less apparent layer lines and higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_13 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in less apparent layer lines and much higher print quality but much longer print time."); - const std::string PROFILE_DESCRIPTION_14 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_15 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height, lower speeds and acceleration, and the sparse infill pattern is Gyroid. This results in almost negligible layer lines and much higher print quality but much longer print time."); - const std::string PROFILE_DESCRIPTION_16 = _L("Compared with the default profile of a 0.4 mm nozzle, it has a smaller layer height. This results in almost negligible layer lines and longer print time."); - const std::string PROFILE_DESCRIPTION_17 = _L("It has a big layer height. This results in apparent layer lines and ordinary print quality and print time."); - const std::string PROFILE_DESCRIPTION_18 = _L("Compared with the default profile of a 0.6 mm nozzle, it has more wall loops and a higher sparse infill density. This results in higher print strength but more filament consumption and longer print time."); - const std::string PROFILE_DESCRIPTION_19 = _L("Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height. This results in more apparent layer lines and lower print quality, but shorter print time in some cases."); - const std::string PROFILE_DESCRIPTION_20 = _L("Compared with the default profile of a 0.6 mm nozzle, it has a bigger layer height. This results in much more apparent layer lines and much lower print quality, but shorter print time in some cases."); - const std::string PROFILE_DESCRIPTION_21 = _L("Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height. This results in less apparent layer lines and slight higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_22 = _L("Compared with the default profile of a 0.6 mm nozzle, it has a smaller layer height. This results in less apparent layer lines and higher print quality but longer print time."); - const std::string PROFILE_DESCRIPTION_23 = _L("It has a very big layer height. This results in very apparent layer lines, low print quality and shorter print time."); - const std::string PROFILE_DESCRIPTION_24 = _L("Compared with the default profile of a 0.8 mm nozzle, it has a bigger layer height. This results in very apparent layer lines and much lower print quality, but shorter print time in some cases."); - const std::string PROFILE_DESCRIPTION_25 = _L("Compared with the default profile of a 0.8 mm nozzle, it has a much bigger layer height. This results in extremely apparent layer lines and much lower print quality, but much shorter print time in some cases."); - const std::string PROFILE_DESCRIPTION_26 = _L("Compared with the default profile of a 0.8 mm nozzle, it has a slightly smaller layer height. This results in slightly less but still apparent layer lines and slightly higher print quality but longer print time in some cases."); - const std::string PROFILE_DESCRIPTION_27 = _L("Compared with the default profile of a 0.8 mm nozzle, it has a smaller layer height. This results in less but still apparent layer lines and slightly higher print quality but longer print time in some cases."); - const std::string PROFILE_DESCRIPTION_28 = _L("This is neither a commonly used filament, nor one of Bambu filaments, and it varies a lot from brand to brand. So, it's highly recommended to ask its vendor for suitable profile before printing and adjust some parameters according to its performances."); - const std::string PROFILE_DESCRIPTION_29 = _L("When printing this filament, there's a risk of warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials."); - const std::string PROFILE_DESCRIPTION_30 = _L("When printing this filament, there's a risk of nozzle clogging, oozing, warping and low layer adhesion strength. To get better results, please refer to this wiki: Printing Tips for High Temp / Engineering materials."); - const std::string PROFILE_DESCRIPTION_31 = _L("To get better transparent or translucent results with the corresponding filament, please refer to this wiki: Printing tips for transparent PETG."); - const std::string PROFILE_DESCRIPTION_32 = _L("To make the prints get higher gloss, please dry the filament before use, and set the outer wall speed to be 40 to 60 mm/s when slicing."); - const std::string PROFILE_DESCRIPTION_33 = _L("This filament is only used to print models with a low density usually, and some special parameters are required. To get better printing quality, please refer to this wiki: Instructions for printing RC model with foaming PLA (PLA Aero)."); - const std::string PROFILE_DESCRIPTION_34 = _L("This filament is only used to print models with a low density usually, and some special parameters are required. To get better printing quality, please refer to this wiki: ASA Aero Printing Guide."); - const std::string PROFILE_DESCRIPTION_35 = _L("This filament is too soft and not compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide."); - const std::string PROFILE_DESCRIPTION_36 = _L("This filament has high enough hardness (about 67D) and is compatible with the AMS. Printing it is of many requirements, and to get better printing quality, please refer to this wiki: TPU printing guide."); - const std::string PROFILE_DESCRIPTION_37 = _L("If you are to print a kind of soft TPU, please don't slice with this profile, and it is only for TPU that has high enough hardness (not less than 55D) and is compatible with the AMS. To get better printing quality, please refer to this wiki: TPU printing guide."); - const std::string PROFILE_DESCRIPTION_38 = _L("This is a water-soluble support filament, and usually it is only for the support structure and not for the model body. Printing this filament is of many requirements, and to get better printing quality, please refer to this wiki: PVA Printing Guide."); - const std::string PROFILE_DESCRIPTION_39 = _L("This is a non-water-soluble support filament, and usually it is only for the support structure and not for the model body. To get better printing quality, please refer to this wiki: Printing Tips for Support Filament and Support Function."); - const std::string PROFILE_DESCRIPTION_40 = _L("The generic presets are conservatively tuned for compatibility with a wider range of filaments. For higher printing quality and speeds, please use Bambu filaments with Bambu presets."); - const std::string PROFILE_DESCRIPTION_41 = _L("High quality profile for 0.2mm nozzle, prioritizing print quality."); - const std::string PROFILE_DESCRIPTION_42 = _L("High quality profile for 0.16mm layer height, prioritizing print quality and strength."); - const std::string PROFILE_DESCRIPTION_43 = _L("Standard profile for 0.16mm layer height, prioritizing speed."); - const std::string PROFILE_DESCRIPTION_44 = _L("High quality profile for 0.2mm layer height, prioritizing strength and print quality."); - const std::string PROFILE_DESCRIPTION_45 = _L("Standard profile for 0.4mm nozzle, prioritizing speed."); - const std::string PROFILE_DESCRIPTION_46 = _L("High quality profile for 0.6mm nozzle, prioritizing print quality and strength."); - const std::string PROFILE_DESCRIPTION_47 = _L("Strength profile for 0.6mm nozzle, prioritizing strength."); - const std::string PROFILE_DESCRIPTION_48 = _L("Standard profile for 0.6mm nozzle, prioritizing speed."); - const std::string PROFILE_DESCRIPTION_49 = _L("High quality profile for 0.8mm nozzle, prioritizing print quality."); - const std::string PROFILE_DESCRIPTION_50 = _L("Strength profile for 0.8mm nozzle, prioritizing strength."); - const std::string PROFILE_DESCRIPTION_51 = _L("Standard profile for 0.8mm nozzle, prioritizing speed."); -} \ No newline at end of file