enricoturri1966 2023-10-21 12:06:59 +08:00 committed by Noisyfox
parent f6a3421e2a
commit 7e04448b7a
23 changed files with 742 additions and 449 deletions

View file

@ -326,40 +326,36 @@ Vec3d extract_euler_angles(const Eigen::Matrix<double, 3, 3, Eigen::DontAlign>&
Vec3d angles1 = Vec3d::Zero();
Vec3d angles2 = Vec3d::Zero();
// BBS: rotation_matrix(2, 0) may be slighterly larger than 1 due to numerical accuracy
if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1)
{
angles1(2) = 0.0;
if (rotation_matrix(2, 0) < 0.0) // == -1.0
{
angles1(1) = 0.5 * (double)PI;
angles1(0) = angles1(2) + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2));
if (std::abs(std::abs(rotation_matrix(2, 0)) - 1.0) < 1e-5 || std::abs(rotation_matrix(2, 0))>1) {
angles1.z() = 0.0;
if (rotation_matrix(2, 0) < 0.0) { // == -1.0
angles1.y() = 0.5 * double(PI);
angles1.x() = angles1.z() + ::atan2(rotation_matrix(0, 1), rotation_matrix(0, 2));
}
else // == 1.0
{
angles1(1) = - 0.5 * (double)PI;
angles1(0) = - angles1(2) + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2));
else { // == 1.0
angles1.y() = - 0.5 * double(PI);
angles1.x() = - angles1.y() + ::atan2(- rotation_matrix(0, 1), - rotation_matrix(0, 2));
}
angles2 = angles1;
}
else
{
angles1(1) = -::asin(rotation_matrix(2, 0));
double inv_cos1 = 1.0 / ::cos(angles1(1));
angles1(0) = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1);
angles1(2) = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1);
else {
angles1.y() = -::asin(rotation_matrix(2, 0));
const double inv_cos1 = 1.0 / ::cos(angles1.y());
angles1.x() = ::atan2(rotation_matrix(2, 1) * inv_cos1, rotation_matrix(2, 2) * inv_cos1);
angles1.z() = ::atan2(rotation_matrix(1, 0) * inv_cos1, rotation_matrix(0, 0) * inv_cos1);
angles2(1) = (double)PI - angles1(1);
double inv_cos2 = 1.0 / ::cos(angles2(1));
angles2(0) = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2);
angles2(2) = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2);
angles2.y() = double(PI) - angles1.y();
const double inv_cos2 = 1.0 / ::cos(angles2.y());
angles2.x() = ::atan2(rotation_matrix(2, 1) * inv_cos2, rotation_matrix(2, 2) * inv_cos2);
angles2.z() = ::atan2(rotation_matrix(1, 0) * inv_cos2, rotation_matrix(0, 0) * inv_cos2);
}
// The following euristic is the best found up to now (in the sense that it works fine with the greatest number of edge use-cases)
// but there are other use-cases were it does not
// We need to improve it
double min_1 = angles1.cwiseAbs().minCoeff();
double min_2 = angles2.cwiseAbs().minCoeff();
bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm()));
const double min_1 = angles1.cwiseAbs().minCoeff();
const double min_2 = angles2.cwiseAbs().minCoeff();
const bool use_1 = (min_1 < min_2) || (is_approx(min_1, min_2) && (angles1.norm() <= angles2.norm()));
return use_1 ? angles1 : angles2;
}
@ -423,14 +419,6 @@ Transform3d rotation_transform(const Vec3d& rotation)
return transform;
}
Transformation::Flags::Flags()
: dont_translate(true)
, dont_rotate(true)
, dont_scale(true)
, dont_mirror(true)
{
}
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
@ -456,15 +444,14 @@ Transformation::Transformation(const Transform3d& transform)
void Transformation::set_offset(const Vec3d& offset)
{
set_offset(X, offset(0));
set_offset(Y, offset(1));
set_offset(Z, offset(2));
set_offset(X, offset.x());
set_offset(Y, offset.y());
set_offset(Z, offset.z());
}
void Transformation::set_offset(Axis axis, double offset)
{
if (m_offset(axis) != offset)
{
if (m_offset(axis) != offset) {
m_offset(axis) = offset;
m_dirty = true;
}
@ -472,19 +459,18 @@ void Transformation::set_offset(Axis axis, double offset)
void Transformation::set_rotation(const Vec3d& rotation)
{
set_rotation(X, rotation(0));
set_rotation(Y, rotation(1));
set_rotation(Z, rotation(2));
set_rotation(X, rotation.x());
set_rotation(Y, rotation.y());
set_rotation(Z, rotation.z());
}
void Transformation::set_rotation(Axis axis, double rotation)
{
rotation = angle_to_0_2PI(rotation);
if (is_approx(std::abs(rotation), 2.0 * (double)PI))
if (is_approx(std::abs(rotation), 2.0 * double(PI)))
rotation = 0.0;
if (m_rotation(axis) != rotation)
{
if (m_rotation(axis) != rotation) {
m_rotation(axis) = rotation;
m_dirty = true;
}
@ -492,15 +478,14 @@ void Transformation::set_rotation(Axis axis, double rotation)
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
{
set_scaling_factor(X, scaling_factor(0));
set_scaling_factor(Y, scaling_factor(1));
set_scaling_factor(Z, scaling_factor(2));
set_scaling_factor(X, scaling_factor.x());
set_scaling_factor(Y, scaling_factor.y());
set_scaling_factor(Z, scaling_factor.z());
}
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
{
if (m_scaling_factor(axis) != std::abs(scaling_factor))
{
if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
m_scaling_factor(axis) = std::abs(scaling_factor);
m_dirty = true;
}
@ -508,9 +493,9 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
void Transformation::set_mirror(const Vec3d& mirror)
{
set_mirror(X, mirror(0));
set_mirror(Y, mirror(1));
set_mirror(Z, mirror(2));
set_mirror(X, mirror.x());
set_mirror(Y, mirror.y());
set_mirror(Z, mirror.z());
}
void Transformation::set_mirror(Axis axis, double mirror)
@ -521,8 +506,7 @@ void Transformation::set_mirror(Axis axis, double mirror)
else if (abs_mirror != 1.0)
mirror /= abs_mirror;
if (m_mirror(axis) != mirror)
{
if (m_mirror(axis) != mirror) {
m_mirror(axis) = mirror;
m_dirty = true;
}
@ -540,9 +524,8 @@ void Transformation::set_from_transform(const Transform3d& transform)
// we can only detect if the matrix contains a left handed reference system
// in which case we reorient it back to right handed by mirroring the x axis
Vec3d mirror = Vec3d::Ones();
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0)
{
mirror(0) = -1.0;
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) {
mirror.x() = -1.0;
// remove mirror
m3x3.col(0) *= -1.0;
}
@ -579,8 +562,7 @@ void Transformation::reset()
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
{
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror))
{
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
m_matrix = Geometry::assemble_transform(
dont_translate ? Vec3d::Zero() : m_offset,
dont_rotate ? Vec3d::Zero() : m_rotation,
@ -609,8 +591,7 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
// Just set the inverse.
out.set_from_transform(instance_transformation.get_matrix(true).inverse());
}
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation()))
{
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) {
// Anisotropic scaling, rotation by multiples of ninety degrees.
Eigen::Matrix3d instance_rotation_trafo =
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) *
@ -643,8 +624,8 @@ Transformation Transformation::volume_to_bed_transformation(const Transformation
scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i));
out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo));
out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2))));
out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1));
out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
}
else
{
@ -663,19 +644,15 @@ Transform3d transform3d_from_string(const std::string& transform_str)
assert(is_decimal_separator_point()); // for atof
Transform3d transform = Transform3d::Identity();
if (!transform_str.empty())
{
if (!transform_str.empty()) {
std::vector<std::string> mat_elements_str;
boost::split(mat_elements_str, transform_str, boost::is_any_of(" "), boost::token_compress_on);
unsigned int size = (unsigned int)mat_elements_str.size();
if (size == 16)
{
const unsigned int size = (unsigned int)mat_elements_str.size();
if (size == 16) {
unsigned int i = 0;
for (unsigned int r = 0; r < 4; ++r)
{
for (unsigned int c = 0; c < 4; ++c)
{
for (unsigned int r = 0; r < 4; ++r) {
for (unsigned int c = 0; c < 4; ++c) {
transform(r, c) = ::atof(mat_elements_str[i++].c_str());
}
}
@ -689,17 +666,17 @@ Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot
{
return
// From the current coordinate system to world.
Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) *
Eigen::AngleAxisd(rot_xyz_to.z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to.x(), Vec3d::UnitX()) *
// From world to the initial coordinate system.
Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ());
Eigen::AngleAxisd(-rot_xyz_from.x(), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from.y(), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from.z(), Vec3d::UnitZ());
}
// This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
Vec3d axis = angle_axis.axis();
double angle = angle_axis.angle();
const Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to));
const Vec3d axis = angle_axis.axis();
const double angle = angle_axis.angle();
#ifndef NDEBUG
if (std::abs(angle) > 1e-8) {
assert(std::abs(axis.x()) < 1e-8);

View file

@ -361,25 +361,23 @@ class Transformation
{
struct Flags
{
bool dont_translate;
bool dont_rotate;
bool dont_scale;
bool dont_mirror;
Flags();
bool dont_translate{ true };
bool dont_rotate{ true };
bool dont_scale{ true };
bool dont_mirror{ true };
bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const;
void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror);
};
Vec3d m_offset; // In unscaled coordinates
Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point
Vec3d m_scaling_factor; // Scaling factors along the three axes
Vec3d m_mirror; // Mirroring along the three axes
Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates
Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point
Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes
Vec3d m_mirror{ Vec3d::Ones() }; // Mirroring along the three axes
mutable Transform3d m_matrix;
mutable Transform3d m_matrix{ Transform3d::Identity() };
mutable Flags m_flags;
mutable bool m_dirty;
mutable bool m_dirty{ false };
public:
Transformation();
@ -457,7 +455,7 @@ extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to
// Is the angle close to a multiple of 90 degrees?
inline bool is_rotation_ninety_degrees(double a)
{
a = fmod(std::abs(a), 0.5 * M_PI);
a = fmod(std::abs(a), 0.5 * PI);
if (a > 0.25 * PI)
a = 0.5 * PI - a;
return a < 0.001;

View file

@ -462,19 +462,62 @@ void GLCanvas3D::LayersEditing::render_curve(const Rect & bar_rect)
const float scale_y = bar_rect.get_height() / m_object_max_z;
const float x = bar_rect.get_left() + float(m_slicing_parameters->layer_height) * scale_x;
// Baseline
glsafe(::glColor3f(0.0f, 0.0f, 0.0f));
::glBegin(GL_LINE_STRIP);
::glVertex2f(x, bar_rect.get_bottom());
::glVertex2f(x, bar_rect.get_top());
glsafe(::glEnd());
bool bar_rect_changed = m_profile.old_bar_rect != bar_rect;
m_profile.old_bar_rect = bar_rect;
// Curve
glsafe(::glColor3f(0.0f, 0.0f, 1.0f));
::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2)
::glVertex2f(bar_rect.get_left() + (float)m_layer_height_profile[i + 1] * scale_x, bar_rect.get_bottom() + (float)m_layer_height_profile[i] * scale_y);
glsafe(::glEnd());
// Baseline
if (!m_profile.baseline.is_initialized() || bar_rect_changed) {
m_profile.old_bar_rect = bar_rect;
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
entity.positions.emplace_back(x, bar_rect.get_bottom(), 0.0f);
entity.positions.emplace_back(x, bar_rect.get_top(), 0.0f);
entity.normals.reserve(2);
for (size_t j = 0; j < 2; ++j) {
entity.normals.emplace_back(Vec3f::UnitZ());
}
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_profile.baseline.init_from(init_data);
m_profile.baseline.set_color(-1, ColorRGBA::BLACK());
}
if (!m_profile.profile.is_initialized() || bar_rect_changed || m_profile.old_layer_height_profile != m_layer_height_profile) {
m_profile.old_layer_height_profile = m_layer_height_profile;
m_profile.profile.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::LineStrip;
entity.positions.reserve(m_layer_height_profile.size());
entity.normals.reserve(m_layer_height_profile.size());
entity.indices.reserve(m_layer_height_profile.size());
for (unsigned int i = 0; i < unsigned int(m_layer_height_profile.size()); i += 2) {
entity.positions.emplace_back(bar_rect.get_left() + float(m_layer_height_profile[i + 1]) * scale_x, bar_rect.get_bottom() + float(m_layer_height_profile[i]) * scale_y, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i / 2);
}
init_data.entities.emplace_back(entity);
m_profile.profile.init_from(init_data);
m_profile.profile.set_color(-1, ColorRGBA::BLUE());
}
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
m_profile.baseline.render();
m_profile.profile.render();
shader->stop_using();
}
}
void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D & canvas, const GLVolumeCollection & volumes)//render volume and layer height texture (has mapping relation with each other)
@ -6822,7 +6865,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
default:
case GLVolumeCollection::ERenderType::Opaque:
{
const GLGizmosManager& gm = get_gizmos_manager();
GLGizmosManager& gm = get_gizmos_manager();
if (dynamic_cast<GLGizmoPainterBase*>(gm.get_current()) == nullptr)
{
if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
@ -8070,28 +8113,59 @@ void GLCanvas3D::_render_assemble_info() const
}
#if ENABLE_SHOW_CAMERA_TARGET
void GLCanvas3D::_render_camera_target() const
void GLCanvas3D::_render_camera_target()
{
double half_length = 5.0;
static const double half_length = 5.0;
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glLineWidth(2.0f));
::glBegin(GL_LINES);
const Vec3d& target = wxGetApp().plater()->get_camera().get_target();
// draw line for x axis
::glColor3f(1.0f, 0.0f, 0.0f);
::glVertex3d(target(0) - half_length, target(1), target(2));
::glVertex3d(target(0) + half_length, target(1), target(2));
// draw line for y axis
::glColor3f(0.0f, 1.0f, 0.0f);
::glVertex3d(target(0), target(1) - half_length, target(2));
::glVertex3d(target(0), target(1) + half_length, target(2));
// draw line for z axis
::glColor3f(0.0f, 0.0f, 1.0f);
::glVertex3d(target(0), target(1), target(2) - half_length);
::glVertex3d(target(0), target(1), target(2) + half_length);
glsafe(::glEnd());
bool target_changed = !m_camera_target.target.isApprox(target);
m_camera_target.target = target;
for (int i = 0; i < 3; ++i) {
if (!m_camera_target.axis[i].is_initialized() || target_changed) {
m_camera_target.axis[i].reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
if (i == X) {
entity.positions.emplace_back(target.x() - half_length, target.y(), target.z());
entity.positions.emplace_back(target.x() + half_length, target.y(), target.z());
}
else if (i == Y) {
entity.positions.emplace_back(target.x(), target.y() - half_length, target.z());
entity.positions.emplace_back(target.x(), target.y() + half_length, target.z());
}
else {
entity.positions.emplace_back(target.x(), target.y(), target.z() - half_length);
entity.positions.emplace_back(target.x(), target.y(), target.z() + half_length);
}
entity.normals.reserve(2);
for (size_t j = 0; j < 2; ++j) {
entity.normals.emplace_back(Vec3f::UnitZ());
}
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_camera_target.axis[i].init_from(init_data);
m_camera_target.axis[i].set_color(-1, (i == X) ? ColorRGBA::X() : (i == Y) ? ColorRGBA::Y() : ColorRGBA::Z());
}
}
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
for (int i = 0; i < 3; ++i) {
m_camera_target.axis[i].render();
}
shader->stop_using();
}
}
#endif // ENABLE_SHOW_CAMERA_TARGET

