Added method const GLVolume* Selection::get_first_volume() const to simplify client code
Fixed conflicts during rebase with master
This commit is contained in:
parent
9f503b95e8
commit
0e3490620e
@ -1530,7 +1530,7 @@ void ObjectList::load_modifier(const wxArrayString& input_files, ModelObject& mo
|
||||
const BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx);
|
||||
|
||||
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
const Geometry::Transformation inst_transform = v->get_instance_transformation();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
const Transform3d inv_inst_transform = inst_transform.get_matrix_no_offset().inverse();
|
||||
@ -1654,7 +1654,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
||||
ModelVolume *new_volume = model_object.add_volume(std::move(mesh), type);
|
||||
|
||||
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
// Transform the new modifier to be aligned with the print bed.
|
||||
const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box();
|
||||
new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb));
|
||||
@ -3282,7 +3282,7 @@ void ObjectList::update_selections()
|
||||
#else
|
||||
else if (selection.is_single_volume() || selection.is_any_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const auto gl_vol = selection.get_first_volume();
|
||||
if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())
|
||||
return;
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||
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()) {
|
||||
@ -351,7 +351,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
if (selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
const double min_z = get_volume_min_z(*volume);
|
||||
if (!is_world_coordinates()) {
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
@ -371,7 +371,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
}
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
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"));
|
||||
@ -384,7 +384,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
#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_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
const Vec3d diff = m_cache.position - volume->get_instance_transformation().get_matrix_no_offset().inverse() * (min_z * Vec3d::UnitZ());
|
||||
#else
|
||||
@ -432,7 +432,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()))->set_volume_rotation(Vec3d::Zero());
|
||||
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()) {
|
||||
const_cast<GLVolume*>(selection.get_volume(idx))->set_instance_rotation(Vec3d::Zero());
|
||||
@ -611,7 +611,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
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();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
@ -674,7 +674,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
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());
|
||||
@ -872,18 +872,18 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
||||
if ((m_coordinates_type == ECoordinatesType::World && selection.is_single_full_instance()) ||
|
||||
(m_coordinates_type == ECoordinatesType::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_volume(*selection.get_volume_idxs().begin()));
|
||||
get_volume_min_z(*selection.get_first_volume());
|
||||
|
||||
show_drop_to_bed = std::abs(min_z) > EPSILON;
|
||||
}
|
||||
|
||||
if (m_coordinates_type == ECoordinatesType::Local && (selection.is_single_full_instance() || selection.is_single_volume_or_modifier())) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d rotation = Vec3d::Zero();
|
||||
Vec3d scale = Vec3d::Ones();
|
||||
#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.0;
|
||||
@ -947,7 +947,7 @@ void ObjectManipulation::update_mirror_buttons_visibility()
|
||||
#else
|
||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Vec3d mirror;
|
||||
|
||||
if (selection.is_single_full_instance())
|
||||
@ -1141,7 +1141,7 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
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);
|
||||
@ -1156,7 +1156,7 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
||||
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_SCALE_REVISITED
|
||||
this->do_size(axis, size.cwiseQuotient(ref_size));
|
||||
@ -1196,10 +1196,10 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
||||
|
||||
if (!uniform_scale && is_world_coordinates()) {
|
||||
if (selection.is_single_full_instance())
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse();
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_volume_rotation()).inverse();
|
||||
scaling_factor = (mv * mi * scaling_factor).cwiseAbs();
|
||||
}
|
||||
}
|
||||
@ -1236,10 +1236,10 @@ void ObjectManipulation::do_size(int axis, const Vec3d& scale) const
|
||||
|
||||
if (!uniform_scale && is_world_coordinates()) {
|
||||
if (selection.is_single_full_instance())
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
scaling_factor = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse() * scaling_factor).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse();
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_volume_rotation()).inverse();
|
||||
scaling_factor = (mv * mi * scaling_factor).cwiseAbs();
|
||||
}
|
||||
}
|
||||
@ -1309,7 +1309,7 @@ void ObjectManipulation::set_uniform_scaling(const bool use_uniform_scale)
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// 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())) {
|
||||
// Cannot apply scaling in the world coordinate system.
|
||||
|
@ -1,416 +1,416 @@
|
||||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoCut.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/sizer.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const double GLGizmoCut::Offset = 10.0;
|
||||
const double GLGizmoCut::Margin = 20.0;
|
||||
static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE();
|
||||
|
||||
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
{}
|
||||
|
||||
std::string GLGizmoCut::get_tooltip() const
|
||||
{
|
||||
double cut_z = m_cut_z;
|
||||
if (wxGetApp().app_config->get("use_inches") == "1")
|
||||
cut_z *= ObjectManipulation::mm_to_in;
|
||||
|
||||
return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(cut_z, 2) : "";
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_init()
|
||||
{
|
||||
m_grabbers.emplace_back();
|
||||
m_shortcut_key = WXK_CONTROL_C;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GLGizmoCut::on_get_name() const
|
||||
{
|
||||
return _u8L("Cut");
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_set_state()
|
||||
{
|
||||
// Reset m_cut_z on gizmo activation
|
||||
if (m_state == On)
|
||||
m_cut_z = bounding_box().center().z();
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return selection.is_single_full_instance() && !selection.is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id == -1)
|
||||
return;
|
||||
|
||||
const BoundingBoxf3 box = bounding_box();
|
||||
m_max_z = box.max.z();
|
||||
m_start_z = m_cut_z;
|
||||
m_drag_pos = m_grabbers[m_hover_id].center;
|
||||
m_drag_center = box.center();
|
||||
m_drag_center.z() = m_cut_z;
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_dragging(const UpdateData &data)
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render()
|
||||
{
|
||||
const BoundingBoxf3 box = bounding_box();
|
||||
Vec3d plane_center = box.center();
|
||||
plane_center.z() = m_cut_z;
|
||||
m_max_z = box.max.z();
|
||||
set_cut_z(m_cut_z);
|
||||
|
||||
update_contours();
|
||||
|
||||
const float min_x = box.min.x() - Margin;
|
||||
const float max_x = box.max.x() + Margin;
|
||||
const float min_y = box.min.y() - Margin;
|
||||
const float max_y = box.max.y() + Margin;
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Vec3d diff = plane_center - m_old_center;
|
||||
// Z changed when move with cut plane
|
||||
// X and Y changed when move with cutted object
|
||||
bool is_changed = std::abs(diff.x()) > EPSILON ||
|
||||
std::abs(diff.y()) > EPSILON ||
|
||||
std::abs(diff.z()) > EPSILON;
|
||||
m_old_center = plane_center;
|
||||
|
||||
if (!m_plane.is_initialized() || is_changed) {
|
||||
m_plane.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f };
|
||||
init_data.reserve_vertices(4);
|
||||
init_data.reserve_indices(6);
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(min_x, min_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(max_x, min_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(max_x, max_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(min_x, max_y, plane_center.z()));
|
||||
|
||||
// indices
|
||||
init_data.add_triangle(0, 1, 2);
|
||||
init_data.add_triangle(2, 3, 0);
|
||||
|
||||
m_plane.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
|
||||
m_plane.render();
|
||||
#else
|
||||
// Draw the cutting plane
|
||||
::glBegin(GL_QUADS);
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, plane_center.z());
|
||||
::glVertex3f(max_x, min_y, plane_center.z());
|
||||
::glVertex3f(max_x, max_y, plane_center.z());
|
||||
::glVertex3f(min_x, max_y, plane_center.z());
|
||||
glsafe(::glEnd());
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
// Draw the grabber and the connecting line
|
||||
m_grabbers[0].center = plane_center;
|
||||
m_grabbers[0].center.z() = plane_center.z() + Offset;
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (!m_grabber_connection.is_initialized() || is_changed) {
|
||||
m_grabber_connection.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.color = ColorRGBA::YELLOW();
|
||||
init_data.reserve_vertices(2);
|
||||
init_data.reserve_indices(2);
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex((Vec3f)plane_center.cast<float>());
|
||||
init_data.add_vertex((Vec3f)m_grabbers[0].center.cast<float>());
|
||||
|
||||
// indices
|
||||
init_data.add_line(0, 1);
|
||||
|
||||
m_grabber_connection.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
m_grabber_connection.render();
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
#else
|
||||
glsafe(::glColor3f(1.0, 1.0, 0.0));
|
||||
::glBegin(GL_LINES);
|
||||
::glVertex3dv(plane_center.data());
|
||||
::glVertex3dv(m_grabbers[0].center.data());
|
||||
glsafe(::glEnd());
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
|
||||
m_grabbers[0].color = GRABBER_COLOR;
|
||||
m_grabbers[0].render(m_hover_id == 0, float((box.size().x() + box.size().y() + box.size().z()) / 3.0));
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
shader = wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* Geometry::assemble_transform(m_cut_contours.shift));
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
glsafe(::glLineWidth(2.0f));
|
||||
m_cut_contours.contours.render();
|
||||
#if !ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
glsafe(::glPopMatrix());
|
||||
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
shader->stop_using();
|
||||
}
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_for_picking()
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
static float last_y = 0.0f;
|
||||
static float last_h = 0.0f;
|
||||
|
||||
m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
const bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
|
||||
// adjust window position to avoid overlap the view toolbar
|
||||
const float win_h = ImGui::GetWindowHeight();
|
||||
y = std::min(y, bottom_limit - win_h);
|
||||
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
|
||||
if (last_h != win_h || last_y != y) {
|
||||
// ask canvas for another frame to render the window in the correct position
|
||||
m_imgui->set_requires_extra_frame();
|
||||
if (last_h != win_h)
|
||||
last_h = win_h;
|
||||
if (last_y != y)
|
||||
last_y = y;
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text("Z");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0f);
|
||||
|
||||
double cut_z = m_cut_z;
|
||||
if (imperial_units)
|
||||
cut_z *= ObjectManipulation::mm_to_in;
|
||||
ImGui::InputDouble("", &cut_z, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal);
|
||||
|
||||
ImGui::SameLine();
|
||||
m_imgui->text(imperial_units ? _L("in") : _L("mm"));
|
||||
|
||||
m_cut_z = cut_z * (imperial_units ? ObjectManipulation::in_to_mm : 1.0);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->checkbox(_L("Keep upper part"), m_keep_upper);
|
||||
m_imgui->checkbox(_L("Keep lower part"), m_keep_lower);
|
||||
m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) || m_cut_z <= 0.0 || m_max_z <= m_cut_z);
|
||||
const bool cut_clicked = m_imgui->button(_L("Perform cut"));
|
||||
m_imgui->disabled_end();
|
||||
|
||||
m_imgui->end();
|
||||
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower))
|
||||
perform_cut(m_parent.get_selection());
|
||||
}
|
||||
|
||||
void GLGizmoCut::set_cut_z(double cut_z)
|
||||
{
|
||||
// Clamp the plane to the object's bounding box
|
||||
m_cut_z = std::clamp(cut_z, 0.0, m_max_z);
|
||||
}
|
||||
|
||||
void GLGizmoCut::perform_cut(const Selection& selection)
|
||||
{
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
const int object_idx = selection.get_object_idx();
|
||||
|
||||
wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection");
|
||||
|
||||
// m_cut_z is the distance from the bed. Subtract possible SLA elevation.
|
||||
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z();
|
||||
|
||||
if (0.0 < object_cut_z && object_cut_z < m_max_z)
|
||||
wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z,
|
||||
only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) |
|
||||
only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) |
|
||||
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower));
|
||||
else {
|
||||
// the object is SLA-elevated and the plane is under it.
|
||||
}
|
||||
}
|
||||
|
||||
double GLGizmoCut::calc_projection(const Linef3& mouse_ray) const
|
||||
{
|
||||
double projection = 0.0;
|
||||
|
||||
const Vec3d starting_vec = m_drag_pos - m_drag_center;
|
||||
const double len_starting_vec = starting_vec.norm();
|
||||
if (len_starting_vec != 0.0) {
|
||||
const Vec3d mouse_dir = mouse_ray.unit_vector();
|
||||
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
|
||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||
const Vec3d inters = mouse_ray.a + (m_drag_pos - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
||||
// vector from the starting position to the found intersection
|
||||
const Vec3d inters_vec = inters - m_drag_pos;
|
||||
|
||||
// finds projection of the vector along the staring direction
|
||||
projection = inters_vec.dot(starting_vec.normalized());
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
BoundingBoxf3 GLGizmoCut::bounding_box() const
|
||||
{
|
||||
BoundingBoxf3 ret;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
return selection.get_bounding_box();
|
||||
|
||||
for (unsigned int i : idxs) {
|
||||
const GLVolume* volume = selection.get_volume(i);
|
||||
if (!volume->is_modifier)
|
||||
ret.merge(volume->transformed_convex_hull_bounding_box());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLGizmoCut::update_contours()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
|
||||
|
||||
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
std::vector<ObjectID> volumes_idxs = std::vector<ObjectID>(model_object->volumes.size());
|
||||
for (size_t i = 0; i < model_object->volumes.size(); ++i) {
|
||||
volumes_idxs[i] = model_object->volumes[i]->id();
|
||||
}
|
||||
|
||||
if (0.0 < m_cut_z && m_cut_z < m_max_z) {
|
||||
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() ||
|
||||
m_cut_contours.instance_idx != instance_idx || m_cut_contours.volumes_idxs != volumes_idxs) {
|
||||
m_cut_contours.cut_z = m_cut_z;
|
||||
|
||||
if (m_cut_contours.object_id != model_object->id() || m_cut_contours.volumes_idxs != volumes_idxs)
|
||||
m_cut_contours.mesh = model_object->raw_mesh();
|
||||
|
||||
m_cut_contours.position = box.center();
|
||||
m_cut_contours.shift = Vec3d::Zero();
|
||||
m_cut_contours.object_id = model_object->id();
|
||||
m_cut_contours.instance_idx = instance_idx;
|
||||
m_cut_contours.volumes_idxs = volumes_idxs;
|
||||
m_cut_contours.contours.reset();
|
||||
|
||||
MeshSlicingParams slicing_params;
|
||||
slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
|
||||
slicing_params.trafo.pretranslate(Vec3d(0., 0., first_glvolume->get_sla_shift_z()));
|
||||
|
||||
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params);
|
||||
if (!polys.empty()) {
|
||||
m_cut_contours.contours.init_from(polys, static_cast<float>(m_cut_z));
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
m_cut_contours.contours.set_color(ColorRGBA::WHITE());
|
||||
#else
|
||||
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
}
|
||||
}
|
||||
else if (box.center() != m_cut_contours.position) {
|
||||
m_cut_contours.shift = box.center() - m_cut_contours.position;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_cut_contours.contours.reset();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoCut.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/sizer.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const double GLGizmoCut::Offset = 10.0;
|
||||
const double GLGizmoCut::Margin = 20.0;
|
||||
static const ColorRGBA GRABBER_COLOR = ColorRGBA::ORANGE();
|
||||
|
||||
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
{}
|
||||
|
||||
std::string GLGizmoCut::get_tooltip() const
|
||||
{
|
||||
double cut_z = m_cut_z;
|
||||
if (wxGetApp().app_config->get("use_inches") == "1")
|
||||
cut_z *= ObjectManipulation::mm_to_in;
|
||||
|
||||
return (m_hover_id == 0 || m_grabbers[0].dragging) ? "Z: " + format(cut_z, 2) : "";
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_init()
|
||||
{
|
||||
m_grabbers.emplace_back();
|
||||
m_shortcut_key = WXK_CONTROL_C;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GLGizmoCut::on_get_name() const
|
||||
{
|
||||
return _u8L("Cut");
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_set_state()
|
||||
{
|
||||
// Reset m_cut_z on gizmo activation
|
||||
if (m_state == On)
|
||||
m_cut_z = bounding_box().center().z();
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return selection.is_single_full_instance() && !selection.is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id == -1)
|
||||
return;
|
||||
|
||||
const BoundingBoxf3 box = bounding_box();
|
||||
m_max_z = box.max.z();
|
||||
m_start_z = m_cut_z;
|
||||
m_drag_pos = m_grabbers[m_hover_id].center;
|
||||
m_drag_center = box.center();
|
||||
m_drag_center.z() = m_cut_z;
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_dragging(const UpdateData &data)
|
||||
{
|
||||
assert(m_hover_id != -1);
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render()
|
||||
{
|
||||
const BoundingBoxf3 box = bounding_box();
|
||||
Vec3d plane_center = box.center();
|
||||
plane_center.z() = m_cut_z;
|
||||
m_max_z = box.max.z();
|
||||
set_cut_z(m_cut_z);
|
||||
|
||||
update_contours();
|
||||
|
||||
const float min_x = box.min.x() - Margin;
|
||||
const float max_x = box.max.x() + Margin;
|
||||
const float min_y = box.min.y() - Margin;
|
||||
const float max_y = box.max.y() + Margin;
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
const Vec3d diff = plane_center - m_old_center;
|
||||
// Z changed when move with cut plane
|
||||
// X and Y changed when move with cutted object
|
||||
bool is_changed = std::abs(diff.x()) > EPSILON ||
|
||||
std::abs(diff.y()) > EPSILON ||
|
||||
std::abs(diff.z()) > EPSILON;
|
||||
m_old_center = plane_center;
|
||||
|
||||
if (!m_plane.is_initialized() || is_changed) {
|
||||
m_plane.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.color = { 0.8f, 0.8f, 0.8f, 0.5f };
|
||||
init_data.reserve_vertices(4);
|
||||
init_data.reserve_indices(6);
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(min_x, min_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(max_x, min_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(max_x, max_y, plane_center.z()));
|
||||
init_data.add_vertex(Vec3f(min_x, max_y, plane_center.z()));
|
||||
|
||||
// indices
|
||||
init_data.add_triangle(0, 1, 2);
|
||||
init_data.add_triangle(2, 3, 0);
|
||||
|
||||
m_plane.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
|
||||
m_plane.render();
|
||||
#else
|
||||
// Draw the cutting plane
|
||||
::glBegin(GL_QUADS);
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, plane_center.z());
|
||||
::glVertex3f(max_x, min_y, plane_center.z());
|
||||
::glVertex3f(max_x, max_y, plane_center.z());
|
||||
::glVertex3f(min_x, max_y, plane_center.z());
|
||||
glsafe(::glEnd());
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
// Draw the grabber and the connecting line
|
||||
m_grabbers[0].center = plane_center;
|
||||
m_grabbers[0].center.z() = plane_center.z() + Offset;
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f));
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (!m_grabber_connection.is_initialized() || is_changed) {
|
||||
m_grabber_connection.reset();
|
||||
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 };
|
||||
init_data.color = ColorRGBA::YELLOW();
|
||||
init_data.reserve_vertices(2);
|
||||
init_data.reserve_indices(2);
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex((Vec3f)plane_center.cast<float>());
|
||||
init_data.add_vertex((Vec3f)m_grabbers[0].center.cast<float>());
|
||||
|
||||
// indices
|
||||
init_data.add_line(0, 1);
|
||||
|
||||
m_grabber_connection.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
m_grabber_connection.render();
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
#else
|
||||
glsafe(::glColor3f(1.0, 1.0, 0.0));
|
||||
::glBegin(GL_LINES);
|
||||
::glVertex3dv(plane_center.data());
|
||||
::glVertex3dv(m_grabbers[0].center.data());
|
||||
glsafe(::glEnd());
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
|
||||
m_grabbers[0].color = GRABBER_COLOR;
|
||||
m_grabbers[0].render(m_hover_id == 0, float((box.size().x() + box.size().y() + box.size().z()) / 3.0));
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
shader = wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* Geometry::assemble_transform(m_cut_contours.shift));
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
glsafe(::glLineWidth(2.0f));
|
||||
m_cut_contours.contours.render();
|
||||
#if !ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
glsafe(::glPopMatrix());
|
||||
#endif // !ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
shader->stop_using();
|
||||
}
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_for_picking()
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
static float last_y = 0.0f;
|
||||
static float last_h = 0.0f;
|
||||
|
||||
m_imgui->begin(_L("Cut"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
const bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
|
||||
// adjust window position to avoid overlap the view toolbar
|
||||
const float win_h = ImGui::GetWindowHeight();
|
||||
y = std::min(y, bottom_limit - win_h);
|
||||
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
|
||||
if (last_h != win_h || last_y != y) {
|
||||
// ask canvas for another frame to render the window in the correct position
|
||||
m_imgui->set_requires_extra_frame();
|
||||
if (last_h != win_h)
|
||||
last_h = win_h;
|
||||
if (last_y != y)
|
||||
last_y = y;
|
||||
}
|
||||
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text("Z");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(m_imgui->get_style_scaling() * 150.0f);
|
||||
|
||||
double cut_z = m_cut_z;
|
||||
if (imperial_units)
|
||||
cut_z *= ObjectManipulation::mm_to_in;
|
||||
ImGui::InputDouble("", &cut_z, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags_CharsDecimal);
|
||||
|
||||
ImGui::SameLine();
|
||||
m_imgui->text(imperial_units ? _L("in") : _L("mm"));
|
||||
|
||||
m_cut_z = cut_z * (imperial_units ? ObjectManipulation::in_to_mm : 1.0);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->checkbox(_L("Keep upper part"), m_keep_upper);
|
||||
m_imgui->checkbox(_L("Keep lower part"), m_keep_lower);
|
||||
m_imgui->checkbox(_L("Rotate lower part upwards"), m_rotate_lower);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->disabled_begin((!m_keep_upper && !m_keep_lower) || m_cut_z <= 0.0 || m_max_z <= m_cut_z);
|
||||
const bool cut_clicked = m_imgui->button(_L("Perform cut"));
|
||||
m_imgui->disabled_end();
|
||||
|
||||
m_imgui->end();
|
||||
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower))
|
||||
perform_cut(m_parent.get_selection());
|
||||
}
|
||||
|
||||
void GLGizmoCut::set_cut_z(double cut_z)
|
||||
{
|
||||
// Clamp the plane to the object's bounding box
|
||||
m_cut_z = std::clamp(cut_z, 0.0, m_max_z);
|
||||
}
|
||||
|
||||
void GLGizmoCut::perform_cut(const Selection& selection)
|
||||
{
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
const int object_idx = selection.get_object_idx();
|
||||
|
||||
wxCHECK_RET(instance_idx >= 0 && object_idx >= 0, "GLGizmoCut: Invalid object selection");
|
||||
|
||||
// m_cut_z is the distance from the bed. Subtract possible SLA elevation.
|
||||
const GLVolume* first_glvolume = selection.get_first_volume();
|
||||
const double object_cut_z = m_cut_z - first_glvolume->get_sla_shift_z();
|
||||
|
||||
if (0.0 < object_cut_z && object_cut_z < m_max_z)
|
||||
wxGetApp().plater()->cut(object_idx, instance_idx, object_cut_z,
|
||||
only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) |
|
||||
only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) |
|
||||
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower));
|
||||
else {
|
||||
// the object is SLA-elevated and the plane is under it.
|
||||
}
|
||||
}
|
||||
|
||||
double GLGizmoCut::calc_projection(const Linef3& mouse_ray) const
|
||||
{
|
||||
double projection = 0.0;
|
||||
|
||||
const Vec3d starting_vec = m_drag_pos - m_drag_center;
|
||||
const double len_starting_vec = starting_vec.norm();
|
||||
if (len_starting_vec != 0.0) {
|
||||
const Vec3d mouse_dir = mouse_ray.unit_vector();
|
||||
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
|
||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||
const Vec3d inters = mouse_ray.a + (m_drag_pos - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
||||
// vector from the starting position to the found intersection
|
||||
const Vec3d inters_vec = inters - m_drag_pos;
|
||||
|
||||
// finds projection of the vector along the staring direction
|
||||
projection = inters_vec.dot(starting_vec.normalized());
|
||||
}
|
||||
return projection;
|
||||
}
|
||||
|
||||
BoundingBoxf3 GLGizmoCut::bounding_box() const
|
||||
{
|
||||
BoundingBoxf3 ret;
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
return selection.get_bounding_box();
|
||||
|
||||
for (unsigned int i : idxs) {
|
||||
const GLVolume* volume = selection.get_volume(i);
|
||||
if (!volume->is_modifier)
|
||||
ret.merge(volume->transformed_convex_hull_bounding_box());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLGizmoCut::update_contours()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const GLVolume* first_glvolume = selection.get_first_volume();
|
||||
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
|
||||
|
||||
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
std::vector<ObjectID> volumes_idxs = std::vector<ObjectID>(model_object->volumes.size());
|
||||
for (size_t i = 0; i < model_object->volumes.size(); ++i) {
|
||||
volumes_idxs[i] = model_object->volumes[i]->id();
|
||||
}
|
||||
|
||||
if (0.0 < m_cut_z && m_cut_z < m_max_z) {
|
||||
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() ||
|
||||
m_cut_contours.instance_idx != instance_idx || m_cut_contours.volumes_idxs != volumes_idxs) {
|
||||
m_cut_contours.cut_z = m_cut_z;
|
||||
|
||||
if (m_cut_contours.object_id != model_object->id() || m_cut_contours.volumes_idxs != volumes_idxs)
|
||||
m_cut_contours.mesh = model_object->raw_mesh();
|
||||
|
||||
m_cut_contours.position = box.center();
|
||||
m_cut_contours.shift = Vec3d::Zero();
|
||||
m_cut_contours.object_id = model_object->id();
|
||||
m_cut_contours.instance_idx = instance_idx;
|
||||
m_cut_contours.volumes_idxs = volumes_idxs;
|
||||
m_cut_contours.contours.reset();
|
||||
|
||||
MeshSlicingParams slicing_params;
|
||||
slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
|
||||
slicing_params.trafo.pretranslate(Vec3d(0., 0., first_glvolume->get_sla_shift_z()));
|
||||
|
||||
const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params);
|
||||
if (!polys.empty()) {
|
||||
m_cut_contours.contours.init_from(polys, static_cast<float>(m_cut_z));
|
||||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
m_cut_contours.contours.set_color(ColorRGBA::WHITE());
|
||||
#else
|
||||
m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
}
|
||||
}
|
||||
else if (box.center() != m_cut_contours.position) {
|
||||
m_cut_contours.shift = box.center() - m_cut_contours.position;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_cut_contours.contours.reset();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
@ -118,17 +118,17 @@ void GLGizmoFlatten::on_render()
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
||||
const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() *
|
||||
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
|
||||
Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
|
||||
glsafe(::glMultMatrixd(m.data()));
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
if (this->is_plane_update_necessary())
|
||||
@ -172,17 +172,17 @@ void GLGizmoFlatten::on_render_for_picking()
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
|
||||
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
|
||||
const Transform3d& m = selection.get_first_volume()->get_instance_transformation().get_matrix();
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() *
|
||||
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
|
||||
Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * m;
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#else
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()));
|
||||
glsafe(::glTranslatef(0.f, 0.f, selection.get_first_volume()->get_sla_shift_z()));
|
||||
glsafe(::glMultMatrixd(m.data()));
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
if (this->is_plane_update_necessary())
|
||||
|
@ -94,7 +94,7 @@ void GLGizmoHollow::on_render_for_picking()
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
//#if ENABLE_RENDER_PICKING_PASS
|
||||
// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
|
||||
// m_z_shift = selection.get_first_volume()->get_sla_shift_z();
|
||||
//#endif
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
@ -117,7 +117,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
|
||||
ScopeGuard guard([shader]() { if (shader) shader->stop_using(); });
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* vol = selection.get_first_volume();
|
||||
Geometry::Transformation trafo = vol->get_instance_transformation() * vol->get_volume_transformation();
|
||||
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
@ -242,7 +242,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
|
||||
|
||||
|
@ -97,7 +97,7 @@ void GLGizmoMove3D::on_start_dragging()
|
||||
if (coordinates_type == ECoordinatesType::World)
|
||||
m_starting_drag_position = m_center + m_grabbers[m_hover_id].center;
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
|
||||
#else
|
||||
@ -105,7 +105,7 @@ void GLGizmoMove3D::on_start_dragging()
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
else {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_starting_drag_position = m_center + v.get_instance_transformation().get_rotation_matrix() * m_grabbers[m_hover_id].center;
|
||||
#else
|
||||
@ -315,7 +315,7 @@ void GLGizmoMove3D::on_render()
|
||||
|
||||
#if ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix()* base_matrix);
|
||||
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * base_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
|
||||
@ -359,7 +359,7 @@ void GLGizmoMove3D::on_render()
|
||||
#endif // ENABLE_GL_SHADERS_ATTRIBUTES
|
||||
#else
|
||||
render_grabber_extension((Axis)m_hover_id, box, false);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#endif // !ENABLE_GIZMO_GRABBER_REFACTOR
|
||||
}
|
||||
|
||||
@ -508,7 +508,7 @@ Transform3d GLGizmoMove3D::local_transform(const Selection& selection) const
|
||||
{
|
||||
Transform3d ret = Geometry::assemble_transform(m_center);
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
|
||||
#else
|
||||
@ -530,7 +530,7 @@ void GLGizmoMove3D::transform_to_local(const Selection& selection) const
|
||||
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
|
||||
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
Transform3d orient_matrix = v.get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
||||
orient_matrix = orient_matrix * v.get_volume_transformation().get_matrix(true, false, true, true);
|
||||
@ -548,7 +548,7 @@ void GLGizmoMove3D::calc_selection_box_and_center()
|
||||
m_center = m_bounding_box.center();
|
||||
}
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box = v.transformed_convex_hull_bounding_box(
|
||||
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
|
||||
@ -565,11 +565,12 @@ void GLGizmoMove3D::calc_selection_box_and_center()
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
|
||||
}
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_scaling_factor_matrix());
|
||||
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix_no_scaling_factor() * m_bounding_box.center();
|
||||
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
|
||||
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
|
||||
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
|
||||
#else
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
m_center = selection.get_first_volume()->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
m_center = m_bounding_box.center();
|
||||
}
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box = v.transformed_convex_hull_bounding_box(
|
||||
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix());
|
||||
@ -318,11 +318,12 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix()));
|
||||
}
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_scaling_factor_matrix());
|
||||
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix_no_scaling_factor() * m_bounding_box.center();
|
||||
const Geometry::Transformation inst_trafo = selection.get_first_volume()->get_instance_transformation();
|
||||
m_bounding_box = m_bounding_box.transformed(inst_trafo.get_scaling_factor_matrix());
|
||||
m_center = inst_trafo.get_matrix_no_scaling_factor() * m_bounding_box.center();
|
||||
#else
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
m_center = selection.get_volume(*ids.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
m_center = selection.get_first_volume()->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
|
||||
@ -339,7 +340,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
#else
|
||||
else if (coordinates_type == ECoordinatesType::Local && selection.is_single_volume_or_modifier()) {
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix() * v.get_volume_transformation().get_rotation_matrix();
|
||||
#else
|
||||
@ -347,7 +348,7 @@ void GLGizmoRotate::init_data_from_selection(const Selection& selection)
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
else {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_orient_matrix = v.get_instance_transformation().get_rotation_matrix();
|
||||
#else
|
||||
@ -789,7 +790,7 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
|
||||
return Geometry::assemble_transform(m_center) * m_orient_matrix * ret;
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
|
||||
ret = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true) * ret;
|
||||
ret = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true) * ret;
|
||||
|
||||
return Geometry::assemble_transform(m_center) * ret;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
@ -803,7 +804,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const
|
||||
glsafe(::glMultMatrixd(m_orient_matrix.data()));
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) {
|
||||
const Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
const Transform3d orient_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
@ -864,7 +865,7 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
|
||||
m = m * m_orient_matrix.inverse();
|
||||
#else
|
||||
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes())
|
||||
m = m * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true).inverse();
|
||||
m = m * selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true).inverse();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
m.translate(-m_center);
|
||||
|
@ -45,13 +45,13 @@ std::string GLGizmoScale3D::get_tooltip() const
|
||||
|
||||
Vec3d scale = 100.0 * Vec3d::Ones();
|
||||
if (selection.is_single_full_instance())
|
||||
scale = 100.0 * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor();
|
||||
scale = 100.0 * selection.get_first_volume()->get_instance_scaling_factor();
|
||||
#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
|
||||
scale = 100.0 * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor();
|
||||
scale = 100.0 * selection.get_first_volume()->get_volume_scaling_factor();
|
||||
|
||||
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
|
||||
return "X: " + format(scale.x(), 4) + "%";
|
||||
@ -99,16 +99,14 @@ void GLGizmoScale3D::data_changed()
|
||||
if (enable_scale_xyz) {
|
||||
// all volumes in the selection belongs to the same instance, any of
|
||||
// them contains the needed data, so we take the first
|
||||
const GLVolume *volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
if (selection.is_single_full_instance()) {
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
if (selection.is_single_full_instance())
|
||||
set_scale(volume->get_instance_scaling_factor());
|
||||
} else if (selection.is_single_volume() ||
|
||||
selection.is_single_modifier()) {
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
set_scale(volume->get_volume_scaling_factor());
|
||||
}
|
||||
} else {
|
||||
set_scale(Vec3d::Ones());
|
||||
}
|
||||
else
|
||||
set_scale(Vec3d::Ones());
|
||||
}
|
||||
|
||||
bool GLGizmoScale3D::on_init()
|
||||
@ -220,14 +218,14 @@ void GLGizmoScale3D::on_render()
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*idxs.begin())->get_instance_transformation().get_scaling_factor_matrix());
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_scaling_factor_matrix());
|
||||
#else
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
m_bounding_box = m_bounding_box.transformed(selection.get_first_volume()->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// gets transform from first selected volume
|
||||
const GLVolume& v = *selection.get_volume(*idxs.begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
const Transform3d inst_trafo = v.get_instance_transformation().get_matrix_no_scaling_factor();
|
||||
@ -235,7 +233,7 @@ void GLGizmoScale3D::on_render()
|
||||
m_center = inst_trafo * m_bounding_box.center();
|
||||
#else
|
||||
m_grabbers_transform = v.get_instance_transformation().get_matrix(false, false, true) * Geometry::assemble_transform(m_bounding_box.center());
|
||||
m_center = selection.get_volume(*idxs.begin())->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
m_center = selection.get_first_volume()->get_instance_transformation().get_matrix(false, false, true, false) * m_bounding_box.center();
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_instance_center = v.get_instance_offset();
|
||||
}
|
||||
@ -251,7 +249,7 @@ void GLGizmoScale3D::on_render()
|
||||
}
|
||||
else if (selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
|
||||
@ -267,7 +265,7 @@ void GLGizmoScale3D::on_render()
|
||||
m_instance_center = m_center;
|
||||
}
|
||||
else if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
m_bounding_box.merge(v.transformed_convex_hull_bounding_box(
|
||||
v.get_instance_transformation().get_scaling_factor_matrix() * v.get_volume_transformation().get_scaling_factor_matrix()));
|
||||
@ -285,7 +283,7 @@ void GLGizmoScale3D::on_render()
|
||||
m_bounding_box = selection.get_bounding_box();
|
||||
m_grabbers_transform = Geometry::assemble_transform(m_bounding_box.center());
|
||||
m_center = m_bounding_box.center();
|
||||
m_instance_center = selection.is_single_full_instance() ? selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_offset() : m_center;
|
||||
m_instance_center = selection.is_single_full_instance() ? selection.get_first_volume()->get_instance_offset() : m_center;
|
||||
}
|
||||
#else
|
||||
m_bounding_box = v.bounding_box();
|
||||
@ -668,13 +666,13 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
const ECoordinatesType coordinates_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
if (selection.is_single_full_instance()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation());
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation());
|
||||
curr_scale = (m * curr_scale).cwiseAbs();
|
||||
starting_scale = (m * starting_scale).cwiseAbs();
|
||||
}
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation());
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation());
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation());
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_volume_rotation());
|
||||
const Transform3d m = mi * mv;
|
||||
curr_scale = (m * curr_scale).cwiseAbs();
|
||||
starting_scale = (m * starting_scale).cwiseAbs();
|
||||
@ -685,10 +683,10 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
|
||||
if (coordinates_type == ECoordinatesType::World) {
|
||||
if (selection.is_single_full_instance())
|
||||
m_scale = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse() * curr_scale).cwiseAbs();
|
||||
m_scale = (Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse() * curr_scale).cwiseAbs();
|
||||
else if (selection.is_single_volume_or_modifier()) {
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_rotation()).inverse();
|
||||
const Transform3d mi = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse();
|
||||
const Transform3d mv = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_volume_rotation()).inverse();
|
||||
m_scale = (mv * mi * curr_scale).cwiseAbs();
|
||||
}
|
||||
else
|
||||
@ -714,7 +712,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d center_offset = m_starting.instance_center - m_starting.center;
|
||||
if (selection.is_single_full_instance() && coordinates_type != ECoordinatesType::World) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse();
|
||||
center_offset = m * center_offset;
|
||||
}
|
||||
|
||||
@ -763,7 +761,7 @@ void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
|
||||
Vec3d center_offset = m_starting.instance_center - m_starting.center;
|
||||
|
||||
if (selection.is_single_full_instance() && !wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_rotation()).inverse();
|
||||
const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), selection.get_first_volume()->get_instance_rotation()).inverse();
|
||||
center_offset = m * center_offset;
|
||||
}
|
||||
|
||||
@ -816,7 +814,7 @@ Transform3d GLGizmoScale3D::local_transform(const Selection& selection) const
|
||||
{
|
||||
Transform3d ret = Geometry::assemble_transform(m_center);
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
const GLVolume& v = *selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume& v = *selection.get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
Transform3d orient_matrix = v.get_instance_transformation().get_rotation_matrix();
|
||||
#else
|
||||
@ -838,9 +836,9 @@ void GLGizmoScale3D::transform_to_local(const Selection& selection) const
|
||||
glsafe(::glTranslated(m_center.x(), m_center.y(), m_center.z()));
|
||||
|
||||
if (!wxGetApp().obj_manipul()->is_world_coordinates()) {
|
||||
Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
Transform3d orient_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (selection.is_single_volume_or_modifier() && wxGetApp().obj_manipul()->is_local_coordinates())
|
||||
orient_matrix = orient_matrix * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
orient_matrix = orient_matrix * selection.get_first_volume()->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
});
|
||||
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
|
||||
const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* vol = selection.get_first_volume();
|
||||
Geometry::Transformation transformation(vol->get_instance_transformation().get_matrix() * vol->get_volume_transformation().get_matrix());
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
|
||||
@ -361,7 +361,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2930,7 +2930,7 @@ int Plater::priv::get_selected_volume_idx() const
|
||||
if ((0 > idx) || (idx > 1000))
|
||||
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
|
||||
return-1;
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
if (model.objects[idx]->volumes.size() > 1)
|
||||
return v->volume_idx();
|
||||
return -1;
|
||||
@ -3533,7 +3533,7 @@ void Plater::priv::replace_with_stl()
|
||||
if (selection.is_wipe_tower() || get_selection().get_volume_idxs().size() != 1)
|
||||
return;
|
||||
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* v = selection.get_first_volume();
|
||||
int object_idx = v->object_idx();
|
||||
int volume_idx = v->volume_idx();
|
||||
|
||||
@ -6052,7 +6052,7 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
|
||||
if (selection.get_mode() == Selection::Instance)
|
||||
mesh = mesh_to_export(*model_object, (selection.is_single_full_object() && model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
|
||||
else {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const GLVolume* volume = selection.get_first_volume();
|
||||
mesh = model_object->volumes[volume->volume_idx()]->mesh();
|
||||
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
|
||||
}
|
||||
|
@ -35,25 +35,25 @@ static const Slic3r::ColorRGBA TRANSPARENT_PLANE_COLOR = { 0.8f, 0.8f, 0.8f, 0.5
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
Selection::VolumeCache::TransformCache::TransformCache(const Geometry::Transformation& transform)
|
||||
: position(transform.get_offset())
|
||||
, rotation(transform.get_rotation())
|
||||
, scaling_factor(transform.get_scaling_factor())
|
||||
, mirror(transform.get_mirror())
|
||||
, full_matrix(transform.get_matrix())
|
||||
Selection::VolumeCache::TransformCache::TransformCache(const Geometry::Transformation& transform)
|
||||
: position(transform.get_offset())
|
||||
, rotation(transform.get_rotation())
|
||||
, scaling_factor(transform.get_scaling_factor())
|
||||
, mirror(transform.get_mirror())
|
||||
, full_matrix(transform.get_matrix())
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
, transform(transform)
|
||||
, rotation_matrix(transform.get_rotation_matrix())
|
||||
, scale_matrix(transform.get_scaling_factor_matrix())
|
||||
, mirror_matrix(transform.get_mirror_matrix())
|
||||
, transform(transform)
|
||||
, rotation_matrix(transform.get_rotation_matrix())
|
||||
, scale_matrix(transform.get_scaling_factor_matrix())
|
||||
, mirror_matrix(transform.get_mirror_matrix())
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
{
|
||||
{
|
||||
#if !ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
||||
mirror_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d::Ones(), mirror);
|
||||
rotation_matrix = Geometry::assemble_transform(Vec3d::Zero(), rotation);
|
||||
scale_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scaling_factor);
|
||||
mirror_matrix = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d::Ones(), mirror);
|
||||
#endif // !ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
}
|
||||
|
||||
Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform)
|
||||
: m_volume(volume_transform)
|
||||
@ -612,14 +612,14 @@ bool Selection::requires_uniform_scale() const
|
||||
ECoordinatesType coord_type = wxGetApp().obj_manipul()->get_coordinates_type();
|
||||
if (is_single_volume_or_modifier()) {
|
||||
if (coord_type == ECoordinatesType::World) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(Geometry::Transformation(get_volume(*m_list.begin())->world_matrix()).get_rotation())) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(Geometry::Transformation(get_first_volume()->world_matrix()).get_rotation())) {
|
||||
if (reason != nullptr)
|
||||
*reason = EUniformScaleRequiredReason::VolumeNotAxisAligned_World;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (coord_type == ECoordinatesType::Instance) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(get_volume(*m_list.begin())->get_volume_rotation())) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(get_first_volume()->get_volume_rotation())) {
|
||||
if (reason != nullptr)
|
||||
*reason = EUniformScaleRequiredReason::VolumeNotAxisAligned_Instance;
|
||||
return true;
|
||||
@ -629,7 +629,7 @@ bool Selection::requires_uniform_scale() const
|
||||
}
|
||||
else if (is_single_full_instance()) {
|
||||
if (coord_type == ECoordinatesType::World) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(get_volume(*m_list.begin())->get_instance_rotation())) {
|
||||
if (!Geometry::is_rotation_ninety_degrees(get_first_volume()->get_instance_rotation())) {
|
||||
if (reason != nullptr)
|
||||
*reason = EUniformScaleRequiredReason::InstanceNotAxisAligned_World;
|
||||
return true;
|
||||
@ -1478,7 +1478,7 @@ int Selection::bake_transform_if_needed() const
|
||||
(is_single_volume_or_modifier() && !wxGetApp().obj_manipul()->is_local_coordinates())) {
|
||||
// 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 = *get_volume(*get_volume_idxs().begin());
|
||||
const GLVolume& volume = *get_first_volume();
|
||||
bool needs_baking = false;
|
||||
if (is_single_full_instance()) {
|
||||
// Is the instance angle close to a multiple of 90 degrees?
|
||||
@ -1646,13 +1646,14 @@ void Selection::render(float scale_factor)
|
||||
trafo = Transform3d::Identity();
|
||||
}
|
||||
else if (coordinates_type == ECoordinatesType::Local && is_single_volume_or_modifier()) {
|
||||
const GLVolume& v = *get_volume(*get_volume_idxs().begin());
|
||||
const GLVolume& v = *get_first_volume();
|
||||
#if ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
box = v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_scaling_factor_matrix());
|
||||
trafo = v.get_instance_transformation().get_matrix() * v.get_volume_transformation().get_matrix_no_scaling_factor();
|
||||
const Geometry::Transformation inst_trafo = get_first_volume()->get_instance_transformation();
|
||||
box = box.transformed(inst_trafo.get_scaling_factor_matrix());
|
||||
trafo = inst_trafo.get_matrix_no_scaling_factor();
|
||||
#else
|
||||
box = v.transformed_convex_hull_bounding_box(v.get_instance_transformation().get_matrix(true, true, false, true) * v.get_volume_transformation().get_matrix(true, true, false, true));
|
||||
trafo = v.get_instance_transformation().get_matrix(false, false, true, false) * v.get_volume_transformation().get_matrix(false, false, true, false);
|
||||
box = box.transformed(get_first_volume()->get_instance_transformation().get_matrix(true, true, false, true));
|
||||
trafo = get_first_volume()->get_instance_transformation().get_matrix(false, false, true, false);
|
||||
#endif // ENABLE_TRANSFORMATIONS_BY_MATRICES
|
||||
}
|
||||
else {
|
||||
|
@ -351,6 +351,7 @@ public:
|
||||
|
||||
const IndicesList& get_volume_idxs() const { return m_list; }
|
||||
const GLVolume* get_volume(unsigned int volume_idx) const;
|
||||
const GLVolume* get_first_volume() const { return get_volume(*m_list.begin()); }
|
||||
|
||||
const ObjectIdxsToInstanceIdxsMap& get_content() const { return m_cache.content; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user