Merge remote-tracking branch 'origin/ys_wx317_master' into ys_cut

This commit is contained in:
YuSanka 2022-06-29 11:44:11 +02:00
commit 89a7f6bdb1
167 changed files with 26900 additions and 24434 deletions

View file

@ -52,10 +52,17 @@ static choice_ctrl* create_word_local_combo(wxWindow *parent)
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
#if ENABLE_WORLD_COORDINATE
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
temp->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
temp->Select((int)ECoordinatesType::World);
#else
temp->Append(_L("World coordinates"));
temp->Append(_L("Local coordinates"));
temp->SetSelection(0);
temp->SetValue(temp->GetString(0));
#endif // ENABLE_WORLD_COORDINATE
temp->SetToolTip(_L("Select coordinate space, in which the transformation will be performed."));
return temp;
@ -81,8 +88,14 @@ void msw_rescale_word_local_combo(choice_ctrl* combo)
// Set rescaled size
combo->SetSize(size);
#if ENABLE_WORLD_COORDINATE
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::World));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Instance));
combo->Append(ObjectManipulation::coordinate_type_str(ECoordinatesType::Local));
#else
combo->Append(_L("World coordinates"));
combo->Append(_L("Local coordinates"));
#endif // ENABLE_WORLD_COORDINATE
combo->SetValue(selection);
#else
@ -101,6 +114,7 @@ static void set_font_and_background_style(wxWindow* win, const wxFont& font)
static const wxString axes_color_text[] = { "#990000", "#009900", "#000099" };
static const wxString axes_color_back[] = { "#f5dcdc", "#dcf5dc", "#dcdcf5" };
ObjectManipulation::ObjectManipulation(wxWindow* parent) :
OG_Settings(parent, true)
{
@ -112,7 +126,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// Load bitmaps to be used for the mirroring buttons:
m_mirror_bitmap_on = ScalableBitmap(parent, "mirroring_on");
m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off");
m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent.png");
m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent");
const int border = wxOSX ? 0 : 4;
const int em = wxGetApp().em_unit();
@ -157,8 +171,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
// Add world local combobox
m_word_local_combo = create_word_local_combo(parent);
m_word_local_combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent& evt) {
#if ENABLE_WORLD_COORDINATE
this->set_coordinates_type(evt.GetString());
#else
this->set_world_coordinates(evt.GetSelection() != 1);
}), m_word_local_combo->GetId());
#endif // ENABLE_WORLD_COORDINATE
}), m_word_local_combo->GetId());
// Small trick to correct layouting in different view_mode :
// Show empty string of a same height as a m_word_local_combo, when m_word_local_combo is hidden
@ -264,8 +282,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
#endif // ENABLE_WORLD_COORDINATE
GLVolume* volume = const_cast<GLVolume*>(selection.get_first_volume());
volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
}
else if (selection.is_single_full_instance()) {
@ -278,7 +300,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
return;
// Update mirroring at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes();
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_mirror(L("Set Mirror"));
@ -327,28 +349,60 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const double min_z = get_volume_min_z(*volume);
if (!is_world_coordinates()) {
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
const Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(*volume));
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix(true).inverse() * (get_volume_min_z(*volume) * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
#endif // ENABLE_WORLD_COORDINATE
}
else if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const double min_z = selection.get_scaled_instance_bounding_box().min.z();
if (!is_world_coordinates()) {
const GLVolume* volume = selection.get_first_volume();
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(0, diff.x());
change_position_value(1, diff.y());
change_position_value(2, diff.z());
}
else {
#else
const ModelObjectPtrs& objects = wxGetApp().model().objects;
const int idx = selection.get_object_idx();
if (0 <= idx && idx < static_cast<int>(objects.size())) {
const ModelObject* mo = wxGetApp().model().objects[idx];
const double min_z = mo->bounding_box().min.z();
if (std::abs(min_z) > SINKING_Z_THRESHOLD) {
#endif // ENABLE_WORLD_COORDINATE
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Drop to bed"));
change_position_value(2, m_cache.position.z() - min_z);
}
#if !ENABLE_WORLD_COORDINATE
}
#endif // !ENABLE_WORLD_COORDINATE
}
});
editors_grid_sizer->Add(m_drop_to_bed_button);
@ -365,21 +419,22 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
volume->set_volume_rotation(Vec3d::Zero());
}
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier())
#else
if (selection.is_single_volume() || selection.is_single_modifier())
#endif // ENABLE_WORLD_COORDINATE
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_rotation(Vec3d::Zero());
else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
volume->set_instance_rotation(Vec3d::Zero());
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
}
}
else
return;
// Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
selection.synchronize_unselected_instances(Selection::SyncRotationType::GENERAL);
selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
canvas->do_rotate(L("Reset Rotation"));
@ -397,11 +452,29 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_scale_button->SetToolTip(_L("Reset scale"));
m_reset_scale_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
#if ENABLE_WORLD_COORDINATE
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_volume_or_modifier())
const_cast<GLVolume*>(selection.get_first_volume())->set_volume_scaling_factor(Vec3d::Ones());
else if (selection.is_single_full_instance()) {
for (unsigned int idx : selection.get_volume_idxs()) {
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_scaling_factor(Vec3d::Ones());
}
}
else
return;
canvas->do_scale(L("Reset scale"));
UpdateAndShow(true);
#else
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Reset scale"));
change_scale_value(0, 100.);
change_scale_value(1, 100.);
change_scale_value(2, 100.);
});
#endif // ENABLE_WORLD_COORDINATE
});
editors_grid_sizer->Add(m_reset_scale_button);
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
@ -411,6 +484,25 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND);
#if ENABLE_WORLD_COORDINATE
m_skew_label = new wxStaticText(parent, wxID_ANY, _L("Skew"));
m_main_grid_sizer->Add(m_skew_label, 1, wxEXPAND);
m_reset_skew_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
m_reset_skew_button->SetToolTip(_L("Reset skew"));
m_reset_skew_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
selection.setup_cache();
selection.reset_skew();
canvas->do_reset_skew(L("Reset skew"));
UpdateAndShow(true);
}
});
m_main_grid_sizer->Add(m_reset_skew_button);
#endif // ENABLE_WORLD_COORDINATE
m_check_inch = new wxCheckBox(parent, wxID_ANY, _L("Inches"));
m_check_inch->SetFont(wxGetApp().normal_font());
@ -444,8 +536,27 @@ void ObjectManipulation::Show(const bool show)
if (show) {
// Show the "World Coordinates" / "Local Coordintes" Combo in Advanced / Expert mode only.
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
m_word_local_combo->Show(show_world_local_combo);
#if ENABLE_WORLD_COORDINATE
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
bool show_world_local_combo = wxGetApp().get_mode() != comSimple && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier());
if (selection.is_single_volume_or_modifier() && m_word_local_combo->GetCount() < 3) {
#ifdef __linux__
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), 1);
#else
m_word_local_combo->Insert(coordinate_type_str(ECoordinatesType::Instance), wxNullBitmap, 1);
#endif // __linux__
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
else if (selection.is_single_full_instance() && m_word_local_combo->GetCount() > 2) {
m_word_local_combo->Delete(1);
m_word_local_combo->Select((int)ECoordinatesType::World);
this->set_coordinates_type(m_word_local_combo->GetString(m_word_local_combo->GetSelection()));
}
#else
bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance() && wxGetApp().get_mode() != comSimple;
#endif // ENABLE_WORLD_COORDINATE
m_word_local_combo->Show(show_world_local_combo);
m_empty_str->Show(!show_world_local_combo);
}
}
@ -505,8 +616,7 @@ void ObjectManipulation::update_ui_from_settings()
}
m_check_inch->SetValue(m_imperial_units);
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1"))
{
if (m_use_colors != (wxGetApp().app_config->get("color_mapinulation_panel") == "1")) {
m_use_colors = wxGetApp().app_config->get("color_mapinulation_panel") == "1";
// update colors for edit-boxes
int axis_id = 0;
@ -538,33 +648,49 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors");
#if !ENABLE_WORLD_COORDINATE
if (wxGetApp().get_mode() == comSimple)
m_world_coordinates = true;
#endif // !ENABLE_WORLD_COORDINATE
ObjectList* obj_list = wxGetApp().obj_list();
if (selection.is_single_full_instance()) {
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
#if !ENABLE_WORLD_COORDINATE
m_new_position = volume->get_instance_offset();
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
if (m_world_coordinates && ! m_uniform_scale &&
if (m_world_coordinates && ! m_uniform_scale &&
! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling.
m_uniform_scale = true;
m_lock_bnt->SetLock(true);
}
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
m_new_position = volume->get_instance_offset();
#else
if (m_world_coordinates) {
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
m_new_size = selection.get_scaled_instance_bounding_box().size();
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.;
}
#endif // ENABLE_WORLD_COORDINATE
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
m_new_size = selection.get_scaled_instance_bounding_box().size();
m_new_scale = m_new_size.cwiseQuotient(selection.get_unscaled_instance_bounding_box().size()) * 100.0;
}
else {
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
m_new_scale = volume->get_instance_scaling_factor() * 100.;
#if ENABLE_WORLD_COORDINATE
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
#else
m_new_rotation = volume->get_instance_rotation() * (180.0 / M_PI);
#endif // ENABLE_WORLD_COORDINATE
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
m_new_scale = volume->get_instance_scaling_factor() * 100.0;
}
m_new_enabled = true;
@ -573,19 +699,52 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
const BoundingBoxf3& box = selection.get_bounding_box();
m_new_position = box.center();
m_new_rotation = Vec3d::Zero();
m_new_scale = Vec3d(100., 100., 100.);
m_new_scale = Vec3d(100.0, 100.0, 100.0);
m_new_size = box.size();
m_new_rotate_label_string = L("Rotate");
m_new_scale_label_string = L("Scale");
m_new_enabled = true;
}
#if ENABLE_WORLD_COORDINATE
else if (selection.is_single_volume_or_modifier()) {
#else
else if (selection.is_single_modifier() || selection.is_single_volume()) {
#endif // ENABLE_WORLD_COORDINATE
// the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
#if ENABLE_WORLD_COORDINATE
if (is_world_coordinates()) {
const Geometry::Transformation trafo(volume->world_matrix());
const Vec3d& offset = trafo.get_offset();
m_new_position = offset;
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
m_new_size = volume->transformed_convex_hull_bounding_box(trafo.get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_instance_transformation().get_matrix() * volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
else if (is_local_coordinates()) {
m_new_move_label_string = L("Translate");
m_new_rotate_label_string = L("Rotate");
m_new_position = Vec3d::Zero();
m_new_rotation = Vec3d::Zero();
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size());
}
else {
#endif // ENABLE_WORLD_COORDINATE
m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
m_new_scale = volume->get_volume_scaling_factor() * 100.;
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
m_new_rotate_label_string = L("Rotate");
m_new_rotation = Vec3d::Zero();
#if ENABLE_WORLD_COORDINATE
m_new_size = volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix()).size();
m_new_scale = m_new_size.cwiseQuotient(volume->transformed_convex_hull_bounding_box(volume->get_volume_transformation().get_matrix_no_scaling_factor()).size()) * 100.0;
}
#else
m_new_scale = volume->get_volume_scaling_factor() * 100.0;
m_new_size = volume->get_instance_scaling_factor().cwiseProduct(volume->get_volume_scaling_factor().cwiseProduct(volume->bounding_box().size()));
#endif // ENABLE_WORLD_COORDINATE
m_new_enabled = true;
}
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) {
@ -651,22 +810,26 @@ void ObjectManipulation::update_if_dirty()
update(m_cache.rotation, m_cache.rotation_rounded, meRotation, m_new_rotation);
}
#if !ENABLE_WORLD_COORDINATE
if (selection.requires_uniform_scale()) {
m_lock_bnt->SetLock(true);
m_lock_bnt->SetToolTip(_L("You cannot use non-uniform scaling mode for multiple objects/parts selection"));
m_lock_bnt->disable();
}
else {
#endif // !ENABLE_WORLD_COORDINATE
m_lock_bnt->SetLock(m_uniform_scale);
m_lock_bnt->SetToolTip(wxEmptyString);
m_lock_bnt->enable();
#if !ENABLE_WORLD_COORDINATE
}
{
{
int new_selection = m_world_coordinates ? 0 : 1;
if (m_word_local_combo->GetSelection() != new_selection)
m_word_local_combo->SetSelection(new_selection);
}
#endif // !ENABLE_WORLD_COORDINATE
if (m_new_enabled)
m_og->enable();
@ -693,29 +856,75 @@ void ObjectManipulation::update_reset_buttons_visibility()
bool show_rotation = false;
bool show_scale = false;
bool show_drop_to_bed = false;
#if ENABLE_WORLD_COORDINATE
bool show_skew = false;
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
const double min_z = selection.is_single_full_instance() ? selection.get_scaled_instance_bounding_box().min.z() :
get_volume_min_z(*selection.get_first_volume());
show_drop_to_bed = std::abs(min_z) > EPSILON;
const GLVolume* volume = selection.get_first_volume();
Transform3d rotation = Transform3d::Identity();
Transform3d scale = Transform3d::Identity();
Geometry::Transformation skew;
#else
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
Vec3d rotation;
Vec3d scale;
double min_z = 0.;
double min_z = 0.0;
#endif // ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance()) {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_instance_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int id : idxs) {
const Geometry::Transformation world_trafo(selection.get_volume(id)->world_matrix());
if (world_trafo.has_skew()) {
skew = world_trafo;
break;
}
}
#else
rotation = volume->get_instance_rotation();
scale = volume->get_instance_scaling_factor();
min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z();
min_z = selection.get_scaled_instance_bounding_box().min.z();
#endif // ENABLE_WORLD_COORDINATE
}
else {
#if ENABLE_WORLD_COORDINATE
const Geometry::Transformation& trafo = volume->get_volume_transformation();
rotation = trafo.get_rotation_matrix();
scale = trafo.get_scaling_factor_matrix();
const Geometry::Transformation world_trafo(volume->world_matrix());
if (world_trafo.has_skew())
skew = world_trafo;
#else
rotation = volume->get_volume_rotation();
scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(*volume);
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
show_rotation = !rotation.isApprox(Transform3d::Identity());
show_scale = !scale.isApprox(Transform3d::Identity());
show_skew = skew.has_skew();
#else
show_rotation = !rotation.isApprox(Vec3d::Zero());
show_scale = !scale.isApprox(Vec3d::Ones());
show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD;
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed, show_skew] {
#else
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
#endif // ENABLE_WORLD_COORDINATE
// There is a case (under OSX), when this function is called after the Manipulation panel is hidden
// So, let check if Manipulation panel is still shown for this moment
if (!this->IsShown())
@ -723,6 +932,10 @@ void ObjectManipulation::update_reset_buttons_visibility()
m_reset_rotation_button->Show(show_rotation);
m_reset_scale_button->Show(show_scale);
m_drop_to_bed_button->Show(show_drop_to_bed);
#if ENABLE_WORLD_COORDINATE
m_reset_skew_button->Show(show_skew);
m_skew_label->Show(show_skew);
#endif // ENABLE_WORLD_COORDINATE
// Because of CallAfter we need to layout sidebar after Show/hide of reset buttons one more time
Sidebar& panel = wxGetApp().sidebar();
@ -742,9 +955,17 @@ void ObjectManipulation::update_mirror_buttons_visibility()
Selection& selection = canvas->get_selection();
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
#if ENABLE_WORLD_COORDINATE
if (is_local_coordinates()) {
#else
if (!m_world_coordinates) {
#endif // ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_full_instance() || selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#endif // ENABLE_WORLD_COORDINATE
const GLVolume* volume = selection.get_first_volume();
Vec3d mirror;
if (selection.is_single_full_instance())
@ -804,10 +1025,23 @@ void ObjectManipulation::update_warning_icon_state(const MeshErrorsInfo& warning
m_manifold_warning_bmp = ScalableBitmap(m_parent, warning_icon_name);
const wxString& tooltip = warning.tooltip;
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.bmp().GetSize());
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0,0) : m_manifold_warning_bmp.GetSize());
m_fix_throught_netfab_bitmap->SetToolTip(tooltip);
}
#if ENABLE_WORLD_COORDINATE
wxString ObjectManipulation::coordinate_type_str(ECoordinatesType type)
{
switch (type)
{
case ECoordinatesType::World: { return _L("World coordinates"); }
case ECoordinatesType::Instance: { return _L("Instance coordinates"); }
case ECoordinatesType::Local: { return _L("Local coordinates"); }
default: { assert(false); return _L("Unknown"); }
}
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::reset_settings_value()
{
m_new_position = Vec3d::Zero();
@ -831,7 +1065,19 @@ void ObjectManipulation::change_position_value(int axis, double value)
auto canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
selection.setup_cache();
#if ENABLE_WORLD_COORDINATE
TransformationType trafo_type;
trafo_type.set_relative();
switch (get_coordinates_type())
{
case ECoordinatesType::Instance: { trafo_type.set_instance(); break; }
case ECoordinatesType::Local: { trafo_type.set_local(); break; }
default: { break; }
}
selection.translate(position - m_cache.position, trafo_type);
#else
selection.translate(position - m_cache.position, selection.requires_local_axes());
#endif // ENABLE_WORLD_COORDINATE
canvas->do_move(L("Set Position"));
m_cache.position = position;
@ -850,6 +1096,18 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
Selection& selection = canvas->get_selection();
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
transformation_type.set_relative();
if (selection.is_single_full_instance())
transformation_type.set_independent();
if (is_local_coordinates())
transformation_type.set_local();
if (is_instance_coordinates())
transformation_type.set_instance();
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance() || selection.requires_local_axes())
transformation_type.set_independent();
@ -858,6 +1116,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
// transformation_type.set_absolute();
transformation_type.set_local();
}
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache();
selection.rotate(
@ -903,8 +1162,12 @@ void ObjectManipulation::change_size_value(int axis, double value)
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
Vec3d ref_size = m_cache.size;
#if ENABLE_WORLD_COORDINATE
if (selection.is_single_volume_or_modifier()) {
#else
if (selection.is_single_volume() || selection.is_single_modifier()) {
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
#endif // ENABLE_WORLD_COORDINATE
const GLVolume* v = selection.get_first_volume();
const Vec3d local_size = size.cwiseQuotient(v->get_instance_scaling_factor());
const Vec3d local_ref_size = v->bounding_box().size().cwiseProduct(v->get_volume_scaling_factor());
const Vec3d local_change = local_size.cwiseQuotient(local_ref_size);
@ -913,11 +1176,19 @@ void ObjectManipulation::change_size_value(int axis, double value)
ref_size = Vec3d::Ones();
}
else if (selection.is_single_full_instance())
ref_size = m_world_coordinates ?
#if ENABLE_WORLD_COORDINATE
ref_size = is_world_coordinates() ?
#else
ref_size = m_world_coordinates ?
#endif // ENABLE_WORLD_COORDINATE
selection.get_unscaled_instance_bounding_box().size() :
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
wxGetApp().model().objects[selection.get_first_volume()->object_idx()]->raw_mesh_bounding_box().size();
#if ENABLE_WORLD_COORDINATE
this->do_size(axis, size.cwiseQuotient(ref_size));
#else
this->do_scale(axis, size.cwiseQuotient(ref_size));
#endif // ENABLE_WORLD_COORDINATE
m_cache.size = size;
m_cache.size_rounded(axis) = DBL_MAX;
@ -927,8 +1198,22 @@ void ObjectManipulation::change_size_value(int axis, double value)
void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
#if !ENABLE_WORLD_COORDINATE
Vec3d scaling_factor = scale;
#endif // !ENABLE_WORLD_COORDINATE
#if ENABLE_WORLD_COORDINATE
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
if (!selection.is_single_full_instance() && !selection.is_single_volume_or_modifier())
transformation_type.set_relative();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
#else
TransformationType transformation_type(TransformationType::World_Relative_Joint);
if (selection.is_single_full_instance()) {
transformation_type.set_absolute();
@ -938,12 +1223,31 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
if (m_uniform_scale || selection.requires_uniform_scale())
scaling_factor = scale(axis) * Vec3d::Ones();
#endif // ENABLE_WORLD_COORDINATE
selection.setup_cache();
selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
{
Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
TransformationType transformation_type;
if (is_local_coordinates())
transformation_type.set_local();
else if (is_instance_coordinates())
transformation_type.set_instance();
const Vec3d scaling_factor = m_uniform_scale ? scale(axis) * Vec3d::Ones() : scale;
selection.setup_cache();
selection.scale(scaling_factor, transformation_type);
wxGetApp().plater()->canvas3D()->do_scale(L("Set Size"));
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::on_change(const std::string& opt_key, int axis, double new_value)
{
if (!m_cache.is_valid())
@ -978,17 +1282,26 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
}
}
void ObjectManipulation::set_uniform_scaling(const bool new_value)
void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
{
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
if (selection.is_single_full_instance() && m_world_coordinates && !new_value) {
#if ENABLE_WORLD_COORDINATE
if (!use_uniform_scale)
// Recalculate cached values at this panel, refresh the screen.
this->UpdateAndShow(true);
m_uniform_scale = use_uniform_scale;
set_dirty();
#else
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
if (selection.is_single_full_instance() && m_world_coordinates && !use_uniform_scale) {
// Verify whether the instance rotation is multiples of 90 degrees, so that the scaling in world coordinates is possible.
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
const GLVolume* volume = selection.get_first_volume();
// Is the angle close to a multiple of 90 degrees?
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
if (!Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system.
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
//wxMessageDialog dlg(GUI::wxGetApp().mainframe,
MessageDialog dlg(GUI::wxGetApp().mainframe,
_L("The currently manipulated object is tilted (rotation angles are not multiples of 90°).\n"
"Non-uniform scaling of tilted objects is only possible in the World coordinate system,\n"
@ -996,7 +1309,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
_L("This operation is irreversible.\n"
"Do you want to proceed?"),
SLIC3R_APP_NAME,
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_QUESTION);
if (dlg.ShowModal() != wxID_YES) {
// Enforce uniform scaling.
m_lock_bnt->SetLock(true);
@ -1010,31 +1323,39 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
this->UpdateAndShow(true);
}
}
m_uniform_scale = new_value;
m_uniform_scale = use_uniform_scale;
#endif // ENABLE_WORLD_COORDINATE
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(ECoordinatesType type)
{
if (wxGetApp().get_mode() == comSimple)
type = ECoordinatesType::World;
if (m_coordinates_type == type)
return;
m_coordinates_type = type;
this->UpdateAndShow(true);
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
canvas->get_gizmos_manager().update_data();
canvas->set_as_dirty();
canvas->request_extra_frame();
}
#endif // ENABLE_WORLD_COORDINATE
void ObjectManipulation::msw_rescale()
{
const int em = wxGetApp().em_unit();
m_item_name->SetMinSize(wxSize(20*em, wxDefaultCoord));
msw_rescale_word_local_combo(m_word_local_combo);
m_word_local_combo_sizer->SetMinSize(wxSize(-1, m_word_local_combo->GetBestHeight(-1)));
m_manifold_warning_bmp.msw_rescale();
const wxString& tooltip = m_fix_throught_netfab_bitmap->GetToolTipText();
m_fix_throught_netfab_bitmap->SetBitmap(tooltip.IsEmpty() ? wxNullBitmap : m_manifold_warning_bmp.bmp());
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0, 0) : m_manifold_warning_bmp.bmp().GetSize());
m_mirror_bitmap_on.msw_rescale();
m_mirror_bitmap_off.msw_rescale();
m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale();
m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale();
for (int id = 0; id < 3; ++id)
m_mirror_buttons[id].first->msw_rescale();
m_fix_throught_netfab_bitmap->SetMinSize(tooltip.IsEmpty() ? wxSize(0, 0) : m_manifold_warning_bmp.GetSize());
// rescale label-heights
// Text trick to grid sizer layout:
@ -1063,19 +1384,31 @@ void ObjectManipulation::sys_color_changed()
for (ManipulationEditor* editor : m_editors)
editor->sys_color_changed(this);
// btn...->msw_rescale() updates icon on button, so use it
m_mirror_bitmap_on.msw_rescale();
m_mirror_bitmap_off.msw_rescale();
m_mirror_bitmap_hidden.msw_rescale();
m_reset_scale_button->msw_rescale();
m_reset_rotation_button->msw_rescale();
m_drop_to_bed_button->msw_rescale();
m_lock_bnt->msw_rescale();
m_mirror_bitmap_on.sys_color_changed();
m_mirror_bitmap_off.sys_color_changed();
m_mirror_bitmap_hidden.sys_color_changed();
m_reset_scale_button->sys_color_changed();
m_reset_rotation_button->sys_color_changed();
m_drop_to_bed_button->sys_color_changed();
m_lock_bnt->sys_color_changed();
for (int id = 0; id < 3; ++id)
m_mirror_buttons[id].first->msw_rescale();
m_mirror_buttons[id].first->sys_color_changed();
}
#if ENABLE_WORLD_COORDINATE
void ObjectManipulation::set_coordinates_type(const wxString& type_string)
{
ECoordinatesType type = ECoordinatesType::World;
if (type_string == coordinate_type_str(ECoordinatesType::Instance))
type = ECoordinatesType::Instance;
else if (type_string == coordinate_type_str(ECoordinatesType::Local))
type = ECoordinatesType::Local;
this->set_coordinates_type(type);
}
#endif // ENABLE_WORLD_COORDINATE
static const char axes[] = { 'x', 'y', 'z' };
ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
const std::string& opt_key,
@ -1117,8 +1450,8 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
parent->set_focused_editor(nullptr);
#if ENABLE_OBJECT_MANIPULATOR_FOCUS
// if the widgets exchanging focus are both manipulator fields, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr && dynamic_cast<ManipulationEditor*>(e.GetWindow()) != nullptr)
// if the widgets loosing focus is a manipulator field, call kill_focus
if (dynamic_cast<ManipulationEditor*>(e.GetEventObject()) != nullptr)
#else
if (!m_enter_pressed)
#endif // ENABLE_OBJECT_MANIPULATOR_FOCUS