View file

@ -257,6 +257,14 @@ class GLCanvas3D
int last_object_id{ -1 };
float last_z{ 0.0f };
LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE };
struct Profile
{
GLModel baseline;
GLModel profile;
Rect old_bar_rect;
std::vector<double> old_layer_height_profile;
};
Profile m_profile;
LayersEditing() = default;
~LayersEditing();
@ -698,6 +706,15 @@ public:
}
m_gizmo_highlighter;
#if ENABLE_SHOW_CAMERA_TARGET
struct CameraTarget
{
std::array<GLModel, 3> axis;
Vec3d target{ Vec3d::Zero() };
};
CameraTarget m_camera_target;
#endif // ENABLE_SHOW_CAMERA_TARGET
public:
explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed);
~GLCanvas3D();
@ -1139,7 +1156,7 @@ private:
void _render_assemble_control() const;
void _render_assemble_info() const;
#if ENABLE_SHOW_CAMERA_TARGET
void _render_camera_target() const;
void _render_camera_target();
#endif // ENABLE_SHOW_CAMERA_TARGET
void _render_sla_slices();
void _render_selection_sidebar_hints();

View file

@ -69,7 +69,7 @@ namespace GUI {
m_state = Off;
}
void GLSelectionRectangle::render(const GLCanvas3D& canvas) const
void GLSelectionRectangle::render(const GLCanvas3D& canvas)
{
if (!is_dragging())
return;
@ -92,11 +92,6 @@ namespace GUI {
float bottom = (float)std::min(start(1), end(1)) * inv_zoom;
glsafe(::glLineWidth(1.5f));
float color[3];
color[0] = 0.00f;
color[1] = 1.00f;
color[2] = 0.38f;
glsafe(::glColor3fv(color));
glsafe(::glDisable(GL_DEPTH_TEST));
@ -112,12 +107,46 @@ namespace GUI {
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
::glBegin(GL_LINE_LOOP);
::glVertex2f((GLfloat)left, (GLfloat)bottom);
::glVertex2f((GLfloat)right, (GLfloat)bottom);
::glVertex2f((GLfloat)right, (GLfloat)top);
::glVertex2f((GLfloat)left, (GLfloat)top);
glsafe(::glEnd());
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
if (!m_rectangle.is_initialized() || !m_old_start_corner.isApprox(m_start_corner) || !m_old_end_corner.isApprox(m_end_corner)) {
m_old_start_corner = m_start_corner;
m_old_end_corner = m_end_corner;
m_rectangle.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::LineLoop;
entity.positions.reserve(4);
entity.positions.emplace_back(left, bottom, 0.0f);
entity.positions.emplace_back(right, bottom, 0.0f);
entity.positions.emplace_back(right, top, 0.0f);
entity.positions.emplace_back(left, top, 0.0f);
entity.normals.reserve(4);
for (size_t j = 0; j < 5; ++j) {
entity.normals.emplace_back(Vec3f::UnitZ());
}
entity.indices.reserve(6);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
entity.indices.emplace_back(2);
entity.indices.emplace_back(2);
entity.indices.emplace_back(3);
entity.indices.emplace_back(0);
init_data.entities.emplace_back(entity);
m_rectangle.init_from(init_data);
}
ColorRGBA color(0.0f, 1.0f, 0.38f, 1.0f);
m_rectangle.set_color(-1, color);
m_rectangle.render();
shader->stop_using();
}
glsafe(::glPopAttrib());

View file

@ -2,6 +2,7 @@
#define slic3r_GLSelectionRectangle_hpp_
#include "libslic3r/Point.hpp"
#include "GLModel.hpp"
namespace Slic3r {
namespace GUI {
@ -30,7 +31,7 @@ public:
// Disables the rectangle.
void stop_dragging();
void render(const GLCanvas3D& canvas) const;
void render(const GLCanvas3D& canvas);
bool is_dragging() const { return m_state != Off; }
EState get_state() const { return m_state; }
@ -43,9 +44,12 @@ public:
float get_bottom() const { return std::min(m_start_corner(1), m_end_corner(1)); }
private:
EState m_state = Off;
Vec2d m_start_corner;
Vec2d m_end_corner;
EState m_state{ Off };
Vec2d m_start_corner{ Vec2d::Zero() };
Vec2d m_end_corner{ Vec2d::Zero() };
GLModel m_rectangle;
Vec2d m_old_start_corner{ Vec2d::Zero() };
Vec2d m_old_end_corner{ Vec2d::Zero() };
};

View file

@ -33,7 +33,8 @@ std::pair<bool, std::string> GLShadersManager::init()
bool valid = true;
// basic shader, used to render selection bbox
// basic shader, used to render selection bbox, gizmo cut plane and grabbers connections,
// gizmo move grabbers connections, gizmo scale grabbers connections
valid &= append_shader("flat", { "flat.vs", "flat.fs" });
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });

View file

@ -105,7 +105,7 @@ bool GLGizmoFdmSupports::on_init()
return true;
}
void GLGizmoFdmSupports::render_painter_gizmo() const
void GLGizmoFdmSupports::render_painter_gizmo()
{
const Selection& selection = m_parent.get_selection();

View file

@ -15,7 +15,7 @@ class GLGizmoFdmSupports : public GLGizmoPainterBase
public:
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
void render_painter_gizmo() const override;
void render_painter_gizmo() override;
//BBS: add edit state
enum EditState {

View file

@ -146,7 +146,7 @@ GLGizmoMmuSegmentation::GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::st
{
}
void GLGizmoMmuSegmentation::render_painter_gizmo() const
void GLGizmoMmuSegmentation::render_painter_gizmo()
{
const Selection& selection = m_parent.get_selection();

View file

@ -67,7 +67,7 @@ public:
GLGizmoMmuSegmentation(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoMmuSegmentation() override = default;
void render_painter_gizmo() const override;
void render_painter_gizmo() override;
void set_painter_gizmo_data(const Selection& selection) override;

View file

@ -23,11 +23,6 @@ const double GLGizmoMove3D::Offset = 10.0;
//BBS: GUI refactor: add obj manipulation
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_displacement(Vec3d::Zero())
, m_snap_step(1.0)
, m_starting_drag_position(Vec3d::Zero())
, m_starting_box_center(Vec3d::Zero())
, m_starting_box_bottom_center(Vec3d::Zero())
//BBS: GUI refactor: add obj manipulation
, m_object_manipulation(obj_manipulation)
{
@ -137,25 +132,57 @@ void GLGizmoMove3D::on_render()
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
// draw grabbers
for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled) render_grabber_extension((Axis) i, box, false);
auto render_grabber_connection = [this, &center](unsigned int id) {
if (m_grabbers[id].enabled) {
if (!m_grabber_connections[id].model.is_initialized() || !m_grabber_connections[id].old_center.isApprox(center)) {
m_grabber_connections[id].old_center = center;
m_grabber_connections[id].model.reset();
GLModel::InitializationData init_data;
GUI::GLModel::InitializationData::Entity entity;
entity.type = GUI::GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
entity.positions.emplace_back(center.cast<float>());
entity.positions.emplace_back(m_grabbers[id].center.cast<float>());
entity.normals.reserve(2);
for (size_t j = 0; j < 2; ++j) {
entity.normals.emplace_back(Vec3f::UnitZ());
}
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_grabber_connections[id].model.init_from(init_data);
m_grabber_connections[id].model.set_color(-1, AXES_COLOR[id]);
}
glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE);
m_grabber_connections[id].model.render();
glDisable(GL_LINE_STIPPLE);
}
};
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
// draw axes line
// draw axes
for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled) {
glsafe(::glColor4fv(AXES_COLOR[i].data()));
glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE);
::glBegin(GL_LINES);
::glVertex3dv(center.data());
// use extension center
::glVertex3dv(m_grabbers[i].center.data());
glsafe(::glEnd());
glDisable(GL_LINE_STIPPLE);
render_grabber_connection(i);
}
shader->stop_using();
}
// draw grabbers
for (unsigned int i = 0; i < 3; ++i) {
if (m_grabbers[i].enabled)
render_grabber_extension((Axis) i, box, false);
}
}

