calculate angle when set volume

This commit is contained in:
Filip Sykala - NTB T15p 2023-02-20 14:50:17 +01:00
parent d6b8163975
commit ead192b43b
3 changed files with 61 additions and 50 deletions

View File

@ -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);

View File

@ -281,6 +281,14 @@ namespace Emboss
/// <param name="up_limit">Is compared with normal.z to suggest up direction</param>
/// <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

View File

@ -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