Assembly: Port BBS' assembly gizmo
Co-authored-by: zhou.xu <zhou.xu@bambulab.com>
This commit is contained in:
parent
e3b1e30387
commit
3d45414b71
17 changed files with 715 additions and 104 deletions
|
@ -1,7 +1,7 @@
|
|||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="7.80615" y="25.5195" width="29" height="9.19336" stroke="#00AE42"/>
|
||||
<rect x="19.1368" y="5.45404" width="15" height="6.00417" transform="rotate(25.5934 19.1368 5.45404)" stroke="#262E30"/>
|
||||
<rect x="14.8062" y="18.5156" width="15" height="6.00417" stroke="#00AE42" stroke-dasharray="1 1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4877 17.5905C13.5899 17.4883 13.5432 17.3137 13.4035 17.2762L4.93754 15.0078C4.79787 14.9704 4.67006 15.0982 4.70749 15.2378L6.97593 23.7038C7.01336 23.8435 7.18794 23.8902 7.29019 23.788L13.4877 17.5905ZM7.54629 22.2037L11.9034 17.8466L5.95148 16.2518L7.54629 22.2037Z" fill="#262E30"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.22678 16.0611C9.70526 15.1933 10.3436 14.4213 11.1102 13.787C11.8768 13.1526 12.7546 12.6699 13.6966 12.3623C13.7768 12.3361 13.8575 12.3112 13.9386 12.2875C13.9519 12.2837 13.9648 12.2792 13.9775 12.2743C14.1795 12.1952 14.3022 11.9815 14.252 11.767C14.1986 11.539 13.9701 11.3964 13.745 11.4608C13.7304 11.4649 13.7158 11.4692 13.7013 11.4734C13.609 11.5003 13.5172 11.5287 13.426 11.5586C12.3857 11.8993 11.4164 12.4329 10.5696 13.1336C9.72279 13.8344 9.01727 14.6868 8.4879 15.6449C8.44147 15.7289 8.3964 15.8138 8.35271 15.8994C8.34582 15.9129 8.33897 15.9264 8.33215 15.94C8.22679 16.1491 8.3241 16.4002 8.53808 16.4953C8.73944 16.5848 8.97228 16.5042 9.08775 16.3206C9.09499 16.3091 9.10177 16.2972 9.10806 16.2848C9.14646 16.2096 9.18604 16.135 9.22678 16.0611Z" fill="#262E30"/>
|
||||
<rect x="7.80615" y="25.5195" width="29" height="9.19336" stroke="#009688"/>
|
||||
<rect x="19.1368" y="5.45404" width="15" height="6.00417" transform="rotate(25.5934 19.1368 5.45404)" stroke="#2b3436"/>
|
||||
<rect x="14.8062" y="18.5156" width="15" height="6.00417" stroke="#009688" stroke-dasharray="1 1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4877 17.5905C13.5899 17.4883 13.5432 17.3137 13.4035 17.2762L4.93754 15.0078C4.79787 14.9704 4.67006 15.0982 4.70749 15.2378L6.97593 23.7038C7.01336 23.8435 7.18794 23.8902 7.29019 23.788L13.4877 17.5905ZM7.54629 22.2037L11.9034 17.8466L5.95148 16.2518L7.54629 22.2037Z" fill="#2b3436"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.22678 16.0611C9.70526 15.1933 10.3436 14.4213 11.1102 13.787C11.8768 13.1526 12.7546 12.6699 13.6966 12.3623C13.7768 12.3361 13.8575 12.3112 13.9386 12.2875C13.9519 12.2837 13.9648 12.2792 13.9775 12.2743C14.1795 12.1952 14.3022 11.9815 14.252 11.767C14.1986 11.539 13.9701 11.3964 13.745 11.4608C13.7304 11.4649 13.7158 11.4692 13.7013 11.4734C13.609 11.5003 13.5172 11.5287 13.426 11.5586C12.3857 11.8993 11.4164 12.4329 10.5696 13.1336C9.72279 13.8344 9.01727 14.6868 8.4879 15.6449C8.44147 15.7289 8.3964 15.8138 8.35271 15.8994C8.34582 15.9129 8.33897 15.9264 8.33215 15.94C8.22679 16.1491 8.3241 16.4002 8.53808 16.4953C8.73944 16.5848 8.97228 16.5042 9.08775 16.3206C9.09499 16.3091 9.10177 16.2972 9.10806 16.2848C9.14646 16.2096 9.18604 16.135 9.22678 16.0611Z" fill="#2b3436"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -1,7 +1,7 @@
|
|||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="7.80615" y="25.5195" width="29" height="9.19336" stroke="#262E30"/>
|
||||
<rect x="19.1368" y="5.45404" width="15" height="6.00417" transform="rotate(25.5934 19.1368 5.45404)" stroke="#262E30"/>
|
||||
<rect x="14.8062" y="18.5156" width="15" height="6.00417" stroke="#262E30" stroke-dasharray="1 1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4877 17.5905C13.5899 17.4883 13.5432 17.3137 13.4035 17.2762L4.93754 15.0078C4.79787 14.9704 4.67006 15.0982 4.70749 15.2378L6.97593 23.7038C7.01336 23.8435 7.18794 23.8902 7.29019 23.788L13.4877 17.5905ZM7.54629 22.2037L11.9034 17.8466L5.95148 16.2518L7.54629 22.2037Z" fill="#262E30"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.22678 16.0611C9.70526 15.1933 10.3436 14.4213 11.1102 13.787C11.8768 13.1526 12.7546 12.6699 13.6966 12.3623C13.7768 12.3361 13.8575 12.3112 13.9386 12.2875C13.9519 12.2837 13.9648 12.2792 13.9775 12.2743C14.1795 12.1952 14.3022 11.9815 14.252 11.767C14.1986 11.539 13.9701 11.3964 13.745 11.4608C13.7304 11.4649 13.7158 11.4692 13.7013 11.4734C13.609 11.5003 13.5172 11.5287 13.426 11.5586C12.3857 11.8993 11.4164 12.4329 10.5696 13.1336C9.72279 13.8344 9.01727 14.6868 8.4879 15.6449C8.44147 15.7289 8.3964 15.8138 8.35271 15.8994C8.34582 15.9129 8.33897 15.9264 8.33215 15.94C8.22679 16.1491 8.3241 16.4002 8.53808 16.4953C8.73944 16.5848 8.97228 16.5042 9.08775 16.3206C9.09499 16.3091 9.10177 16.2972 9.10806 16.2848C9.14646 16.2096 9.18604 16.135 9.22678 16.0611Z" fill="#262E30"/>
|
||||
<rect x="7.80615" y="25.5195" width="29" height="9.19336" stroke="#009688"/>
|
||||
<rect x="19.1368" y="5.45404" width="15" height="6.00417" transform="rotate(25.5934 19.1368 5.45404)" stroke="#b6b6b6"/>
|
||||
<rect x="14.8062" y="18.5156" width="15" height="6.00417" stroke="#009688" stroke-dasharray="1 1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4877 17.5905C13.5899 17.4883 13.5432 17.3137 13.4035 17.2762L4.93754 15.0078C4.79787 14.9704 4.67006 15.0982 4.70749 15.2378L6.97593 23.7038C7.01336 23.8435 7.18794 23.8902 7.29019 23.788L13.4877 17.5905ZM7.54629 22.2037L11.9034 17.8466L5.95148 16.2518L7.54629 22.2037Z" fill="#009688"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.22678 16.0611C9.70526 15.1933 10.3436 14.4213 11.1102 13.787C11.8768 13.1526 12.7546 12.6699 13.6966 12.3623C13.7768 12.3361 13.8575 12.3112 13.9386 12.2875C13.9519 12.2837 13.9648 12.2792 13.9775 12.2743C14.1795 12.1952 14.3022 11.9815 14.252 11.767C14.1986 11.539 13.9701 11.3964 13.745 11.4608C13.7304 11.4649 13.7158 11.4692 13.7013 11.4734C13.609 11.5003 13.5172 11.5287 13.426 11.5586C12.3857 11.8993 11.4164 12.4329 10.5696 13.1336C9.72279 13.8344 9.01727 14.6868 8.4879 15.6449C8.44147 15.7289 8.3964 15.8138 8.35271 15.8994C8.34582 15.9129 8.33897 15.9264 8.33215 15.94C8.22679 16.1491 8.3241 16.4002 8.53808 16.4953C8.73944 16.5848 8.97228 16.5042 9.08775 16.3206C9.09499 16.3091 9.10177 16.2972 9.10806 16.2848C9.14646 16.2096 9.18604 16.135 9.22678 16.0611Z" fill="#b6b6b6"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -717,53 +717,6 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
|
|||
return out;
|
||||
}
|
||||
|
||||
TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
{
|
||||
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||
mirror = m0.determinant() < 0.0;
|
||||
|
||||
Matrix3d m;
|
||||
if (mirror)
|
||||
m = m0 * Eigen::DiagonalMatrix<double, 3, 3>(-1.0, 1.0, 1.0);
|
||||
else
|
||||
m = m0;
|
||||
const Eigen::JacobiSVD<Matrix3d> svd(m, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||
u = svd.matrixU();
|
||||
v = svd.matrixV();
|
||||
s = svd.singularValues().asDiagonal();
|
||||
|
||||
scale = !s.isApprox(Matrix3d::Identity());
|
||||
anisotropic_scale = ! is_approx(s(0, 0), s(1, 1)) || ! is_approx(s(1, 1), s(2, 2));
|
||||
rotation = !v.isApprox(u);
|
||||
|
||||
if (anisotropic_scale) {
|
||||
rotation_90_degrees = true;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const Vec3d row = v.row(i).cwiseAbs();
|
||||
const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||
const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||
if (num_zeros != 2 || num_ones != 1) {
|
||||
rotation_90_degrees = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Detect skew by brute force: check if the axes are still orthogonal after transformation
|
||||
const Matrix3d trafo_linear = trafo.linear();
|
||||
const std::array<Vec3d, 3> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
|
||||
std::array<Vec3d, 3> transformed_axes;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
transformed_axes[i] = trafo_linear * axes[i];
|
||||
}
|
||||
skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON ||
|
||||
std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON ||
|
||||
std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON;
|
||||
|
||||
// This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492)
|
||||
// skew = ! rotation_90_degrees;
|
||||
} else
|
||||
skew = false;
|
||||
}
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
Transform3d transform3d_from_string(const std::string& transform_str)
|
||||
{
|
||||
|
@ -812,4 +765,78 @@ double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
|
|||
return (axis.z() < 0) ? -angle : angle;
|
||||
}
|
||||
|
||||
TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
{
|
||||
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||
mirror = m0.determinant() < 0.0;
|
||||
|
||||
Matrix3d m;
|
||||
if (mirror)
|
||||
m = m0 * Eigen::DiagonalMatrix<double, 3, 3>(-1.0, 1.0, 1.0);
|
||||
else
|
||||
m = m0;
|
||||
const Eigen::JacobiSVD<Matrix3d> svd(m, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||
u = svd.matrixU();
|
||||
v = svd.matrixV();
|
||||
s = svd.singularValues().asDiagonal();
|
||||
|
||||
scale = !s.isApprox(Matrix3d::Identity());
|
||||
anisotropic_scale = ! is_approx(s(0, 0), s(1, 1)) || ! is_approx(s(1, 1), s(2, 2));
|
||||
rotation = !v.isApprox(u);
|
||||
|
||||
if (anisotropic_scale) {
|
||||
rotation_90_degrees = true;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const Vec3d row = v.row(i).cwiseAbs();
|
||||
const size_t num_zeros = is_approx(row[0], 0.) + is_approx(row[1], 0.) + is_approx(row[2], 0.);
|
||||
const size_t num_ones = is_approx(row[0], 1.) + is_approx(row[1], 1.) + is_approx(row[2], 1.);
|
||||
if (num_zeros != 2 || num_ones != 1) {
|
||||
rotation_90_degrees = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Detect skew by brute force: check if the axes are still orthogonal after transformation
|
||||
const Matrix3d trafo_linear = trafo.linear();
|
||||
const std::array<Vec3d, 3> axes = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
|
||||
std::array<Vec3d, 3> transformed_axes;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
transformed_axes[i] = trafo_linear * axes[i];
|
||||
}
|
||||
skew = std::abs(transformed_axes[0].dot(transformed_axes[1])) > EPSILON ||
|
||||
std::abs(transformed_axes[1].dot(transformed_axes[2])) > EPSILON ||
|
||||
std::abs(transformed_axes[2].dot(transformed_axes[0])) > EPSILON;
|
||||
|
||||
// This following old code does not work under all conditions. The v matrix can become non diagonal (see SPE-1492)
|
||||
// skew = ! rotation_90_degrees;
|
||||
} else
|
||||
skew = false;
|
||||
}
|
||||
|
||||
Transformation mat_around_a_point_rotate(const Transformation &InMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian)
|
||||
{
|
||||
auto xyz = InMat.get_offset();
|
||||
Transformation left;
|
||||
left.set_offset(-xyz); // at world origin
|
||||
auto curMat = left * InMat;
|
||||
|
||||
auto qua = Eigen::Quaterniond(Eigen::AngleAxisd(rotate_theta_radian, axis));
|
||||
qua.normalize();
|
||||
Transform3d cur_matrix;
|
||||
Transformation rotateMat4;
|
||||
rotateMat4.set_matrix(cur_matrix.fromPositionOrientationScale(Vec3d(0., 0., 0.), qua, Vec3d(1., 1., 1.)));
|
||||
|
||||
curMat = rotateMat4 * curMat; // along_fix_axis
|
||||
// rotate mat4 along fix pt
|
||||
Transformation temp_world;
|
||||
auto qua_world = Eigen::Quaterniond(Eigen::AngleAxisd(0, axis));
|
||||
qua_world.normalize();
|
||||
Transform3d cur_matrix_world;
|
||||
temp_world.set_matrix(cur_matrix_world.fromPositionOrientationScale(pt, qua_world, Vec3d(1., 1., 1.)));
|
||||
auto temp_xyz = temp_world.get_matrix().inverse() * xyz;
|
||||
auto new_pos = temp_world.get_matrix() * (rotateMat4.get_matrix() * temp_xyz);
|
||||
curMat.set_offset(new_pos);
|
||||
|
||||
return curMat;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::Geometry
|
||||
|
|
|
@ -544,6 +544,7 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation)
|
|||
return is_rotation_ninety_degrees(rotation.x()) && is_rotation_ninety_degrees(rotation.y()) && is_rotation_ninety_degrees(rotation.z());
|
||||
}
|
||||
|
||||
Transformation mat_around_a_point_rotate(const Transformation& innMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian);
|
||||
} } // namespace Slicer::Geometry
|
||||
|
||||
#endif
|
||||
|
|
|
@ -145,6 +145,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
#GUI/Gizmos/GLGizmoFaceDetector.hpp
|
||||
GUI/Gizmos/GLGizmoMeasure.cpp
|
||||
GUI/Gizmos/GLGizmoMeasure.hpp
|
||||
GUI/Gizmos/GLGizmoAssembly.cpp
|
||||
GUI/Gizmos/GLGizmoAssembly.hpp
|
||||
GUI/Gizmos/GLGizmoSeam.cpp
|
||||
GUI/Gizmos/GLGizmoSeam.hpp
|
||||
#GUI/Gizmos/GLGizmoText.cpp
|
||||
|
|
167
src/slic3r/GUI/Gizmos/GLGizmoAssembly.cpp
Normal file
167
src/slic3r/GUI/Gizmos/GLGizmoAssembly.cpp
Normal file
|
@ -0,0 +1,167 @@
|
|||
#include "GLGizmoAssembly.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GizmoObjectManipulation.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/MeasureUtils.hpp"
|
||||
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <future>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
GLGizmoAssembly::GLGizmoAssembly(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) :
|
||||
GLGizmoMeasure(parent, icon_filename, sprite_id)
|
||||
{
|
||||
m_measure_mode = EMeasureMode::ONLY_ASSEMBLY;
|
||||
}
|
||||
|
||||
std::string GLGizmoAssembly::on_get_name() const
|
||||
{
|
||||
if (!on_is_activable() && m_state == EState::Off) {
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
return _u8L("Assemble") + ":\n" + _u8L("Please confirm explosion ratio = 1 and select at least two volumes.");
|
||||
}
|
||||
else {
|
||||
return _u8L("Assemble") + ":\n" + _u8L("Please select at least two volumes.");
|
||||
}
|
||||
} else {
|
||||
return _u8L("Assemble");
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoAssembly::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
if (selection.is_wipe_tower()) {
|
||||
return false;
|
||||
}
|
||||
const int selection_volumes_count = 2;
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView) {
|
||||
if (abs(m_parent.get_explosion_ratio() - 1.0f) < 1e-2 && selection.volumes_count() >= selection_volumes_count) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return selection.volumes_count() >= selection_volumes_count;
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoAssembly::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
static std::optional<Measure::SurfaceFeature> last_feature;
|
||||
static EMode last_mode = EMode::FeatureSelection;
|
||||
static SelectedFeatures last_selected_features;
|
||||
|
||||
static float last_y = 0.0f;
|
||||
static float last_h = 0.0f;
|
||||
|
||||
if (m_editing_distance)
|
||||
return;
|
||||
m_current_active_imgui_id = ImGui::GetActiveID();
|
||||
// adjust window position to avoid overlap the view toolbar
|
||||
const float win_h = ImGui::GetWindowHeight();
|
||||
y = std::min(y, bottom_limit - win_h);
|
||||
GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f);
|
||||
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;
|
||||
}
|
||||
// Orca
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
init_render_input_window();
|
||||
|
||||
float moving_size = m_imgui->calc_text_size(_L("(Moving)")).x;
|
||||
float combox_content_size = m_imgui->calc_text_size(_L("Point and point assembly")).x*1.1 + ImGui::GetStyle().FramePadding.x * 18.0f;
|
||||
float caption_size = moving_size + 2 * m_space_size;
|
||||
if (render_assembly_mode_combo(caption_size + 0.5 * m_space_size, combox_content_size)) {
|
||||
;
|
||||
}
|
||||
show_selection_ui();
|
||||
show_face_face_assembly_common();
|
||||
ImGui::Separator();
|
||||
show_face_face_assembly_senior();
|
||||
show_distance_xyz_ui();
|
||||
render_input_window_warning(m_same_model_object);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
|
||||
float caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
for (const auto &t : std::array<std::string, 3>{"point_selection", "reset", "unselect"}) {
|
||||
caption_max = std::max(caption_max, m_imgui->calc_text_size(m_desc[t + "_caption"]).x);
|
||||
total_text_max = std::max(total_text_max, m_imgui->calc_text_size(m_desc[t]).x);
|
||||
}
|
||||
show_tooltip_information(caption_max, 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::PopStyleVar(2);
|
||||
|
||||
if (last_feature != m_curr_feature || last_mode != m_mode || last_selected_features != m_selected_features) {
|
||||
// the dialog may have changed its size, ask for an extra frame to render it properly
|
||||
last_feature = m_curr_feature;
|
||||
last_mode = m_mode;
|
||||
last_selected_features = m_selected_features;
|
||||
m_imgui->set_requires_extra_frame();
|
||||
}
|
||||
m_last_active_item_imgui = m_current_active_imgui_id;
|
||||
GizmoImguiEnd();
|
||||
// Orca
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
void GLGizmoAssembly::render_input_window_warning(bool same_model_object)
|
||||
{
|
||||
if (wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasView3D) {
|
||||
if (m_hit_different_volumes.size() == 2) {
|
||||
if (same_model_object == false) {
|
||||
m_imgui->warning_text(_L("Warning") + ": " +
|
||||
_L("It is recommended to assemble the objects first,\nbecause the objects is restriced to bed \nand only parts can be lifted."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoAssembly::render_assembly_mode_combo(double label_width, float item_width)
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
int selection_idx = int(m_assembly_mode);
|
||||
std::vector<std::string> modes = {_u8L("Face and face assembly"), _u8L("Point and point assembly")};
|
||||
bool is_changed = false;
|
||||
|
||||
ImGuiWrapper::push_combo_style(m_parent.get_scale());
|
||||
if (render_combo(_u8L("Mode"), modes, selection_idx, label_width, item_width)) {
|
||||
is_changed = true;
|
||||
switch_to_mode((AssemblyMode) selection_idx);
|
||||
}
|
||||
ImGuiWrapper::pop_combo_style();
|
||||
return is_changed;
|
||||
}
|
||||
|
||||
void GLGizmoAssembly::switch_to_mode(AssemblyMode new_mode)
|
||||
{
|
||||
m_assembly_mode = new_mode;
|
||||
reset_all_feature();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
43
src/slic3r/GUI/Gizmos/GLGizmoAssembly.hpp
Normal file
43
src/slic3r/GUI/Gizmos/GLGizmoAssembly.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef slic3r_GLGizmoAssembly_hpp_
|
||||
#define slic3r_GLGizmoAssembly_hpp_
|
||||
|
||||
#include "GLGizmoMeasure.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
class GLGizmoAssembly : public GLGizmoMeasure
|
||||
{
|
||||
|
||||
public:
|
||||
GLGizmoAssembly(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
/// <summary>
|
||||
/// Apply rotation on select plane
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
//bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
//void data_changed(bool is_serializing) override;
|
||||
//bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down) override;
|
||||
|
||||
bool wants_enter_leave_snapshots() const override { return true; }
|
||||
std::string get_gizmo_entering_text() const override { return _u8L("Entering Assembly gizmo"); }
|
||||
std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Assembly gizmo"); }
|
||||
protected:
|
||||
//bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
bool on_is_activable() const override;
|
||||
//void on_render() override;
|
||||
//void on_set_state() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
void render_input_window_warning(bool same_model_object) override;
|
||||
bool render_assembly_mode_combo(double label_width, float item_width);
|
||||
|
||||
void switch_to_mode(AssemblyMode new_mode);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLGizmoAssembly_hpp_
|
|
@ -194,6 +194,39 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color)
|
|||
}
|
||||
}
|
||||
|
||||
bool GLGizmoBase::render_combo(const std::string &label, const std::vector<std::string> &lines, int &selection_idx, float label_width, float item_width)
|
||||
{
|
||||
ImGuiWrapper::push_combo_style(m_parent.get_scale());
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(label);
|
||||
ImGui::SameLine(label_width);
|
||||
ImGui::PushItemWidth(item_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();
|
||||
ImGuiWrapper::pop_combo_style();
|
||||
|
||||
return is_changed;
|
||||
}
|
||||
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: m_parent(parent)
|
||||
, m_group_id(-1)
|
||||
|
|
|
@ -149,6 +149,9 @@ protected:
|
|||
|
||||
bool m_is_dark_mode = false;
|
||||
|
||||
bool render_combo(const std::string &label, const std::vector<std::string> &lines,
|
||||
int &selection_idx, float label_width, float item_width);
|
||||
|
||||
public:
|
||||
GLGizmoBase(GLCanvas3D& parent,
|
||||
const std::string& icon_filename,
|
||||
|
|
|
@ -520,40 +520,6 @@ bool GLGizmoCut3D::render_cut_mode_combo()
|
|||
return is_changed;
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::render_combo(const std::string& label, const std::vector<std::string>& lines, int& selection_idx)
|
||||
{
|
||||
ImGuiWrapper::push_combo_style(m_parent.get_scale());
|
||||
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();
|
||||
ImGuiWrapper::pop_combo_style();
|
||||
|
||||
return is_changed;
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::render_double_input(const std::string& label, double& value_in)
|
||||
{
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
@ -2299,7 +2265,7 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
|||
m_connector_style = int(CutConnectorStyle::Prism);
|
||||
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
|
||||
}
|
||||
if (render_combo(m_labels_map["Style"], m_connector_styles, m_connector_style))
|
||||
if (render_combo(m_labels_map["Style"], m_connector_styles, m_connector_style, m_label_width, m_editing_window_width))
|
||||
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
|
||||
m_imgui->disabled_end();
|
||||
|
||||
|
@ -2308,7 +2274,7 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors, flo
|
|||
m_connector_shape_id = int(CutConnectorShape::Circle);
|
||||
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
|
||||
}
|
||||
if (render_combo(m_labels_map["Shape"], m_connector_shapes, m_connector_shape_id))
|
||||
if (render_combo(m_labels_map["Shape"], m_connector_shapes, m_connector_shape_id, m_label_width, m_editing_window_width))
|
||||
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
|
||||
m_imgui->disabled_end();
|
||||
|
||||
|
|
|
@ -335,7 +335,6 @@ private:
|
|||
void set_center(const Vec3d¢er, bool update_tbb = false);
|
||||
void switch_to_mode(size_t new_mode);
|
||||
bool render_cut_mode_combo();
|
||||
bool render_combo(const std::string&label, const std::vector<std::string>&lines, int&selection_idx);
|
||||
bool render_double_input(const std::string& label, double& value_in);
|
||||
bool render_slider_double_input(const std::string& label, float& value_in, float& tolerance_in, float min_val = -0.1f, float max_tolerance = -0.1f);
|
||||
void render_move_center_input(int axis);
|
||||
|
|
|
@ -265,6 +265,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
|
|||
if (m_selected_features.first.feature.has_value()) {
|
||||
reset_feature2_render();
|
||||
const SelectedFeatures::Item item = detect_current_item();
|
||||
if (!is_pick_meet_assembly_mode(item)) { // assembly deal
|
||||
m_selected_wrong_feature_waring_tip = true;
|
||||
return true;
|
||||
}
|
||||
m_selected_wrong_feature_waring_tip = false;
|
||||
if (m_selected_features.first != item) {
|
||||
bool processed = false;
|
||||
|
@ -329,6 +333,10 @@ bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
|
|||
// 1st feature selection
|
||||
reset_feature1_render();
|
||||
const SelectedFeatures::Item item = detect_current_item();
|
||||
if (!is_pick_meet_assembly_mode(item)) {//assembly deal
|
||||
m_selected_wrong_feature_waring_tip = true;
|
||||
return true;
|
||||
}
|
||||
m_selected_wrong_feature_waring_tip = false;
|
||||
m_selected_features.first = item;
|
||||
if (requires_sphere_raycaster_for_picking(item)) {
|
||||
|
@ -2035,6 +2043,79 @@ void GLGizmoMeasure::show_distance_xyz_ui()
|
|||
//{
|
||||
//}
|
||||
|
||||
void GLGizmoMeasure::show_face_face_assembly_common() {
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY && m_hit_different_volumes.size() == 2 &&
|
||||
m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane &&
|
||||
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) {
|
||||
auto &action = m_assembly_action;
|
||||
auto set_to_parallel_size = m_imgui->calc_button_size(_L("Parallel")).x;
|
||||
auto set_to_center_coincidence_size = m_imgui->calc_button_size(_L("Center coincidence")).x;
|
||||
|
||||
m_imgui->disabled_begin(!(action.can_set_to_center_coincidence));
|
||||
{
|
||||
ImGui::PushItemWidth(set_to_center_coincidence_size);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(0 / 255.0, 174 / 255.0, 66 / 255.0, 1.0) : ImVec4(0 / 255.0, 174 / 255.0, 66 / 255.0, 1.0));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
m_is_dark_mode ? ImVec4(50 / 255.0f, 238 / 255.0f, 61 / 255.0f, 1.00f) : ImVec4(50 / 255.0f, 238 / 255.0f, 61 / 255.0f, 1.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
m_is_dark_mode ? ImVec4(206 / 255.0f, 206 / 255.0f, 206 / 255.0f, 1.00f) : ImVec4(206 / 255.0f, 206 / 255.0f, 206 / 255.0f, 1.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,
|
||||
m_is_dark_mode ? ImVec4(255 / 255.0f, 255 / 255.0f, 255 / 255.0f, 1.00f) : ImVec4(255 / 255.0f, 255 / 255.0f, 255 / 255.0f, 1.00f));
|
||||
if (m_imgui->button(_L("Center coincidence"))) {
|
||||
set_to_center_coincidence(m_same_model_object);
|
||||
}
|
||||
ImGui::PopStyleColor(4);
|
||||
ImGui::SameLine(set_to_center_coincidence_size + m_space_size * 2);
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
m_imgui->disabled_begin(!action.can_set_to_parallel);
|
||||
{
|
||||
if (m_imgui->button(_L("Parallel"))) { set_to_parallel(m_same_model_object); }
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::show_face_face_assembly_senior()
|
||||
{
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY && m_hit_different_volumes.size() == 2 &&
|
||||
m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Plane &&
|
||||
m_selected_features.second.feature->get_type() == Measure::SurfaceFeatureType::Plane) {
|
||||
auto &action = m_assembly_action;
|
||||
auto feature_text_size = m_imgui->calc_button_size(_L("Featue 1")).x + m_imgui->calc_button_size(":").x;
|
||||
auto set_to_reverse_rotation_size = m_imgui->calc_button_size(_L("Reverse rotation")).x;
|
||||
auto rotate_around_center_size = m_imgui->calc_button_size(_L("Rotate around center:")).x;
|
||||
auto parallel_distance_size = m_imgui->calc_button_size(_L("Parallel_distance:")).x;
|
||||
|
||||
if (m_imgui->bbl_checkbox(_L("Flip by Face 2"), m_flip_volume_2)) {
|
||||
set_to_reverse_rotation(m_same_model_object, 1);
|
||||
}
|
||||
|
||||
if (action.has_parallel_distance) {
|
||||
m_imgui->text(_u8L("Parallel_distance:"));
|
||||
ImGui::SameLine(parallel_distance_size + m_space_size);
|
||||
ImGui::PushItemWidth(m_input_size_max);
|
||||
ImGui::BBLInputDouble("##parallel_distance_z", &m_buffered_parallel_distance, 0.0f, 0.0f, "%.2f");
|
||||
if (m_last_active_item_imgui != m_current_active_imgui_id && std::abs(m_buffered_parallel_distance - action.parallel_distance) > EPSILON) {
|
||||
set_parallel_distance(m_same_model_object, m_buffered_parallel_distance);
|
||||
}
|
||||
}
|
||||
if (action.can_around_center_of_faces) {
|
||||
m_imgui->text(_u8L("Rotate around center:"));
|
||||
ImGui::SameLine(rotate_around_center_size + m_space_size);
|
||||
ImGui::PushItemWidth(m_input_size_max);
|
||||
ImGui::BBLInputDouble("##rotate_around_center", &m_buffered_around_center, 0.0f, 0.0f, "%.2f");
|
||||
if (m_last_active_item_imgui != m_current_active_imgui_id && std::abs(m_buffered_around_center) > EPSILON) {
|
||||
set_to_around_center_of_faces(m_same_model_object, m_buffered_around_center);
|
||||
m_buffered_around_center = 0;
|
||||
}
|
||||
ImGui::SameLine(rotate_around_center_size + m_space_size + m_input_size_max + m_space_size / 2.0f);
|
||||
m_imgui->text(_L("°"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::init_render_input_window()
|
||||
{
|
||||
m_use_inches = wxGetApp().app_config->get_bool("use_inches");
|
||||
|
@ -2101,6 +2182,10 @@ void GLGizmoMeasure::on_render_input_window(float x, float y, float bottom_limit
|
|||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::render_input_window_warning(bool same_model_object)
|
||||
{
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::remove_selected_sphere_raycaster(int id)
|
||||
{
|
||||
reset_gripper_pick(id == SEL_SPHERE_1_ID ? GripperType::SPHERE_1 : GripperType::SPHERE_2);
|
||||
|
@ -2110,9 +2195,11 @@ void GLGizmoMeasure::update_measurement_result()
|
|||
{
|
||||
if (!m_selected_features.first.feature.has_value()) {
|
||||
m_measurement_result = Measure::MeasurementResult();
|
||||
m_assembly_action = Measure::AssemblyAction();
|
||||
}
|
||||
else if (m_selected_features.second.feature.has_value()) {
|
||||
m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, *m_selected_features.second.feature, true);
|
||||
m_assembly_action = Measure::get_assembly_action(*m_selected_features.first.feature, *m_selected_features.second.feature);
|
||||
m_can_set_xyz_distance = Measure::can_set_xyz_distance(*m_selected_features.first.feature, *m_selected_features.second.feature);
|
||||
//update buffer
|
||||
const Measure::MeasurementResult &measure = m_measurement_result;
|
||||
|
@ -2126,6 +2213,9 @@ void GLGizmoMeasure::update_measurement_result()
|
|||
}
|
||||
if (wxGetApp().app_config->get_bool("use_inches")) m_distance = GizmoObjectManipulation::mm_to_in * m_distance;
|
||||
m_buffered_distance = m_distance;
|
||||
if (m_assembly_action.has_parallel_distance) {
|
||||
m_buffered_parallel_distance = m_assembly_action.parallel_distance;
|
||||
}
|
||||
}
|
||||
else if (!m_selected_features.second.feature.has_value() && m_selected_features.first.feature->get_type() == Measure::SurfaceFeatureType::Circle)
|
||||
m_measurement_result = Measure::get_measurement(*m_selected_features.first.feature, Measure::SurfaceFeature(std::get<0>(m_selected_features.first.feature->get_circle())));
|
||||
|
@ -2399,5 +2489,201 @@ void GLGizmoMeasure::set_distance(bool same_model_object, const Vec3d &displacem
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::set_to_parallel(bool same_model_object, bool take_shot, bool is_anti_parallel)
|
||||
{
|
||||
if (m_hit_different_volumes.size() == 2) {
|
||||
auto &action = m_assembly_action;
|
||||
auto v = m_hit_different_volumes[1];
|
||||
auto selection = const_cast<Selection *>(&m_parent.get_selection());
|
||||
selection->setup_cache();
|
||||
if (take_shot) {
|
||||
wxGetApp().plater()->take_snapshot("RotateInMeasure", UndoRedo::SnapshotType::GizmoAction); // avoid storing another snapshot
|
||||
}
|
||||
selection->set_mode(same_model_object ? Selection::Volume : Selection::Instance);
|
||||
const auto [idx1, normal1, pt1] = m_selected_features.first.feature->get_plane();
|
||||
const auto [idx2, normal2, pt2] = m_selected_features.second.feature->get_plane();
|
||||
if ((is_anti_parallel && normal1.dot(normal2) > -1 + 1e-3) ||
|
||||
(is_anti_parallel == false && (normal1.dot(normal2) < 1 - 1e-3))) {
|
||||
m_pending_scale ++;
|
||||
Vec3d axis;
|
||||
double angle;
|
||||
Matrix3d rotation_matrix;
|
||||
Geometry::rotation_from_two_vectors(normal2, -normal1, axis, angle, &rotation_matrix);
|
||||
Transform3d r_m = (Transform3d) rotation_matrix;
|
||||
if (same_model_object == false) {
|
||||
auto new_rotation_tran = r_m * v->get_instance_transformation().get_rotation_matrix();
|
||||
Vec3d rotation = Geometry::extract_euler_angles(new_rotation_tran);
|
||||
v->set_instance_rotation(rotation);
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), v->get_instance_transformation().get_matrix());
|
||||
} else {
|
||||
Geometry::Transformation world_tran(v->world_matrix());
|
||||
auto new_tran = r_m * world_tran.get_rotation_matrix();
|
||||
Transform3d volume_rotation_tran = v->get_instance_transformation().get_rotation_matrix().inverse() * new_tran;
|
||||
Vec3d rotation = Geometry::extract_euler_angles(volume_rotation_tran);
|
||||
v->set_volume_rotation(rotation);
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), v->volume_idx(), v->get_volume_transformation().get_matrix());
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->do_rotate("");
|
||||
register_single_mesh_pick();
|
||||
if (same_model_object) {
|
||||
update_feature_by_tran(*m_selected_features.first.feature);
|
||||
}
|
||||
update_feature_by_tran(*m_selected_features.second.feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::set_to_reverse_rotation(bool same_model_object, int feature_index)
|
||||
{
|
||||
if (m_hit_different_volumes.size() == 2 && feature_index < 2) {
|
||||
auto &action = m_assembly_action;
|
||||
auto v = m_hit_different_volumes[feature_index];
|
||||
auto selection = const_cast<Selection *>(&m_parent.get_selection());
|
||||
selection->setup_cache();
|
||||
wxGetApp().plater()->take_snapshot("ReverseRotateInMeasure", UndoRedo::SnapshotType::GizmoAction); // avoid storing another snapshot
|
||||
|
||||
selection->set_mode(same_model_object ? Selection::Volume : Selection::Instance);
|
||||
m_pending_scale = 1;
|
||||
Vec3d plane_normal,plane_center;
|
||||
if (feature_index ==0) {//feature 1
|
||||
const auto [idx1, normal1, pt1] = m_selected_features.first.feature->get_plane();
|
||||
plane_normal = normal1;
|
||||
plane_center = pt1;
|
||||
}
|
||||
else { // feature 2
|
||||
const auto [idx2, normal2, pt2] = m_selected_features.second.feature->get_plane();
|
||||
plane_normal = normal2;
|
||||
plane_center = pt2;
|
||||
}
|
||||
auto new_pt = Measure::get_one_point_in_plane(plane_center, plane_normal);
|
||||
Vec3d axis = (new_pt - plane_center).normalized();
|
||||
if (axis.norm() < 0.1) {
|
||||
throw;
|
||||
}
|
||||
if (same_model_object == false) {
|
||||
Geometry::Transformation inMat(v->get_instance_transformation());
|
||||
Geometry::Transformation outMat = Geometry::mat_around_a_point_rotate(inMat, plane_center, axis, PI);
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), outMat.get_matrix());
|
||||
} else {
|
||||
Geometry::Transformation inMat(v->world_matrix());
|
||||
Geometry::Transformation outMat = Geometry::mat_around_a_point_rotate(inMat, plane_center, axis, PI);
|
||||
Transform3d volume_tran = v->get_instance_transformation().get_matrix().inverse() * outMat.get_matrix();
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), v->volume_idx(), volume_tran);
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->do_rotate("");
|
||||
register_single_mesh_pick();
|
||||
if (same_model_object == false) {
|
||||
if (feature_index == 0) { // feature 1
|
||||
update_feature_by_tran(*m_selected_features.first.feature);
|
||||
} else { // feature 2
|
||||
update_feature_by_tran(*m_selected_features.second.feature);
|
||||
}
|
||||
}
|
||||
else {
|
||||
update_feature_by_tran(*m_selected_features.first.feature);
|
||||
update_feature_by_tran(*m_selected_features.second.feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::set_to_around_center_of_faces(bool same_model_object, float rotate_degree)
|
||||
{
|
||||
if (m_hit_different_volumes.size() == 2 ) {
|
||||
auto &action = m_assembly_action;
|
||||
auto v = m_hit_different_volumes[1];
|
||||
auto selection = const_cast<Selection *>(&m_parent.get_selection());
|
||||
selection->setup_cache();
|
||||
wxGetApp().plater()->take_snapshot("ReverseRotateInMeasure", UndoRedo::SnapshotType::GizmoAction); // avoid storing another snapshot
|
||||
|
||||
selection->set_mode(same_model_object ? Selection::Volume : Selection::Instance);
|
||||
m_pending_scale = 1;
|
||||
|
||||
auto radian = Geometry::deg2rad(rotate_degree);
|
||||
Vec3d plane_normal, plane_center;
|
||||
const auto [idx2, normal2, pt2] = m_selected_features.second.feature->get_plane();
|
||||
plane_normal = normal2;
|
||||
plane_center = pt2;
|
||||
|
||||
if (same_model_object == false) {
|
||||
Geometry::Transformation inMat(v->get_instance_transformation());
|
||||
Geometry::Transformation outMat = Geometry::mat_around_a_point_rotate(inMat, plane_center, plane_normal, radian);
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), outMat.get_matrix());
|
||||
} else {
|
||||
Geometry::Transformation inMat(v->world_matrix());
|
||||
Geometry::Transformation outMat = Geometry::mat_around_a_point_rotate(inMat, plane_center, plane_normal, radian);
|
||||
Transform3d volume_tran = v->get_instance_transformation().get_matrix().inverse() * outMat.get_matrix();
|
||||
selection->rotate(v->object_idx(), v->instance_idx(), v->volume_idx(), volume_tran);
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->do_rotate("");
|
||||
register_single_mesh_pick();
|
||||
if (same_model_object) {
|
||||
update_feature_by_tran(*m_selected_features.first.feature);
|
||||
}
|
||||
update_feature_by_tran(*m_selected_features.second.feature);
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::set_to_center_coincidence(bool same_model_object) {
|
||||
auto v = m_hit_different_volumes[1];
|
||||
wxGetApp().plater()->take_snapshot("RotateThenMoveInMeasure", UndoRedo::SnapshotType::GizmoAction);
|
||||
set_to_parallel(same_model_object, false,true);
|
||||
|
||||
const auto [idx1, normal1, pt1] = m_selected_features.first.feature->get_plane();
|
||||
const auto [idx2, normal2, pt2] = m_selected_features.second.feature->get_plane();
|
||||
set_distance(same_model_object, pt1 - pt2, false);
|
||||
m_set_center_coincidence = true;
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::set_parallel_distance(bool same_model_object, float dist)
|
||||
{
|
||||
if (m_hit_different_volumes.size() == 2 && abs(dist) >= 0.0f) {
|
||||
auto v = m_hit_different_volumes[1];
|
||||
auto selection = const_cast<Selection *>(&m_parent.get_selection());
|
||||
selection->setup_cache();
|
||||
|
||||
wxGetApp().plater()->take_snapshot("SetParallelDistanceInMeasure", UndoRedo::SnapshotType::GizmoAction); // avoid storing another snapshot
|
||||
|
||||
selection->set_mode(same_model_object ? Selection::Volume : Selection::Instance);
|
||||
m_pending_scale = 1;
|
||||
|
||||
const auto [idx1, normal1, pt1] = m_selected_features.first.feature->get_plane();
|
||||
const auto [idx2, normal2, pt2] = m_selected_features.second.feature->get_plane();
|
||||
Vec3d proj_pt2;
|
||||
Measure::get_point_projection_to_plane(pt2, pt1, normal1, proj_pt2);
|
||||
auto new_pt2 = proj_pt2 + normal1 * dist;
|
||||
|
||||
Vec3d displacement = new_pt2 - pt2;
|
||||
|
||||
if (same_model_object == false) {
|
||||
selection->translate(v->object_idx(), v->instance_idx(), displacement);
|
||||
} else {
|
||||
selection->translate(v->object_idx(), v->instance_idx(), v->volume_idx(), displacement);
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->do_move("");
|
||||
register_single_mesh_pick();
|
||||
if (same_model_object) {
|
||||
update_feature_by_tran(*m_selected_features.first.feature);
|
||||
}
|
||||
update_feature_by_tran(*m_selected_features.second.feature);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoMeasure::is_pick_meet_assembly_mode(const SelectedFeatures::Item &item) {
|
||||
if (m_measure_mode == EMeasureMode::ONLY_ASSEMBLY) {
|
||||
if (m_assembly_mode == AssemblyMode::FACE_FACE && item.feature->get_type() == Measure::SurfaceFeatureType::Plane) {
|
||||
return true;
|
||||
}
|
||||
if (m_assembly_mode == AssemblyMode::POINT_POINT &&
|
||||
(item.feature->get_type() == Measure::SurfaceFeatureType::Point||
|
||||
item.feature->get_type() == Measure::SurfaceFeatureType::Circle)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -155,6 +155,7 @@ protected:
|
|||
|
||||
EMode m_mode{ EMode::FeatureSelection };
|
||||
Measure::MeasurementResult m_measurement_result;
|
||||
Measure::AssemblyAction m_assembly_action;
|
||||
std::map<GLVolume*, std::shared_ptr<Measure::Measuring>> m_mesh_measure_map;
|
||||
std::shared_ptr<Measure::Measuring> m_curr_measuring{nullptr};
|
||||
|
||||
|
@ -198,6 +199,8 @@ protected:
|
|||
unsigned int m_last_active_item_imgui{0};
|
||||
Vec3d m_buffered_distance;
|
||||
Vec3d m_distance;
|
||||
double m_buffered_parallel_distance{0};
|
||||
double m_buffered_around_center{0};
|
||||
// used to keep the raycasters for point/center spheres
|
||||
//std::vector<std::shared_ptr<PickRaycaster>> m_selected_sphere_raycasters;
|
||||
std::optional<Measure::SurfaceFeature> m_curr_feature;
|
||||
|
@ -259,9 +262,12 @@ protected:
|
|||
void show_selection_ui();
|
||||
void show_distance_xyz_ui();
|
||||
//void show_point_point_assembly();
|
||||
void show_face_face_assembly_common();
|
||||
void show_face_face_assembly_senior();
|
||||
void init_render_input_window();
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
virtual void render_input_window_warning(bool same_model_object);
|
||||
void remove_selected_sphere_raycaster(int id);
|
||||
void update_measurement_result();
|
||||
|
||||
|
@ -289,6 +295,13 @@ protected:
|
|||
void update_world_plane_features(Measure::Measuring *cur_measuring, Measure::SurfaceFeature &feautre);
|
||||
void update_feature_by_tran(Measure::SurfaceFeature & feature);
|
||||
void set_distance(bool same_model_object, const Vec3d &displacement, bool take_shot = true);
|
||||
void set_to_parallel(bool same_model_object, bool take_shot = true, bool is_anti_parallel = false);
|
||||
void set_to_reverse_rotation(bool same_model_object,int feature_index);
|
||||
void set_to_around_center_of_faces(bool same_model_object,float rotate_degree);
|
||||
void set_to_center_coincidence(bool same_model_object);
|
||||
void set_parallel_distance(bool same_model_object,float dist);
|
||||
|
||||
bool is_pick_meet_assembly_mode(const SelectedFeatures::Item& item);
|
||||
protected:
|
||||
// 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.
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoEmboss.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSVG.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoMeasure.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoAssembly.hpp"
|
||||
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
@ -62,6 +62,7 @@ std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
|
|||
if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
|
||||
for (size_t i = 0; i < m_gizmos.size(); ++i)
|
||||
if (m_gizmos[i]->get_sprite_id() == (unsigned int) Measure ||
|
||||
m_gizmos[i]->get_sprite_id() == (unsigned int) Assembly ||
|
||||
m_gizmos[i]->get_sprite_id() == (unsigned int) MmuSegmentation)
|
||||
out.push_back(i);
|
||||
}
|
||||
|
@ -162,6 +163,9 @@ void GLGizmosManager::switch_gizmos_icon_filename()
|
|||
case (EType::Measure):
|
||||
gizmo->set_icon_filename(m_is_dark ? "toolbar_measure_dark.svg" : "toolbar_measure.svg");
|
||||
break;
|
||||
case (EType::Assembly):
|
||||
gizmo->set_icon_filename(m_is_dark ? "toolbar_assembly_dark.svg" : "toolbar_assembly.svg");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -200,6 +204,7 @@ bool GLGizmosManager::init()
|
|||
m_gizmos.emplace_back(new GLGizmoEmboss(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Emboss));
|
||||
m_gizmos.emplace_back(new GLGizmoSVG(m_parent));
|
||||
m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, m_is_dark ? "toolbar_measure_dark.svg" : "toolbar_measure.svg", EType::Measure));
|
||||
m_gizmos.emplace_back(new GLGizmoAssembly(m_parent, m_is_dark ? "toolbar_assembly_dark.svg" : "toolbar_assembly.svg", EType::Assembly));
|
||||
m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "reduce_triangles.svg", EType::Simplify));
|
||||
//m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", sprite_id++));
|
||||
//m_gizmos.emplace_back(new GLGizmoFaceDetector(m_parent, "face recognition.svg", sprite_id++));
|
||||
|
@ -343,8 +348,8 @@ bool GLGizmosManager::check_gizmos_closed_except(EType type) const
|
|||
|
||||
void GLGizmosManager::set_hover_id(int id)
|
||||
{
|
||||
// Measure handles hover by itself
|
||||
if (m_current == EType::Measure) { return; }
|
||||
// Measure and assembly handles hover by itself
|
||||
if (m_current == EType::Measure || m_current == EType::Assembly) { return; }
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
|
@ -439,6 +444,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
|
|||
return dynamic_cast<GLGizmoMmuSegmentation*>(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Measure)
|
||||
return dynamic_cast<GLGizmoMeasure *>(m_gizmos[Measure].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Assembly)
|
||||
return dynamic_cast<GLGizmoAssembly *>(m_gizmos[Assembly].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Cut)
|
||||
return dynamic_cast<GLGizmoCut3D*>(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == MeshBoolean)
|
||||
|
@ -701,7 +708,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
case WXK_ESCAPE:
|
||||
{
|
||||
if (m_current != Undefined) {
|
||||
if (m_current == Measure && gizmo_event(SLAGizmoEventType::Escape)) {
|
||||
if ((m_current == Measure || m_current == Assembly) && gizmo_event(SLAGizmoEventType::Escape)) {
|
||||
// do nothing
|
||||
} else
|
||||
//if ((m_current != SlaSupports) || !gizmo_event(SLAGizmoEventType::DiscardChanges))
|
||||
|
@ -740,7 +747,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
|
||||
case WXK_BACK:
|
||||
case WXK_DELETE: {
|
||||
if ((m_current == Cut || m_current == Measure) && gizmo_event(SLAGizmoEventType::Delete))
|
||||
if ((m_current == Cut || m_current == Measure || m_current == Assembly) && gizmo_event(SLAGizmoEventType::Delete))
|
||||
processed = true;
|
||||
break;
|
||||
}
|
||||
|
@ -838,7 +845,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
|||
processed = true;
|
||||
}
|
||||
}*/
|
||||
if (m_current == Measure) {
|
||||
if (m_current == Measure || m_current == Assembly) {
|
||||
if (keyCode == WXK_CONTROL)
|
||||
gizmo_event(SLAGizmoEventType::CtrlUp, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown());
|
||||
else if (keyCode == WXK_SHIFT)
|
||||
|
@ -925,8 +932,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
|||
// force extra frame to automatically update window size
|
||||
wxGetApp().imgui()->set_requires_extra_frame();
|
||||
}
|
||||
}
|
||||
else if (m_current == Measure) {
|
||||
} else if (m_current == Measure || m_current == Assembly) {
|
||||
if (keyCode == WXK_CONTROL)
|
||||
gizmo_event(SLAGizmoEventType::CtrlDown, Vec2d::Zero(), evt.ShiftDown(), evt.AltDown(), evt.CmdDown());
|
||||
else if (keyCode == WXK_SHIFT)
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
Emboss,
|
||||
Svg,
|
||||
Measure,
|
||||
Assembly,
|
||||
Simplify,
|
||||
//SlaSupports,
|
||||
// BBS
|
||||
|
|
|
@ -1720,6 +1720,66 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
|||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::translate(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx, const Vec3d &displacement) {
|
||||
if (!m_valid) return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (v.object_idx() == (int) object_idx && v.instance_idx() == (int) instance_idx && v.volume_idx() == (int) volume_idx)
|
||||
v.set_volume_offset(v.get_volume_offset() + displacement);
|
||||
}
|
||||
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::rotate(unsigned int object_idx, unsigned int instance_idx, const Transform3d &overwrite_tran)
|
||||
{
|
||||
if (!m_valid) return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (v.object_idx() == (int) object_idx && v.instance_idx() == (int) instance_idx) {
|
||||
v.set_instance_transformation(overwrite_tran);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<unsigned int> done; // prevent processing volumes twice
|
||||
done.insert(m_list.begin(), m_list.end());
|
||||
for (unsigned int i : m_list) {
|
||||
if (done.size() == m_volumes->size()) break;
|
||||
|
||||
int object_idx = (*m_volumes)[i]->object_idx();
|
||||
if (object_idx >= 1000) continue;
|
||||
|
||||
// Process unselected volumes of the object.
|
||||
for (unsigned int j = 0; j < (unsigned int) m_volumes->size(); ++j) {
|
||||
if (done.size() == m_volumes->size()) break;
|
||||
|
||||
if (done.find(j) != done.end()) continue;
|
||||
|
||||
GLVolume &v = *(*m_volumes)[j];
|
||||
if (v.object_idx() != object_idx || v.instance_idx() != (int) instance_idx)
|
||||
continue;
|
||||
|
||||
v.set_instance_transformation(overwrite_tran);
|
||||
done.insert(j);
|
||||
}
|
||||
}
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
void Selection::rotate(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx, const Transform3d &overwrite_tran)
|
||||
{
|
||||
if (!m_valid) return;
|
||||
|
||||
for (unsigned int i : m_list) {
|
||||
GLVolume &v = *(*m_volumes)[i];
|
||||
if (v.object_idx() == (int) object_idx && v.instance_idx() == (int) instance_idx && v.volume_idx() == (int) volume_idx) {
|
||||
v.set_volume_transformation(overwrite_tran);
|
||||
}
|
||||
}
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
//BBS: add partplate related logic
|
||||
void Selection::notify_instance_update(int object_idx, int instance_idx)
|
||||
{
|
||||
|
|
|
@ -344,6 +344,10 @@ public:
|
|||
|
||||
void translate(unsigned int object_idx, const Vec3d& displacement);
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx, const Vec3d &displacement);
|
||||
|
||||
void rotate(unsigned int object_idx, unsigned int instance_idx, const Transform3d &overwrite_tran);
|
||||
void rotate(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx, const Transform3d &overwrite_tran);
|
||||
//BBS: add partplate related logic
|
||||
void notify_instance_update(int object_idx, int instance_idx);
|
||||
// BBS
|
||||
|
|
Loading…
Reference in a new issue