View file

@ -15,15 +15,19 @@ class GLGizmoMove3D : public GLGizmoBase
{
static const double Offset;
Vec3d m_displacement;
double m_snap_step;
Vec3d m_starting_drag_position;
Vec3d m_starting_box_center;
Vec3d m_starting_box_bottom_center;
Vec3d m_displacement{ Vec3d::Zero() };
double m_snap_step{ 1.0 };
Vec3d m_starting_drag_position{ Vec3d::Zero() };
Vec3d m_starting_box_center{ Vec3d::Zero() };
Vec3d m_starting_box_bottom_center{ Vec3d::Zero() };
GLModel m_vbo_cone;
struct GrabberConnection
{
GLModel model;
Vec3d old_center{ Vec3d::Zero() };
};
std::array<GrabberConnection, 3> m_grabber_connections;
//BBS: add size adjust related
GizmoObjectManipulation* m_object_manipulation;

View file

@ -119,7 +119,7 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
}
void GLGizmoPainterBase::render_cursor() const
void GLGizmoPainterBase::render_cursor()
{
// First check that the mouse pointer is on an object.
const ModelObject* mo = m_c->selection_info()->model_object();
@ -159,31 +159,22 @@ void GLGizmoPainterBase::render_cursor() const
void GLGizmoPainterBase::render_cursor_circle() const
void GLGizmoPainterBase::render_cursor_circle()
{
const Camera &camera = wxGetApp().plater()->get_camera();
auto zoom = (float) camera.get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
const float zoom = float(camera.get_zoom());
const float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
Size cnv_size = m_parent.get_canvas_size();
float cnv_half_width = 0.5f * (float) cnv_size.get_width();
float cnv_half_height = 0.5f * (float) cnv_size.get_height();
if ((cnv_half_width == 0.0f) || (cnv_half_height == 0.0f))
const Size cnv_size = m_parent.get_canvas_size();
const float cnv_half_width = 0.5f * float(cnv_size.get_width());
const float cnv_half_height = 0.5f * float(cnv_size.get_height());
if (cnv_half_width == 0.0f || cnv_half_height == 0.0f)
return;
Vec2d mouse_pos(m_parent.get_local_mouse_position()(0), m_parent.get_local_mouse_position()(1));
Vec2d center(mouse_pos(0) - cnv_half_width, cnv_half_height - mouse_pos(1));
const Vec2d mouse_pos(m_parent.get_local_mouse_position().x(), m_parent.get_local_mouse_position().y());
Vec2d center(mouse_pos.x() - cnv_half_width, cnv_half_height - mouse_pos.y());
center = center * inv_zoom;
glsafe(::glLineWidth(1.5f));
// BBS
ColorRGBA render_color = this->get_cursor_hover_color();
if (m_button_down == Button::Left)
render_color = this->get_cursor_sphere_left_button_color();
else if (m_button_down == Button::Right)
render_color = this->get_cursor_sphere_right_button_color();
glsafe(::glColor4fv(render_color.data()));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glPushMatrix());
@ -191,17 +182,46 @@ void GLGizmoPainterBase::render_cursor_circle() const
// ensure that the circle is renderered inside the frustrum
glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.5)));
// ensure that the overlay fits the frustrum near z plane
double gui_scale = camera.get_gui_scale();
const double gui_scale = camera.get_gui_scale();
glsafe(::glScaled(gui_scale, gui_scale, 1.0));
glsafe(::glPushAttrib(GL_ENABLE_BIT));
glsafe(::glLineStipple(4, 0xAAAA));
glsafe(::glEnable(GL_LINE_STIPPLE));
::glBegin(GL_LINE_LOOP);
for (double angle=0; angle<2*M_PI; angle+=M_PI/20.)
::glVertex2f(GLfloat(center.x()+m_cursor_radius*cos(angle)), GLfloat(center.y()+m_cursor_radius*sin(angle)));
glsafe(::glEnd());
if (!m_circle.is_initialized() || !m_old_center.isApprox(center) || std::abs(m_old_cursor_radius - m_cursor_radius) > EPSILON) {
m_old_center = center;
m_old_cursor_radius = m_cursor_radius;
m_circle.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::LineLoop;
static const unsigned int StepsCount = 32;
static const float StepSize = 2.0f * float(PI) / float(StepsCount);
entity.positions.reserve(StepsCount);
entity.normals.reserve(StepsCount);
entity.indices.reserve(StepsCount);
for (unsigned int i = 0; i < StepsCount; ++i) {
const float angle = float(i * StepSize);
entity.positions.emplace_back(center.x() + ::cos(angle) * m_cursor_radius, center.y() + ::sin(angle) * m_cursor_radius, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i);
}
init_data.entities.emplace_back(entity);
m_circle.init_from(init_data);
}
// BBS
ColorRGBA render_color = this->get_cursor_hover_color();
if (m_button_down == Button::Left)
render_color = this->get_cursor_sphere_left_button_color();
else if (m_button_down == Button::Right)
render_color = this->get_cursor_sphere_right_button_color();
m_circle.set_color(-1, render_color);
m_circle.render();
glsafe(::glPopAttrib());
glsafe(::glPopMatrix());

