mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 14:44:19 -06:00
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
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;
|
||||
|
||||
|
@ -438,7 +443,9 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
|
|||
else if (m_current == MmuSegmentation)
|
||||
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);
|
||||
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…
Add table
Add a link
Reference in a new issue