mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 13:45:59 +08:00
calculate angle when set volume
This commit is contained in:
parent
d6b8163975
commit
ead192b43b
@ -1544,7 +1544,7 @@ std::optional<Vec2d> Emboss::ProjectZ::unproject(const Vec3d &p, double *depth)
|
||||
Vec3d Emboss::suggest_up(const Vec3d normal, double up_limit)
|
||||
{
|
||||
// Normal must be 1
|
||||
assert(is_approx(normal.norm(), 1.));
|
||||
assert(is_approx(normal.squaredNorm(), 1.));
|
||||
|
||||
// wanted up direction of result
|
||||
Vec3d wanted_up_side =
|
||||
@ -1560,28 +1560,45 @@ Vec3d Emboss::suggest_up(const Vec3d normal, double up_limit)
|
||||
return wanted_up_dir;
|
||||
}
|
||||
|
||||
std::optional<float> Emboss::calc_up(const Transform3d &tr, double up_limit)
|
||||
{
|
||||
auto tr_linear = tr.linear();
|
||||
// z base of transformation ( tr * UnitZ )
|
||||
Vec3d normal = tr_linear.col(2);
|
||||
// scaled matrix has base with different size
|
||||
normal.normalize();
|
||||
Vec3d suggested = suggest_up(normal);
|
||||
assert(is_approx(suggested.squaredNorm(), 1.));
|
||||
|
||||
Vec3d up = tr_linear.col(1); // tr * UnitY()
|
||||
up.normalize();
|
||||
|
||||
double dot = suggested.dot(up);
|
||||
if (dot >= 1. || dot <= -1.)
|
||||
return {}; // zero angle
|
||||
|
||||
Matrix3d m;
|
||||
m.row(0) = up;
|
||||
m.row(1) = suggested;
|
||||
m.row(2) = normal;
|
||||
double det = m.determinant();
|
||||
|
||||
return atan2(det, dot);
|
||||
}
|
||||
|
||||
Transform3d Emboss::create_transformation_onto_surface(const Vec3d &position,
|
||||
const Vec3d &normal,
|
||||
float up_limit)
|
||||
{
|
||||
// up and emboss direction for generated model
|
||||
Vec3d text_up_dir = Vec3d::UnitY();
|
||||
Vec3d text_emboss_dir = Vec3d::UnitZ();
|
||||
// is normalized ?
|
||||
assert(is_approx(normal.squaredNorm(), 1.));
|
||||
|
||||
// wanted up direction of result
|
||||
Vec3d wanted_up_side = Vec3d::UnitZ();
|
||||
if (std::fabs(normal.z()) > up_limit) wanted_up_side = Vec3d::UnitY();
|
||||
// up and emboss direction for generated model
|
||||
Vec3d up_dir = Vec3d::UnitY();
|
||||
Vec3d emboss_dir = Vec3d::UnitZ();
|
||||
|
||||
// after cast from float it needs to be normalized again
|
||||
assert(is_approx(normal.norm(), 1.));
|
||||
|
||||
// create perpendicular unit vector to surface triangle normal vector
|
||||
// lay on surface of triangle and define up vector for text
|
||||
Vec3d wanted_up_dir = normal
|
||||
.cross(wanted_up_side)
|
||||
.cross(normal);
|
||||
// normal3d is NOT perpendicular to normal_up_dir
|
||||
wanted_up_dir.normalize();
|
||||
Vec3d wanted_up_dir = suggest_up(normal, up_limit);
|
||||
|
||||
// perpendicular to emboss vector of text and normal
|
||||
Vec3d axis_view;
|
||||
@ -1591,25 +1608,24 @@ Transform3d Emboss::create_transformation_onto_surface(const Vec3d &position,
|
||||
axis_view = Vec3d::UnitY();
|
||||
angle_view = M_PI;
|
||||
} else {
|
||||
axis_view = text_emboss_dir.cross(normal);
|
||||
angle_view = std::acos(text_emboss_dir.dot(normal)); // in rad
|
||||
axis_view = emboss_dir.cross(normal);
|
||||
angle_view = std::acos(emboss_dir.dot(normal)); // in rad
|
||||
axis_view.normalize();
|
||||
}
|
||||
|
||||
Eigen::AngleAxis view_rot(angle_view, axis_view);
|
||||
Vec3d wanterd_up_rotated = view_rot.matrix().inverse() * wanted_up_dir;
|
||||
wanterd_up_rotated.normalize();
|
||||
double angle_up = std::acos(text_up_dir.dot(wanterd_up_rotated));
|
||||
double angle_up = std::acos(up_dir.dot(wanterd_up_rotated));
|
||||
|
||||
// text_view and text_view2 should have same direction
|
||||
Vec3d text_view2 = text_up_dir.cross(wanterd_up_rotated);
|
||||
Vec3d diff_view = text_emboss_dir - text_view2;
|
||||
Vec3d text_view = up_dir.cross(wanterd_up_rotated);
|
||||
Vec3d diff_view = emboss_dir - text_view;
|
||||
if (std::fabs(diff_view.x()) > 1. ||
|
||||
std::fabs(diff_view.y()) > 1. ||
|
||||
std::fabs(diff_view.z()) > 1.) // oposit direction
|
||||
angle_up *= -1.;
|
||||
|
||||
Eigen::AngleAxis up_rot(angle_up, text_emboss_dir);
|
||||
Eigen::AngleAxis up_rot(angle_up, emboss_dir);
|
||||
|
||||
Transform3d transform = Transform3d::Identity();
|
||||
transform.translate(position);
|
||||
|
@ -282,6 +282,14 @@ namespace Emboss
|
||||
/// <returns>Wanted up vector</returns>
|
||||
Vec3d suggest_up(const Vec3d normal, double up_limit = 0.9);
|
||||
|
||||
/// <summary>
|
||||
/// By transformation calculate angle between suggested and actual up vector
|
||||
/// </summary>
|
||||
/// <param name="tr">Transformation of embossed volume in world</param>
|
||||
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
|
||||
/// <returns>Rotation of suggested up-vector[in rad] in the range [-Pi, Pi], When rotation is not zero</returns>
|
||||
std::optional<float> calc_up(const Transform3d &tr, double up_limit = 0.9);
|
||||
|
||||
/// <summary>
|
||||
/// Create transformation for emboss text object to lay on surface point
|
||||
/// </summary>
|
||||
|
@ -103,8 +103,12 @@ static const struct Limits
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} limits;
|
||||
|
||||
// Define where is up vector on model
|
||||
constexpr double up_limit = 0.9;
|
||||
|
||||
static bool is_text_empty(const std::string &text){
|
||||
return text.empty() ||
|
||||
text.find_first_not_of(" \n\t\r") == std::string::npos;
|
||||
@ -1239,7 +1243,8 @@ void GLGizmoEmboss::set_default_text(){ m_text = _u8L("Embossed text"); }
|
||||
|
||||
void GLGizmoEmboss::set_volume_by_selection()
|
||||
{
|
||||
ModelVolume *vol = priv::get_selected_volume(m_parent.get_selection());
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
ModelVolume *vol = priv::get_selected_volume(selection);
|
||||
// is same volume selected?
|
||||
if (vol != nullptr && vol->id() == m_volume_id)
|
||||
return;
|
||||
@ -1259,6 +1264,13 @@ void GLGizmoEmboss::set_volume_by_selection()
|
||||
|
||||
// is select embossed volume?
|
||||
set_volume(vol);
|
||||
|
||||
// Check if user changed up vector by rotation or scale out of emboss gizmo
|
||||
if (m_volume != nullptr) {
|
||||
Transform3d world = selection.get_first_volume()->world_matrix();
|
||||
std::optional<float> angle = calc_up(world, priv::up_limit);
|
||||
m_volume->text_configuration->style.prop.angle = angle;
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::set_volume(ModelVolume *volume)
|
||||
@ -3563,31 +3575,6 @@ void GLGizmoEmboss::draw_advanced()
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", _u8L("Use camera direction for text orientation").c_str());
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(_u8L("Reset Up").c_str())) {
|
||||
GLVolume *gl_volume = priv::get_gl_volume(m_parent);
|
||||
if (gl_volume != nullptr) {
|
||||
Transform3d world = gl_volume->world_matrix();
|
||||
auto world_linear = world.linear();
|
||||
Vec3d z_world = world_linear.col(2);
|
||||
z_world.normalize();
|
||||
Vec3d wanted_up = suggest_up(z_world);
|
||||
|
||||
Vec3d y_world = world_linear.col(1);
|
||||
auto z_rotation = Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(y_world, wanted_up);
|
||||
Transform3d world_new = z_rotation * world;
|
||||
auto world_new_linear = world_new.linear();
|
||||
Transform3d volume_new = gl_volume->get_volume_transformation().get_matrix();
|
||||
Transform3d instance = gl_volume->get_instance_transformation().get_matrix();
|
||||
volume_new.linear() = instance.linear().inverse() * world_new.linear();
|
||||
gl_volume->set_volume_transformation(volume_new);
|
||||
m_parent.do_move(L("Reset up vector"));
|
||||
}
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", _u8L("Reset skew of text to be normal in world").c_str());
|
||||
}
|
||||
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
ImGui::Text("family = %s", (font_prop.family.has_value() ?
|
||||
font_prop.family->c_str() :
|
||||
@ -4079,7 +4066,7 @@ bool priv::start_create_volume_on_surface_job(
|
||||
Transform3d instance = gl_volume->get_instance_transformation().get_matrix();
|
||||
|
||||
// Create result volume transformation
|
||||
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal);
|
||||
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, priv::up_limit);
|
||||
const FontProp &font_prop = emboss_data.text_configuration.style.prop;
|
||||
apply_transformation(font_prop, surface_trmat);
|
||||
// new transformation in world coor is surface_trmat
|
||||
|
Loading…
x
Reference in New Issue
Block a user