View file

@ -225,7 +225,7 @@ public:
// from usual on_render method allows to render them before transparent
// objects, so they can be seen inside them. The usual on_render is called
// after all volumes (including transparent ones) are rendered.
virtual void render_painter_gizmo() const = 0;
virtual void render_painter_gizmo() = 0;
virtual const float get_cursor_radius_min() const { return CursorRadiusMin; }
virtual const float get_cursor_radius_max() const { return CursorRadiusMax; }
@ -238,8 +238,8 @@ public:
protected:
virtual void render_triangles(const Selection& selection) const;
void render_cursor() const;
void render_cursor_circle() const;
void render_cursor();
void render_cursor_circle();
void render_cursor_sphere(const Transform3d& trafo) const;
// BBS
void render_cursor_height_range(const Transform3d& trafo) const;
@ -300,6 +300,9 @@ protected:
bool m_paint_on_overhangs_only = false;
float m_highlight_by_angle_threshold_deg = 0.f;
GLModel m_circle;
Vec2d m_old_center{ Vec2d::Zero() };
float m_old_cursor_radius{ 0.0f };
static constexpr float SmartFillAngleMin = 0.0f;
static constexpr float SmartFillAngleMax = 90.f;
static constexpr float SmartFillAngleStep = 1.f;

View file

@ -17,10 +17,9 @@ namespace GUI {
const float GLGizmoRotate::Offset = 5.0f;
const unsigned int GLGizmoRotate::CircleResolution = 64;
const unsigned int GLGizmoRotate::AngleResolution = 64;
const unsigned int GLGizmoRotate::ScaleStepsCount = 72;
const float GLGizmoRotate::ScaleStepRad = 2.0f * (float)PI / GLGizmoRotate::ScaleStepsCount;
const float GLGizmoRotate::ScaleStepRad = 2.0f * float(PI) / GLGizmoRotate::ScaleStepsCount;
const unsigned int GLGizmoRotate::ScaleLongEvery = 2;
const float GLGizmoRotate::ScaleLongTooth = 0.1f; // in percent of radius
const unsigned int GLGizmoRotate::SnapRegionsCount = 8;
@ -30,15 +29,7 @@ const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius
GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
: GLGizmoBase(parent, "", -1)
, m_axis(axis)
, m_angle(0.0)
, m_center(0.0, 0.0, 0.0)
, m_radius(0.0f)
, m_snap_coarse_in_radius(0.0f)
, m_snap_coarse_out_radius(0.0f)
, m_snap_fine_in_radius(0.0f)
, m_snap_fine_out_radius(0.0f)
{
}
{}
GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
: GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id)
@ -56,7 +47,7 @@ GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
void GLGizmoRotate::set_angle(double angle)
{
if (std::abs(angle - 2.0 * (double)PI) < EPSILON)
if (std::abs(angle - 2.0 * double(PI)) < EPSILON)
angle = 0.0;
m_angle = angle;
@ -71,7 +62,7 @@ std::string GLGizmoRotate::get_tooltip() const
case Y: { axis = "Y"; break; }
case Z: { axis = "Z"; break; }
}
return (m_hover_id == 0 || m_grabbers[0].dragging) ? axis + ": " + format((float)Geometry::rad2deg(m_angle), 2) : "";
return (m_hover_id == 0 || m_grabbers.front().dragging) ? axis + ": " + format(float(Geometry::rad2deg(m_angle)), 2) : "";
}
bool GLGizmoRotate::on_init()
@ -94,34 +85,31 @@ void GLGizmoRotate::on_start_dragging()
void GLGizmoRotate::on_update(const UpdateData& data)
{
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
const Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
Vec2d orig_dir = Vec2d::UnitX();
Vec2d new_dir = mouse_pos.normalized();
const Vec2d orig_dir = Vec2d::UnitX();
const Vec2d new_dir = mouse_pos.normalized();
double theta = ::acos(std::clamp(new_dir.dot(orig_dir), -1.0, 1.0));
if (cross2(orig_dir, new_dir) < 0.0)
theta = 2.0 * (double)PI - theta;
double len = mouse_pos.norm();
const double len = mouse_pos.norm();
// snap to coarse snap region
if ((m_snap_coarse_in_radius <= len) && (len <= m_snap_coarse_out_radius))
{
double step = 2.0 * (double)PI / (double)SnapRegionsCount;
theta = step * (double)std::round(theta / step);
if (m_snap_coarse_in_radius <= len && len <= m_snap_coarse_out_radius) {
const double step = 2.0 * double(PI) / double(SnapRegionsCount);
theta = step * std::round(theta / step);
}
else
{
else {
// snap to fine snap region (scale)
if ((m_snap_fine_in_radius <= len) && (len <= m_snap_fine_out_radius))
{
double step = 2.0 * (double)PI / (double)ScaleStepsCount;
theta = step * (double)std::round(theta / step);
if (m_snap_fine_in_radius <= len && len <= m_snap_fine_out_radius) {
const double step = 2.0 * double(PI) / double(ScaleStepsCount);
theta = step * std::round(theta / step);
}
}
if (theta == 2.0 * (double)PI)
if (theta == 2.0 * double(PI))
theta = 0.0;
m_angle = theta;
@ -129,13 +117,13 @@ void GLGizmoRotate::on_update(const UpdateData& data)
void GLGizmoRotate::on_render()
{
if (!m_grabbers[0].enabled)
if (!m_grabbers.front().enabled)
return;
const Selection& selection = m_parent.get_selection();
const BoundingBoxf3& box = selection.get_bounding_box();
if (m_hover_id != 0 && !m_grabbers[0].dragging) {
if (m_hover_id != 0 && !m_grabbers.front().dragging) {
m_center = m_custom_center == Vec3d::Zero() ? box.center() : m_custom_center;
m_radius = Offset + box.radius();
m_snap_coarse_in_radius = m_radius / 3.0f;
@ -144,26 +132,41 @@ void GLGizmoRotate::on_render()
m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth);
}
const double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
m_grabbers.front().center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
m_grabbers.front().angles.z() = m_angle;
m_grabbers.front().color = AXES_COLOR[m_axis];
m_grabbers.front().hover_color = AXES_HOVER_COLOR[m_axis];
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glPushMatrix());
transform_to_local(selection);
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data()));
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
render_circle();
const float radius = Offset + m_parent.get_selection().get_bounding_box().radius();
const bool radius_changed = std::abs(m_old_radius - radius) > EPSILON;
m_old_radius = radius;
ColorRGBA color((m_hover_id != -1) ? m_drag_color : m_highlight_color);
render_circle(color, radius_changed);
if (m_hover_id != -1) {
render_scale();
render_snap_radii();
render_reference_radius();
const bool hover_radius_changed = std::abs(m_old_hover_radius - radius) > EPSILON;
m_old_hover_radius = radius;
render_scale(color, hover_radius_changed);
render_snap_radii(color, hover_radius_changed);
render_reference_radius(color, hover_radius_changed);
render_angle_arc(m_highlight_color, hover_radius_changed);
}
glsafe(::glColor4fv(m_highlight_color.data()));
if (m_hover_id != -1)
render_angle();
render_grabber_connection(color, radius_changed);
shader->stop_using();
}
render_grabber(box);
render_grabber_extension(box, false);
@ -220,138 +223,223 @@ void GLGizmoRotate3D::load_rotoptimize_state()
}
}
void GLGizmoRotate::render_circle() const
void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed)
{
::glBegin(GL_LINE_LOOP);
for (unsigned int i = 0; i < ScaleStepsCount; ++i)
{
float angle = (float)i * ScaleStepRad;
float x = ::cos(angle) * m_radius;
float y = ::sin(angle) * m_radius;
float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
if (!m_circle.is_initialized() || radius_changed) {
m_circle.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::LineLoop;
entity.positions.reserve(ScaleStepsCount);
entity.normals.reserve(ScaleStepsCount);
entity.indices.reserve(ScaleStepsCount);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
const float angle = float(i * ScaleStepRad);
entity.positions.emplace_back(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i);
}
glsafe(::glEnd());
init_data.entities.emplace_back(entity);
m_circle.init_from(init_data);
}
m_circle.set_color(-1, color);
m_circle.render();
}
void GLGizmoRotate::render_scale() const
void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed)
{
float out_radius_long = m_snap_fine_out_radius;
float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth);
const float out_radius_long = m_snap_fine_out_radius;
const float out_radius_short = m_radius * (1.0f + 0.5f * ScaleLongTooth);
::glBegin(GL_LINES);
for (unsigned int i = 0; i < ScaleStepsCount; ++i)
{
float angle = (float)i * ScaleStepRad;
float cosa = ::cos(angle);
float sina = ::sin(angle);
float in_x = cosa * m_radius;
float in_y = sina * m_radius;
float in_z = 0.0f;
float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short;
float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short;
float out_z = 0.0f;
::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z);
::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z);
if (!m_scale.is_initialized() || radius_changed) {
m_scale.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2 * ScaleStepsCount);
entity.normals.reserve(2 * ScaleStepsCount);
entity.indices.reserve(2 * ScaleStepsCount);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
const float angle = float(i * ScaleStepRad);
const float cosa = ::cos(angle);
const float sina = ::sin(angle);
const float in_x = cosa * m_radius;
const float in_y = sina * m_radius;
const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short;
const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short;
entity.positions.emplace_back(in_x, in_y, 0.0f);
entity.positions.emplace_back(out_x, out_y, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i * 2 + 0);
entity.indices.emplace_back(i * 2 + 1);
}
glsafe(::glEnd());
init_data.entities.emplace_back(entity);
m_scale.init_from(init_data);
}
void GLGizmoRotate::render_snap_radii() const
{
float step = 2.0f * (float)PI / (float)SnapRegionsCount;
float in_radius = m_radius / 3.0f;
float out_radius = 2.0f * in_radius;
::glBegin(GL_LINES);
for (unsigned int i = 0; i < SnapRegionsCount; ++i)
{
float angle = (float)i * step;
float cosa = ::cos(angle);
float sina = ::sin(angle);
float in_x = cosa * in_radius;
float in_y = sina * in_radius;
float in_z = 0.0f;
float out_x = cosa * out_radius;
float out_y = sina * out_radius;
float out_z = 0.0f;
::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z);
::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z);
}
glsafe(::glEnd());
m_scale.set_color(-1, color);
m_scale.render();
}
void GLGizmoRotate::render_reference_radius() const
void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_changed)
{
::glBegin(GL_LINES);
::glVertex3f(0.0f, 0.0f, 0.0f);
::glVertex3f((GLfloat)(m_radius * (1.0f + GrabberOffset)), 0.0f, 0.0f);
glsafe(::glEnd());
const float step = 2.0f * float(PI) / float(SnapRegionsCount);
const float in_radius = m_radius / 3.0f;
const float out_radius = 2.0f * in_radius;
if (!m_snap_radii.is_initialized() || radius_changed) {
m_snap_radii.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2 * ScaleStepsCount);
entity.normals.reserve(2 * ScaleStepsCount);
entity.indices.reserve(2 * ScaleStepsCount);
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
const float angle = float(i * step);
const float cosa = ::cos(angle);
const float sina = ::sin(angle);
const float in_x = cosa * in_radius;
const float in_y = sina * in_radius;
const float out_x = cosa * out_radius;
const float out_y = sina * out_radius;
entity.positions.emplace_back(in_x, in_y, 0.0f);
entity.positions.emplace_back(out_x, out_y, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i * 2 + 0);
entity.indices.emplace_back(i * 2 + 1);
}
init_data.entities.emplace_back(entity);
m_snap_radii.init_from(init_data);
}
m_snap_radii.set_color(-1, color);
m_snap_radii.render();
}
void GLGizmoRotate::render_angle() const
void GLGizmoRotate::render_reference_radius(const ColorRGBA& color, bool radius_changed)
{
float step_angle = (float)m_angle / AngleResolution;
float ex_radius = m_radius * (1.0f + GrabberOffset);
if (!m_reference_radius.is_initialized() || radius_changed) {
m_reference_radius.reset();
::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i <= AngleResolution; ++i)
{
float angle = (float)i * step_angle;
float x = ::cos(angle) * ex_radius;
float y = ::sin(angle) * ex_radius;
float z = 0.0f;
::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z);
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
entity.positions.emplace_back(0.0f, 0.0f, 0.0f);
entity.positions.emplace_back(m_radius * (1.0f + GrabberOffset), 0.0f, 0.0f);
entity.normals.reserve(2);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_reference_radius.init_from(init_data);
}
glsafe(::glEnd());
m_reference_radius.set_color(-1, color);
m_reference_radius.render();
}
void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed)
{
const float step_angle = float(m_angle) / float(AngleResolution);
const float ex_radius = m_radius * (1.0f + GrabberOffset);
if (!m_angle_arc.is_initialized() || radius_changed) {
m_angle_arc.reset();
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::LineStrip;
entity.positions.reserve(1 + AngleResolution);
entity.normals.reserve(1 + AngleResolution);
entity.indices.reserve(1 + AngleResolution);
for (unsigned int i = 0; i <= AngleResolution; ++i) {
const float angle = float(i) * step_angle;
entity.positions.emplace_back(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.emplace_back(i);
}
init_data.entities.emplace_back(entity);
m_angle_arc.init_from(init_data);
}
m_angle_arc.set_color(-1, color);
m_angle_arc.render();
}
void GLGizmoRotate::render_grabber_connection(const ColorRGBA& color, bool radius_changed)
{
if (!m_grabber_connection.model.is_initialized() || radius_changed || !m_grabber_connection.old_center.isApprox(m_grabbers.front().center)) {
m_grabber_connection.model.reset();
m_grabber_connection.old_center = m_grabbers.front().center;
GLModel::InitializationData init_data;
GLModel::InitializationData::Entity entity;
entity.type = GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
entity.positions.emplace_back(0.0f, 0.0f, 0.0f);
entity.positions.emplace_back(m_grabbers.front().center.cast<float>());
entity.normals.reserve(2);
entity.normals.emplace_back(Vec3f::UnitZ());
entity.normals.emplace_back(Vec3f::UnitZ());
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_grabber_connection.model.init_from(init_data);
}
m_grabber_connection.model.set_color(-1, color);
m_grabber_connection.model.render();
}
void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
{
double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset);
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
m_grabbers[0].angles(2) = m_angle;
m_grabbers[0].color = AXES_COLOR[m_axis];
m_grabbers[0].hover_color = AXES_HOVER_COLOR[m_axis];
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color.data() : m_highlight_color.data()));
::glBegin(GL_LINES);
::glVertex3f(0.0f, 0.0f, 0.0f);
::glVertex3dv(m_grabbers[0].center.data());
glsafe(::glEnd());
m_grabbers[0].color = m_highlight_color;
m_grabbers.front().color = m_highlight_color;
render_grabbers(box);
}
void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking) const
void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool picking)
{
double size = 0.75 * GLGizmoBase::Grabber::FixedGrabberSize * GLGizmoBase::INV_ZOOM;
//float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
//double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size);
ColorRGBA color = m_grabbers[0].color;
if (!picking && m_hover_id != -1) {
color = m_grabbers[0].hover_color;
//color[0] = 1.0f - color[0];
//color[1] = 1.0f - color[1];
//color[2] = 1.0f - color[2];
}
ColorRGBA color = m_grabbers.front().color;
if (!picking && m_hover_id != -1)
color = m_grabbers.front().hover_color;
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
const_cast<GLModel*>(&m_cone)->set_color(-1, color);
m_cone.set_color(-1, color);
if (!picking) {
shader->start_using();
shader->set_uniform("emission_factor", 0.1f);
}
const Vec3d& center = m_grabbers.front().center;
glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z()));
glsafe(::glTranslated(center.x(), center.y(), center.z()));
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 1.5 * size));
@ -359,7 +447,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
m_cone.render();
glsafe(::glPopMatrix());
glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[0].center.x(), m_grabbers[0].center.y(), m_grabbers[0].center.z()));
glsafe(::glTranslated(center.x(), center.y(), center.z()));
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0));
glsafe(::glTranslated(0.0, 0.0, 1.5 * size));
@ -376,7 +464,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const
glsafe(::glTranslated(m_center(0), m_center(1), m_center(2)));
if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) {
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_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
@ -405,7 +493,7 @@ void GLGizmoRotate::transform_to_local(const Selection& selection) const
Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const
{
double half_pi = 0.5 * (double)PI;
double half_pi = 0.5 * double(PI);
Transform3d m = Transform3d::Identity();
@ -486,13 +574,13 @@ bool GLGizmoRotate3D::on_is_activable() const
void GLGizmoRotate3D::on_start_dragging()
{
if ((0 <= m_hover_id) && (m_hover_id < 3))
if (0 <= m_hover_id && m_hover_id < 3)
m_gizmos[m_hover_id].start_dragging();
}
void GLGizmoRotate3D::on_stop_dragging()
{
if ((0 <= m_hover_id) && (m_hover_id < 3))
if (0 <= m_hover_id && m_hover_id < 3)
m_gizmos[m_hover_id].stop_dragging();
}

View file

@ -13,7 +13,6 @@ namespace GUI {
class GLGizmoRotate : public GLGizmoBase
{
static const float Offset;
static const unsigned int CircleResolution;
static const unsigned int AngleResolution;
static const unsigned int ScaleStepsCount;
static const float ScaleStepRad;
@ -32,18 +31,29 @@ public:
private:
Axis m_axis;
double m_angle;
mutable Vec3d m_custom_center{Vec3d::Zero()};
mutable Vec3d m_center;
mutable float m_radius;
mutable float m_snap_coarse_in_radius;
mutable float m_snap_coarse_out_radius;
mutable float m_snap_fine_in_radius;
mutable float m_snap_fine_out_radius;
double m_angle{ 0.0 };
Vec3d m_custom_center{Vec3d::Zero()};
Vec3d m_center{ Vec3d::Zero() };
float m_radius{ 0.0f };
float m_snap_coarse_in_radius{ 0.0f };
float m_snap_coarse_out_radius{ 0.0f };
float m_snap_fine_in_radius{ 0.0f };
float m_snap_fine_out_radius{ 0.0f };
GLModel m_cone;
GLModel m_circle;
GLModel m_scale;
GLModel m_snap_radii;
GLModel m_reference_radius;
GLModel m_angle_arc;
struct GrabberConnection
{
GLModel model;
Vec3d old_center{ Vec3d::Zero() };
};
GrabberConnection m_grabber_connection;
float m_old_radius{ 0.0f };
float m_old_hover_radius{ 0.0f };
public:
GLGizmoRotate(GLCanvas3D& parent, Axis axis);
@ -66,13 +76,14 @@ protected:
void on_render_for_picking() override;
private:
void render_circle() const;
void render_scale() const;
void render_snap_radii() const;
void render_reference_radius() const;
void render_angle() const;
void render_circle(const ColorRGBA& color, bool radius_changed);
void render_scale(const ColorRGBA& color, bool radius_changed);
void render_snap_radii(const ColorRGBA& color, bool radius_changed);
void render_reference_radius(const ColorRGBA& color, bool radius_changed);
void render_angle_arc(const ColorRGBA& color, bool radius_changed);
void render_grabber_connection(const ColorRGBA& color, bool radius_changed);
void render_grabber(const BoundingBoxf3& box) const;
void render_grabber_extension(const BoundingBoxf3& box, bool picking) const;
void render_grabber_extension(const BoundingBoxf3& box, bool picking);
void transform_to_local(const Selection& selection) const;
// returns the intersection of the mouse ray with the plane perpendicular to the gizmo axis, in local coordinate
@ -96,8 +107,7 @@ public:
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
std::string get_tooltip() const override
{
std::string get_tooltip() const override {
std::string tooltip = m_gizmos[X].get_tooltip();
if (tooltip.empty())
tooltip = m_gizmos[Y].get_tooltip();
@ -116,38 +126,32 @@ public:
protected:
bool on_init() override;
std::string on_get_name() const override;
void on_set_state() override
{
void on_set_state() override {
for (GLGizmoRotate& g : m_gizmos)
g.set_state(m_state);
}
void on_set_hover_id() override
{
void on_set_hover_id() override {
for (int i = 0; i < 3; ++i)
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
}
void on_enable_grabber(unsigned int id) override
{
void on_enable_grabber(unsigned int id) override {
if (id < 3)
m_gizmos[id].enable_grabber(0);
}
void on_disable_grabber(unsigned int id) override
{
void on_disable_grabber(unsigned int id) override {
if (id < 3)
m_gizmos[id].disable_grabber(0);
}
bool on_is_activable() const override;
void on_start_dragging() override;
void on_stop_dragging() override;
void on_update(const UpdateData& data) override
{
void on_update(const UpdateData& data) override {
for (GLGizmoRotate& g : m_gizmos) {
g.update(data);
}
}
void on_render() override;
void on_render_for_picking() override
{
void on_render_for_picking() override {
for (GLGizmoRotate& g : m_gizmos) {
g.render_for_picking();
}
@ -157,10 +161,11 @@ protected:
private:
class RotoptimzeWindow {
class RotoptimzeWindow
{
ImGuiWrapper *m_imgui = nullptr;
public:
public:
struct State {
float accuracy = 1.f;
int method_id = 0;

View file

@ -24,12 +24,16 @@ Vec3d GetIntersectionOfRayAndPlane(Vec3d ray_position, Vec3d ray_dir, Vec3d plan
//BBS: GUI refactor: add obj manipulation
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_scale(Vec3d::Ones())
, m_offset(Vec3d::Zero())
, m_snap_step(0.05)
//BBS: GUI refactor: add obj manipulation
, m_object_manipulation(obj_manipulation)
{
m_grabber_connections[0].grabber_indices = { 0, 1 };
m_grabber_connections[1].grabber_indices = { 2, 3 };
m_grabber_connections[2].grabber_indices = { 4, 5 };
m_grabber_connections[3].grabber_indices = { 6, 7 };
m_grabber_connections[4].grabber_indices = { 7, 8 };
m_grabber_connections[5].grabber_indices = { 8, 9 };
m_grabber_connections[6].grabber_indices = { 9, 6 };
}
std::string GLGizmoScale3D::get_tooltip() const
@ -46,17 +50,17 @@ std::string GLGizmoScale3D::get_tooltip() const
scale = 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_volume_scaling_factor().cast<float>();
if (m_hover_id == 0 || m_hover_id == 1 || m_grabbers[0].dragging || m_grabbers[1].dragging)
return "X: " + format(scale(0), 4) + "%";
return "X: " + format(scale.x(), 4) + "%";
else if (m_hover_id == 2 || m_hover_id == 3 || m_grabbers[2].dragging || m_grabbers[3].dragging)
return "Y: " + format(scale(1), 4) + "%";
return "Y: " + format(scale.y(), 4) + "%";
else if (m_hover_id == 4 || m_hover_id == 5 || m_grabbers[4].dragging || m_grabbers[5].dragging)
return "Z: " + format(scale(2), 4) + "%";
return "Z: " + format(scale.z(), 4) + "%";
else if (m_hover_id == 6 || m_hover_id == 7 || m_hover_id == 8 || m_hover_id == 9 ||
m_grabbers[6].dragging || m_grabbers[7].dragging || m_grabbers[8].dragging || m_grabbers[9].dragging)
{
std::string tooltip = "X: " + format(scale(0), 2) + "%\n";
tooltip += "Y: " + format(scale(1), 2) + "%\n";
tooltip += "Z: " + format(scale(2), 2) + "%";
std::string tooltip = "X: " + format(scale.x(), 2) + "%\n";
tooltip += "Y: " + format(scale.y(), 2) + "%\n";
tooltip += "Z: " + format(scale.z(), 2) + "%";
return tooltip;
}
else
@ -71,8 +75,7 @@ void GLGizmoScale3D::enable_ununiversal_scale(bool enable)
bool GLGizmoScale3D::on_init()
{
for (int i = 0; i < 10; ++i)
{
for (int i = 0; i < 10; ++i) {
m_grabbers.push_back(Grabber());
}
@ -106,8 +109,7 @@ bool GLGizmoScale3D::on_is_activable() const
void GLGizmoScale3D::on_start_dragging()
{
if (m_hover_id != -1)
{
if (m_hover_id != -1) {
m_starting.drag_position = m_grabbers[m_hover_id].center;
m_starting.plane_center = m_grabbers[4].center;
m_starting.plane_nromal = m_grabbers[5].center - m_grabbers[4].center;
@ -115,22 +117,22 @@ void GLGizmoScale3D::on_start_dragging()
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
const Vec3d& center = m_starting.box.center();
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2));
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min(0), center(1), center(2));
m_starting.pivots[2] = m_transform * Vec3d(center(0), m_starting.box.max(1), center(2));
m_starting.pivots[3] = m_transform * Vec3d(center(0), m_starting.box.min(1), center(2));
m_starting.pivots[4] = m_transform * Vec3d(center(0), center(1), m_starting.box.max(2));
m_starting.pivots[5] = m_transform * Vec3d(center(0), center(1), m_starting.box.min(2));
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max.x(), center.y(), center.z());
m_starting.pivots[1] = m_transform * Vec3d(m_starting.box.min.x(), center.y(), center.z());
m_starting.pivots[2] = m_transform * Vec3d(center.x(), m_starting.box.max.y(), center.z());
m_starting.pivots[3] = m_transform * Vec3d(center.x(), m_starting.box.min.y(), center.z());
m_starting.pivots[4] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.max.z());
m_starting.pivots[5] = m_transform * Vec3d(center.x(), center.y(), m_starting.box.min.z());
}
}
void GLGizmoScale3D::on_update(const UpdateData& data)
{
if ((m_hover_id == 0) || (m_hover_id == 1))
if (m_hover_id == 0 || m_hover_id == 1)
do_scale_along_axis(X, data);
else if ((m_hover_id == 2) || (m_hover_id == 3))
else if (m_hover_id == 2 || m_hover_id == 3)
do_scale_along_axis(Y, data);
else if ((m_hover_id == 4) || (m_hover_id == 5))
else if (m_hover_id == 4 || m_hover_id == 5)
do_scale_along_axis(Z, data);
else if (m_hover_id >= 6)
do_scale_uniform(data);
@ -190,24 +192,24 @@ void GLGizmoScale3D::on_render()
bool ctrl_down = (m_dragging && m_starting.ctrl_down) || (!m_dragging && wxGetKeyState(WXK_CONTROL));
// x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), m_box.min(2));
m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), m_box.min(2));
m_grabbers[0].center = m_transform * Vec3d(m_box.min.x(), center.y(), m_box.min.z());
m_grabbers[1].center = m_transform * Vec3d(m_box.max.x(), center.y(), m_box.min.z());
// y axis
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), m_box.min(2));
m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), m_box.min(2));
m_grabbers[2].center = m_transform * Vec3d(center.x(), m_box.min.y(), m_box.min.z());
m_grabbers[3].center = m_transform * Vec3d(center.x(), m_box.max.y(), m_box.min.z());
// z axis do not show 4
m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2));
m_grabbers[4].center = m_transform * Vec3d(center.x(), center.y(), m_box.min.z());
m_grabbers[4].enabled = false;
m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2));
m_grabbers[5].center = m_transform * Vec3d(center.x(), center.y(), m_box.max.z());
// uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), m_box.min(2));
m_grabbers[7].center = m_transform * Vec3d(m_box.max(0), m_box.min(1), m_box.min(2));
m_grabbers[8].center = m_transform * Vec3d(m_box.max(0), m_box.max(1), m_box.min(2));
m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), m_box.min(2));
m_grabbers[6].center = m_transform * Vec3d(m_box.min.x(), m_box.min.y(), m_box.min.z());
m_grabbers[7].center = m_transform * Vec3d(m_box.max.x(), m_box.min.y(), m_box.min.z());
m_grabbers[8].center = m_transform * Vec3d(m_box.max.x(), m_box.max.y(), m_box.min.z());
m_grabbers[9].center = m_transform * Vec3d(m_box.min.x(), m_box.max.y(), m_box.min.z());
for (int i = 0; i < 6; ++i) {
m_grabbers[i].color = AXES_COLOR[i/2];
@ -228,26 +230,23 @@ void GLGizmoScale3D::on_render()
const BoundingBoxf3& selection_box = selection.get_bounding_box();
float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0);
float grabber_mean_size = (float)((selection_box.size().x() + selection_box.size().y() + selection_box.size().z()) / 3.0);
//draw connections
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader != nullptr) {
shader->start_using();
// BBS: when select multiple objects, uniform scale can be deselected, display the connection(4,5)
//if (single_instance || single_volume) {
if (m_grabbers[4].enabled && m_grabbers[5].enabled) {
glsafe(::glColor4fv(m_grabbers[4].color.data()));
render_grabbers_connection(4, 5);
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
render_grabbers_connection(4, 5, m_grabbers[4].color);
render_grabbers_connection(6, 7, m_grabbers[2].color);
render_grabbers_connection(7, 8, m_grabbers[2].color);
render_grabbers_connection(8, 9, m_grabbers[0].color);
render_grabbers_connection(9, 6, m_grabbers[0].color);
shader->stop_using();
}
glsafe(::glColor4fv(m_grabbers[2].color.data()));
render_grabbers_connection(6, 7);
render_grabbers_connection(8, 9);
glsafe(::glColor4fv(m_grabbers[0].color.data()));
render_grabbers_connection(7, 8);
render_grabbers_connection(9, 6);
// draw grabbers
render_grabbers(grabber_mean_size);
}
@ -258,19 +257,52 @@ void GLGizmoScale3D::on_render_for_picking()
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
}
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color)
{
unsigned int grabbers_count = (unsigned int)m_grabbers.size();
if ((id_1 < grabbers_count) && (id_2 < grabbers_count))
{
auto grabber_connection = [this](unsigned int id_1, unsigned int id_2) {
for (int i = 0; i < int(m_grabber_connections.size()); ++i) {
if (m_grabber_connections[i].grabber_indices.first == id_1 && m_grabber_connections[i].grabber_indices.second == id_2)
return i;
}
return -1;
};
int id = grabber_connection(id_1, id_2);
if (id == -1)
return;
if (!m_grabber_connections[id].model.is_initialized() ||
!m_grabber_connections[id].old_v1.isApprox(m_grabbers[id_1].center) ||
!m_grabber_connections[id].old_v2.isApprox(m_grabbers[id_2].center)) {
m_grabber_connections[id].old_v1 = m_grabbers[id_1].center;
m_grabber_connections[id].old_v2 = m_grabbers[id_2].center;
m_grabber_connections[id].model.reset();
GLModel::InitializationData init_data;
GUI::GLModel::InitializationData::Entity entity;
entity.type = GUI::GLModel::PrimitiveType::Lines;
entity.positions.reserve(2);
entity.positions.emplace_back(m_grabbers[id_1].center.cast<float>());
entity.positions.emplace_back(m_grabbers[id_2].center.cast<float>());
entity.normals.reserve(2);
for (size_t j = 0; j < 2; ++j) {
entity.normals.emplace_back(Vec3f::UnitZ());
}
entity.indices.reserve(2);
entity.indices.emplace_back(0);
entity.indices.emplace_back(1);
init_data.entities.emplace_back(entity);
m_grabber_connections[id].model.init_from(init_data);
}
m_grabber_connections[id].model.set_color(-1, color);
glLineStipple(1, 0x0FFF);
glEnable(GL_LINE_STIPPLE);
::glBegin(GL_LINES);
::glVertex3dv(m_grabbers[id_1].center.data());
::glVertex3dv(m_grabbers[id_2].center.data());
glsafe(::glEnd());
m_grabber_connections[id].model.render();
glDisable(GL_LINE_STIPPLE);
}
}
//BBS: add input window for move
@ -283,11 +315,9 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit
void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
{
double ratio = calc_ratio(data);
if (ratio > 0.0)
{
if (ratio > 0.0) {
m_scale(axis) = m_starting.scale(axis) * ratio;
if (m_starting.ctrl_down)
{
if (m_starting.ctrl_down) {
double local_offset = 0.5 * (m_scale(axis) - m_starting.scale(axis)) * m_starting.box.size()(axis);
if (m_hover_id == 2 * axis)
local_offset *= -1.0;
@ -311,8 +341,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
{
double ratio = calc_ratio(data);
if (ratio > 0.0)
{
if (ratio > 0.0) {
m_scale = m_starting.scale * ratio;
m_offset = Vec3d::Zero();
}
@ -322,11 +351,11 @@ double GLGizmoScale3D::calc_ratio(const UpdateData& data) const
{
double ratio = 0.0;
Vec3d pivot = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_starting.pivots[m_hover_id] : m_starting.plane_center;
Vec3d pivot = (m_starting.ctrl_down && m_hover_id < 6) ? m_starting.pivots[m_hover_id] : m_starting.plane_center;
Vec3d starting_vec = m_starting.drag_position - pivot;
double len_starting_vec = starting_vec.norm();
if (len_starting_vec != 0.0)
{
if (len_starting_vec != 0.0) {
Vec3d mouse_dir = data.mouse_ray.unit_vector();
Vec3d plane_normal = m_starting.plane_nromal;
if (m_hover_id == 5) {

View file

@ -32,11 +32,20 @@ class GLGizmoScale3D : public GLGizmoBase
mutable Transform3d m_transform;
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
mutable Transform3d m_offsets_transform;
Vec3d m_scale;
Vec3d m_offset;
double m_snap_step;
Vec3d m_scale{ Vec3d::Ones() };
Vec3d m_offset{ Vec3d::Zero() };
double m_snap_step{ 0.05 };
StartingData m_starting;
struct GrabberConnection
{
GLModel model;
std::pair<unsigned int, unsigned int> grabber_indices;
Vec3d old_v1{ Vec3d::Zero() };
Vec3d old_v2{ Vec3d::Zero() };
};
std::array<GrabberConnection, 7> m_grabber_connections;
//BBS: add size adjust related
GizmoObjectManipulation* m_object_manipulation;
@ -68,7 +77,7 @@ protected:
virtual void on_render_input_window(float x, float y, float bottom_limit);
private:
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
void render_grabbers_connection(unsigned int id_1, unsigned int id_2, const ColorRGBA& color);
void do_scale_along_axis(Axis axis, const UpdateData& data);
void do_scale_uniform(const UpdateData& data);

View file

@ -62,7 +62,7 @@ std::string GLGizmoSeam::on_get_name() const
void GLGizmoSeam::render_painter_gizmo() const
void GLGizmoSeam::render_painter_gizmo()
{
const Selection& selection = m_parent.get_selection();

View file

@ -10,7 +10,7 @@ class GLGizmoSeam : public GLGizmoPainterBase
public:
GLGizmoSeam(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
void render_painter_gizmo() const override;
void render_painter_gizmo() override;
//BBS
bool on_key_down_select_tool_type(int keyCode);

View file

@ -692,7 +692,7 @@ void GLGizmosManager::render_current_gizmo() const
m_gizmos[m_current]->render();
}
void GLGizmosManager::render_painter_gizmo() const
void GLGizmosManager::render_painter_gizmo()
{
// This function shall only be called when current gizmo is
// derived from GLGizmoPainterBase.

View file

@ -31,16 +31,24 @@ class CommonGizmosDataPool;
class GizmoObjectManipulation;
class Rect
{
float m_left;
float m_top;
float m_right;
float m_bottom;
float m_left{ 0.0f };
float m_top{ 0.0f };
float m_right{ 0.0f };
float m_bottom{ 0.0f };
public:
Rect() : m_left(0.0f) , m_top(0.0f) , m_right(0.0f) , m_bottom(0.0f) {}
Rect() = default;
Rect(float left, float top, float right, float bottom) : m_left(left) , m_top(top) , m_right(right) , m_bottom(bottom) {}
bool operator == (const Rect& other) {
if (std::abs(m_left - other.m_left) > EPSILON) return false;
if (std::abs(m_top - other.m_top) > EPSILON) return false;
if (std::abs(m_right - other.m_right) > EPSILON) return false;
if (std::abs(m_bottom - other.m_bottom) > EPSILON) return false;
return true;
}
bool operator != (const Rect& other) { return !operator==(other); }
float get_left() const { return m_left; }
void set_left(float left) { m_left = left; }
@ -287,7 +295,7 @@ public:
void on_change_color_mode(bool is_dark);
void render_current_gizmo() const;
void render_current_gizmo_for_picking_pass() const;
void render_painter_gizmo() const;
void render_painter_gizmo();
void render_painter_assemble_view() const;
void render_overlay();