Volume do not store angle of text any more.
(it is stored inside of volume transformation and si calculated on the fly)
This commit is contained in:
parent
e428dcc57e
commit
191f670dbd
9 changed files with 167 additions and 103 deletions
|
@ -1264,15 +1264,17 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
|
|||
return result;
|
||||
}
|
||||
|
||||
void Emboss::apply_transformation(const FontProp &font_prop,
|
||||
Transform3d &transformation)
|
||||
{
|
||||
if (font_prop.angle.has_value()) {
|
||||
double angle_z = *font_prop.angle;
|
||||
void Emboss::apply_transformation(const FontProp &font_prop, Transform3d &transformation){
|
||||
apply_transformation(font_prop.angle, font_prop.distance, transformation);
|
||||
}
|
||||
|
||||
void Emboss::apply_transformation(const std::optional<float>& angle, const std::optional<float>& distance, Transform3d &transformation) {
|
||||
if (angle.has_value()) {
|
||||
double angle_z = *angle;
|
||||
transformation *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ());
|
||||
}
|
||||
if (font_prop.distance.has_value()) {
|
||||
Vec3d translate = Vec3d::UnitZ() * (*font_prop.distance);
|
||||
if (distance.has_value()) {
|
||||
Vec3d translate = Vec3d::UnitZ() * (*distance);
|
||||
transformation.translate(translate);
|
||||
}
|
||||
}
|
||||
|
@ -1583,7 +1585,7 @@ std::optional<float> Emboss::calc_up(const Transform3d &tr, double up_limit)
|
|||
m.row(2) = normal;
|
||||
double det = m.determinant();
|
||||
|
||||
return atan2(det, dot);
|
||||
return -atan2(det, dot);
|
||||
}
|
||||
|
||||
Transform3d Emboss::create_transformation_onto_surface(const Vec3d &position,
|
||||
|
|
|
@ -193,6 +193,7 @@ namespace Emboss
|
|||
/// Z-rotation as angle to Y axis(FontProp::angle)</param>
|
||||
/// <param name="transformation">In / Out transformation to modify by property</param>
|
||||
void apply_transformation(const FontProp &font_prop, Transform3d &transformation);
|
||||
void apply_transformation(const std::optional<float> &angle, const std::optional<float> &distance, Transform3d &transformation);
|
||||
|
||||
/// <summary>
|
||||
/// Read information from naming table of font file
|
||||
|
|
|
@ -49,10 +49,12 @@ struct FontProp
|
|||
// used for move over model surface
|
||||
// When not set value is zero and is not stored
|
||||
std::optional<float> distance; // [in mm]
|
||||
|
||||
// change up vector direction of font
|
||||
|
||||
// Angle of rotation around emboss direction (Z axis)
|
||||
// It is calculate on the fly from volume world transformation
|
||||
// only StyleManager keep actual value for comparision with style
|
||||
// When not set value is zero and is not stored
|
||||
std::optional<float> angle; // [in radians]
|
||||
std::optional<float> angle; // [in radians] form -Pi to Pi
|
||||
|
||||
// Parameter for True Type Font collections
|
||||
// Select index of font in collection
|
||||
|
|
|
@ -325,9 +325,13 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||
if (!m_dragging) return used;
|
||||
|
||||
if (mouse_event.Dragging()) {
|
||||
auto &angle_opt = m_volume->text_configuration->style.prop.angle;
|
||||
if (!m_rotate_start_angle.has_value())
|
||||
m_rotate_start_angle = angle_opt.has_value() ? *angle_opt : 0.f;
|
||||
if (!m_rotate_start_angle.has_value()) {
|
||||
// when m_rotate_start_angle is not set mean it is not Dragging
|
||||
// when angle_opt is not set mean angle is Zero
|
||||
const std::optional<float> &angle_opt = m_style_manager.get_font_prop().angle;
|
||||
m_rotate_start_angle = angle_opt.has_value() ? *angle_opt : 0.f;
|
||||
}
|
||||
|
||||
double angle = m_rotate_gizmo.get_angle();
|
||||
angle -= PI / 2; // Grabber is upward
|
||||
|
||||
|
@ -339,18 +343,15 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
|||
angle += *m_rotate_start_angle;
|
||||
// move to range <-M_PI, M_PI>
|
||||
priv::to_range_pi_pi(angle);
|
||||
// propagate angle into property
|
||||
angle_opt = static_cast<float>(angle);
|
||||
|
||||
// do not store zero
|
||||
if (is_approx(*angle_opt, 0.f))
|
||||
angle_opt.reset();
|
||||
|
||||
// set into activ style
|
||||
assert(m_style_manager.is_active_font());
|
||||
if (m_style_manager.is_active_font())
|
||||
if (m_style_manager.is_active_font()) {
|
||||
std::optional<float> angle_opt;
|
||||
if (!is_approx(angle, 0.))
|
||||
angle_opt = angle;
|
||||
m_style_manager.get_font_prop().angle = angle_opt;
|
||||
|
||||
}
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
@ -361,9 +362,11 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||
if (m_volume == nullptr)
|
||||
return false;
|
||||
|
||||
std::optional<double> up_limit;
|
||||
if (m_keep_up) up_limit = priv::up_limit;
|
||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||
bool was_dragging = m_surface_drag.has_value();
|
||||
bool res = on_mouse_surface_drag(mouse_event, camera, m_surface_drag, m_parent, m_raycast_manager);
|
||||
bool res = on_mouse_surface_drag(mouse_event, camera, m_surface_drag, m_parent, m_raycast_manager, up_limit);
|
||||
bool is_dragging = m_surface_drag.has_value();
|
||||
|
||||
// End with surface dragging?
|
||||
|
@ -387,6 +390,17 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||
else if (was_dragging && is_dragging) {
|
||||
// update scale of selected volume --> should be approx the same
|
||||
calculate_scale();
|
||||
|
||||
// Recalculate angle for GUI
|
||||
if (!m_keep_up) {
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
|
||||
assert(gl_volume != nullptr);
|
||||
assert(m_style_manager.is_active_font());
|
||||
if (gl_volume == nullptr || !m_style_manager.is_active_font())
|
||||
return res;
|
||||
|
||||
m_style_manager.get_style().prop.angle = calc_up(gl_volume->world_matrix(), priv::up_limit);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -693,6 +707,13 @@ void GLGizmoEmboss::on_stop_dragging()
|
|||
// apply rotation
|
||||
m_parent.do_rotate(L("Text-Rotate"));
|
||||
|
||||
// Re-Calculate current angle of up vector
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
|
||||
assert(m_style_manager.is_active_font());
|
||||
assert(gl_volume != nullptr);
|
||||
if (m_style_manager.is_active_font() && gl_volume != nullptr)
|
||||
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), priv::up_limit);
|
||||
|
||||
m_rotate_start_angle.reset();
|
||||
|
||||
// recalculate for surface cut
|
||||
|
@ -723,32 +744,37 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration()
|
|||
int count_letter_M_in_input = 12;
|
||||
cfg.input_width = letter_m_size.x * count_letter_M_in_input;
|
||||
GuiCfg::Translations &tr = cfg.translations;
|
||||
tr.font = _u8L("Font");
|
||||
tr.size = _u8L("Height");
|
||||
tr.depth = _u8L("Depth");
|
||||
|
||||
tr.font = _u8L("Font");
|
||||
tr.height = _u8L("Height");
|
||||
tr.depth = _u8L("Depth");
|
||||
|
||||
float max_text_width = std::max({
|
||||
ImGui::CalcTextSize(tr.font.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.size.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.height.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.depth.c_str()).x});
|
||||
cfg.indent = static_cast<float>(cfg.icon_width);
|
||||
cfg.input_offset = style.WindowPadding.x + cfg.indent + max_text_width + space;
|
||||
|
||||
tr.use_surface = _u8L("Use surface");
|
||||
tr.char_gap = _u8L("Char gap");
|
||||
tr.line_gap = _u8L("Line gap");
|
||||
tr.boldness = _u8L("Boldness");
|
||||
tr.italic = _u8L("Skew ratio");
|
||||
tr.surface_distance = _u8L("Z-move");
|
||||
tr.angle = _u8L("Z-rot");
|
||||
tr.collection = _u8L("Collection");
|
||||
tr.use_surface = _u8L("Use surface");
|
||||
tr.char_gap = _u8L("Char gap");
|
||||
tr.line_gap = _u8L("Line gap");
|
||||
tr.boldness = _u8L("Boldness");
|
||||
tr.skew_ration = _u8L("Skew ratio");
|
||||
tr.from_surface = _u8L("From surface");
|
||||
tr.rotation = _u8L("Rotation");
|
||||
tr.keep_up = _u8L("Keep Up");
|
||||
tr.collection = _u8L("Collection");
|
||||
|
||||
float max_advanced_text_width = std::max({
|
||||
ImGui::CalcTextSize(tr.use_surface.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.char_gap.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.line_gap.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.boldness.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.italic.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.surface_distance.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.angle.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.skew_ration.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.from_surface.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.rotation.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.keep_up.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.collection.c_str()).x });
|
||||
cfg.advanced_input_offset = max_advanced_text_width
|
||||
+ 3 * space + cfg.indent;
|
||||
|
@ -774,9 +800,9 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration()
|
|||
+ 2 * (cfg.icon_width + space);
|
||||
cfg.minimal_window_size = ImVec2(window_width, window_height);
|
||||
|
||||
// 6 = charGap, LineGap, Bold, italic, surfDist, angle
|
||||
// 9 = useSurface, charGap, lineGap, bold, italic, surfDist, rotation, keepUp, textFaceToCamera
|
||||
// 4 = 1px for fix each edit image of drag float
|
||||
float advance_height = input_height * 8 + 8;
|
||||
float advance_height = input_height * 9 + 8;
|
||||
cfg.minimal_window_size_with_advance =
|
||||
ImVec2(cfg.minimal_window_size.x,
|
||||
cfg.minimal_window_size.y + advance_height);
|
||||
|
@ -867,9 +893,17 @@ void GLGizmoEmboss::set_default_text(){ m_text = _u8L("Embossed text"); }
|
|||
void GLGizmoEmboss::set_volume_by_selection()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
ModelVolume *vol = get_selected_volume(selection);
|
||||
// is same volume selected?
|
||||
if (vol != nullptr && vol->id() == m_volume_id)
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(selection);
|
||||
if (gl_volume == nullptr)
|
||||
return reset_volume();
|
||||
|
||||
const ModelObjectPtrs &objects = selection.get_model()->objects;
|
||||
ModelVolume *volume =get_model_volume(*gl_volume, objects);
|
||||
if (volume == nullptr)
|
||||
return reset_volume();
|
||||
|
||||
// is same volume as actual selected?
|
||||
if (volume->id() == m_volume_id)
|
||||
return;
|
||||
|
||||
// for changed volume notification is NOT valid
|
||||
|
@ -877,30 +911,14 @@ void GLGizmoEmboss::set_volume_by_selection()
|
|||
|
||||
// Do not use focused input value when switch volume(it must swith value)
|
||||
if (m_volume != nullptr &&
|
||||
m_volume != vol) // when update volume it changed id BUT not pointer
|
||||
m_volume != volume) // when update volume it changed id BUT not pointer
|
||||
ImGuiWrapper::left_inputs();
|
||||
|
||||
if (vol == nullptr) {
|
||||
reset_volume();
|
||||
return;
|
||||
}
|
||||
// Is selected volume text volume?
|
||||
const std::optional<TextConfiguration>& tc_opt = volume->text_configuration;
|
||||
if (!tc_opt.has_value())
|
||||
return reset_volume();
|
||||
|
||||
// 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)
|
||||
{
|
||||
assert(volume != nullptr);
|
||||
const std::optional<TextConfiguration> tc_opt = volume->text_configuration;
|
||||
if (!tc_opt.has_value()) return false;
|
||||
const TextConfiguration &tc = *tc_opt;
|
||||
const EmbossStyle &style = tc.style;
|
||||
|
||||
|
@ -992,7 +1010,7 @@ bool GLGizmoEmboss::set_volume(ModelVolume *volume)
|
|||
|
||||
// The change of volume could show or hide part with setter on volume type
|
||||
if (m_volume == nullptr ||
|
||||
get_model_volume(m_volume_id, m_parent.get_selection().get_model()->objects) == nullptr ||
|
||||
get_model_volume(m_volume_id, objects) == nullptr ||
|
||||
(m_volume->get_object()->volumes.size() == 1) !=
|
||||
(volume->get_object()->volumes.size() == 1)){
|
||||
m_should_set_minimal_windows_size = true;
|
||||
|
@ -1008,9 +1026,13 @@ bool GLGizmoEmboss::set_volume(ModelVolume *volume)
|
|||
m_volume = volume;
|
||||
m_volume_id = volume->id();
|
||||
|
||||
// Calculate current angle of up vector
|
||||
assert(m_style_manager.is_active_font());
|
||||
if (m_style_manager.is_active_font())
|
||||
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), priv::up_limit);
|
||||
|
||||
// calculate scale for height and depth inside of scaled object instance
|
||||
calculate_scale();
|
||||
return true;
|
||||
calculate_scale();
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::reset_volume()
|
||||
|
@ -1020,9 +1042,9 @@ void GLGizmoEmboss::reset_volume()
|
|||
|
||||
m_volume = nullptr;
|
||||
m_volume_id.id = 0;
|
||||
// TODO: check if it is neccessary to set default text
|
||||
// Idea is to set default text when create object
|
||||
set_default_text();
|
||||
|
||||
// No more need of current notification
|
||||
remove_notification_not_valid_font();
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::calculate_scale() {
|
||||
|
@ -2677,7 +2699,7 @@ void GLGizmoEmboss::draw_height(bool use_inch)
|
|||
const float *stored = ((stored_style)? &stored_style->prop.size_in_mm : nullptr);
|
||||
const char *size_format = ((use_inch) ? "%.2f in" : "%.1f mm");
|
||||
const std::string revert_text_size = _u8L("Revert text size.");
|
||||
const std::string& name = m_gui_cfg->translations.size;
|
||||
const std::string& name = m_gui_cfg->translations.height;
|
||||
if (rev_input_mm(name, value, stored, revert_text_size, 0.1f, 1.f, size_format, use_inch, m_scale_height))
|
||||
if (set_height())
|
||||
process();
|
||||
|
@ -2915,7 +2937,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||
// input italic
|
||||
auto def_skew = stored_style ?
|
||||
&stored_style->prop.skew : nullptr;
|
||||
if (rev_slider(tr.italic, font_prop.skew, def_skew, _u8L("Undo letter's skew"),
|
||||
if (rev_slider(tr.skew_ration, font_prop.skew, def_skew, _u8L("Undo letter's skew"),
|
||||
priv::limits.skew.gui.min, priv::limits.skew.gui.max, "%.2f", _L("Italic strength ratio"))){
|
||||
if (!priv::Limits::apply(font_prop.skew, priv::limits.skew.values) ||
|
||||
!m_volume->text_configuration->style.prop.skew.has_value() ||
|
||||
|
@ -2949,7 +2971,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||
}
|
||||
min_distance *= ObjectManipulation::mm_to_in;
|
||||
max_distance *= ObjectManipulation::mm_to_in;
|
||||
if (rev_slider(tr.surface_distance, distance_inch, def_distance, undo_move_tooltip, min_distance, max_distance, "%.3f in", move_tooltip)) {
|
||||
if (rev_slider(tr.from_surface, distance_inch, def_distance, undo_move_tooltip, min_distance, max_distance, "%.3f in", move_tooltip)) {
|
||||
if (distance_inch.has_value()) {
|
||||
font_prop.distance = *distance_inch * ObjectManipulation::in_to_mm;
|
||||
} else {
|
||||
|
@ -2958,7 +2980,7 @@ void GLGizmoEmboss::draw_advanced()
|
|||
is_moved = true;
|
||||
}
|
||||
} else {
|
||||
if (rev_slider(tr.surface_distance, distance, def_distance, undo_move_tooltip,
|
||||
if (rev_slider(tr.from_surface, distance, def_distance, undo_move_tooltip,
|
||||
min_distance, max_distance, "%.2f mm", move_tooltip)) is_moved = true;
|
||||
}
|
||||
|
||||
|
@ -2971,33 +2993,50 @@ void GLGizmoEmboss::draw_advanced()
|
|||
|
||||
// slider for Clock-wise angle in degress
|
||||
// stored angle is optional CCW and in radians
|
||||
std::optional<float> &angle = font_prop.angle;
|
||||
float prev_angle = angle.has_value() ? *angle : .0f;
|
||||
// Convert stored value to degress
|
||||
// minus create clock-wise roation from CCW
|
||||
float angle_deg = angle.has_value() ?
|
||||
static_cast<float>(-(*angle) * 180 / M_PI) : .0f;
|
||||
const std::optional<float> &angle_opt = m_style_manager.get_font_prop().angle;
|
||||
float angle = angle_opt.has_value() ? *angle_opt: 0.f;
|
||||
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
|
||||
float def_angle_deg_val =
|
||||
(!stored_style || !stored_style->prop.angle.has_value()) ?
|
||||
0.f : (*stored_style->prop.angle * -180 / M_PI);
|
||||
float* def_angle_deg = stored_style ?
|
||||
&def_angle_deg_val : nullptr;
|
||||
if (rev_slider(tr.angle, angle_deg, def_angle_deg, _u8L("Undo rotation"),
|
||||
if (rev_slider(tr.rotation, angle_deg, def_angle_deg, _u8L("Undo rotation"),
|
||||
priv::limits.angle.min, priv::limits.angle.max, u8"%.2f °",
|
||||
_L("Rotate text Clock-wise."))) {
|
||||
// convert back to radians and CCW
|
||||
angle = -angle_deg * M_PI / 180.0;
|
||||
priv::to_range_pi_pi(*angle);
|
||||
if (is_approx(*angle, 0.f))
|
||||
angle.reset();
|
||||
float angle_rad = static_cast<float>(-angle_deg * M_PI / 180.0);
|
||||
priv::to_range_pi_pi(angle_rad);
|
||||
|
||||
|
||||
float diff_angle = angle_rad - angle;
|
||||
do_rotate(diff_angle);
|
||||
|
||||
// calc angle after rotation
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(m_parent.get_selection());
|
||||
assert(gl_volume != nullptr);
|
||||
assert(m_style_manager.is_active_font());
|
||||
if (m_style_manager.is_active_font() && gl_volume != nullptr)
|
||||
m_style_manager.get_font_prop().angle = calc_up(gl_volume->world_matrix(), priv::up_limit);
|
||||
|
||||
m_volume->text_configuration->style.prop.angle = angle;
|
||||
float act_angle = angle.has_value() ? *angle : .0f;
|
||||
do_rotate(act_angle - prev_angle);
|
||||
// recalculate for surface cut
|
||||
if (font_prop.use_surface) process();
|
||||
if (font_prop.use_surface)
|
||||
process();
|
||||
}
|
||||
|
||||
ImGui::Text("%s", tr.keep_up.c_str());
|
||||
ImGui::SameLine(m_gui_cfg->advanced_input_offset);
|
||||
if (ImGui::Checkbox("##keep_up", &m_keep_up)) {
|
||||
if (m_keep_up) {
|
||||
// copy angle to volume
|
||||
m_volume->text_configuration->style.prop.angle = font_prop.angle;
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Keep text orientation during surface dragging.\nNot stable between horizontal and vertical alignment.").c_str());
|
||||
|
||||
// when more collection add selector
|
||||
if (ff.font_file->infos.size() > 1) {
|
||||
ImGui::Text("%s", tr.collection.c_str());
|
||||
|
|
|
@ -83,8 +83,6 @@ private:
|
|||
void set_default_text();
|
||||
|
||||
void set_volume_by_selection();
|
||||
// load text configuration from volume into gizmo
|
||||
bool set_volume(ModelVolume *volume);
|
||||
void reset_volume();
|
||||
|
||||
// create volume from text - main functionality
|
||||
|
@ -198,7 +196,7 @@ private:
|
|||
struct Translations
|
||||
{
|
||||
std::string font;
|
||||
std::string size;
|
||||
std::string height;
|
||||
std::string depth;
|
||||
std::string use_surface;
|
||||
|
||||
|
@ -206,9 +204,10 @@ private:
|
|||
std::string char_gap;
|
||||
std::string line_gap;
|
||||
std::string boldness;
|
||||
std::string italic;
|
||||
std::string surface_distance;
|
||||
std::string angle;
|
||||
std::string skew_ration;
|
||||
std::string from_surface;
|
||||
std::string rotation;
|
||||
std::string keep_up;
|
||||
std::string collection;
|
||||
};
|
||||
Translations translations;
|
||||
|
@ -286,7 +285,10 @@ private:
|
|||
static void init_truncated_names(Facenames &face_names, float max_width);
|
||||
|
||||
// Text to emboss
|
||||
std::string m_text;
|
||||
std::string m_text; // Sequence of Unicode UTF8 symbols
|
||||
|
||||
// When true keep up vector otherwise relative rotation
|
||||
bool m_keep_up = true;
|
||||
|
||||
// current selected volume
|
||||
// NOTE: Be carefull could be uninitialized (removed from Model)
|
||||
|
|
|
@ -502,6 +502,9 @@ void UpdateJob::update_volume(ModelVolume *volume,
|
|||
volume->calculate_convex_hull();
|
||||
volume->get_object()->invalidate_bounding_box();
|
||||
volume->text_configuration = text_configuration;
|
||||
|
||||
// discard information about rotation, should not be stored in volume
|
||||
volume->text_configuration->style.prop.angle.reset();
|
||||
|
||||
GUI_App &app = wxGetApp(); // may be move to input
|
||||
GLCanvas3D *canvas = app.plater()->canvas3D();
|
||||
|
@ -615,6 +618,10 @@ void priv::create_volume(
|
|||
|
||||
volume->name = data.volume_name; // copy
|
||||
volume->text_configuration = data.text_configuration; // copy
|
||||
|
||||
// discard information about rotation, should not be stored in volume
|
||||
volume->text_configuration->style.prop.angle.reset();
|
||||
|
||||
volume->set_transformation(trmat);
|
||||
|
||||
// update printable state on canvas
|
||||
|
|
|
@ -3366,9 +3366,11 @@ void Selection::transform_volume_relative(GLVolume& volume, const VolumeCache& v
|
|||
|
||||
ModelVolume *get_selected_volume(const Selection &selection)
|
||||
{
|
||||
const GLVolume *vol_gl = get_selected_gl_volume(selection);
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(selection);
|
||||
if (gl_volume == nullptr)
|
||||
return nullptr;
|
||||
const ModelObjectPtrs &objects = selection.get_model()->objects;
|
||||
return get_model_volume(*vol_gl, objects);
|
||||
return get_model_volume(*gl_volume, objects);
|
||||
}
|
||||
|
||||
const GLVolume *get_selected_gl_volume(const Selection &selection)
|
||||
|
|
|
@ -69,7 +69,8 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
const Camera &camera,
|
||||
std::optional<SurfaceDrag> &surface_drag,
|
||||
GLCanvas3D &canvas,
|
||||
RaycastManager &raycast_manager)
|
||||
RaycastManager &raycast_manager,
|
||||
std::optional<double> up_limit)
|
||||
{
|
||||
// Fix when leave window during dragging
|
||||
// Fix when click right button
|
||||
|
@ -153,7 +154,10 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
Transform3d instance_tr = instance->get_matrix();
|
||||
Transform3d instance_tr_inv = instance_tr.inverse();
|
||||
Transform3d world_tr = instance_tr * volume_tr;
|
||||
surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition};
|
||||
std::optional<float> start_angle;
|
||||
if (up_limit.has_value())
|
||||
start_angle = Emboss::calc_up(world_tr, *up_limit);
|
||||
surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle};
|
||||
|
||||
// disable moving with object by mouse
|
||||
canvas.enable_moving(false);
|
||||
|
@ -195,11 +199,11 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
Transform3d world_new = z_rotation * surface_drag->world;
|
||||
auto world_new_linear = world_new.linear();
|
||||
|
||||
// Fix direction of up vector
|
||||
{
|
||||
// Fix direction of up vector to zero initial rotation
|
||||
if(up_limit.has_value()){
|
||||
Vec3d z_world = world_new_linear.col(2);
|
||||
z_world.normalize();
|
||||
Vec3d wanted_up = Emboss::suggest_up(z_world);
|
||||
Vec3d wanted_up = Emboss::suggest_up(z_world, *up_limit);
|
||||
|
||||
Vec3d y_world = world_new_linear.col(1);
|
||||
auto y_rotation = Eigen::Quaternion<double, Eigen::DontAlign>::FromTwoVectors(y_world, wanted_up);
|
||||
|
@ -229,7 +233,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
volume_new = volume_new * (*tc.fix_3mf_tr);
|
||||
|
||||
// apply move in Z direction and rotation by up vector
|
||||
Emboss::apply_transformation(tc.style.prop, volume_new);
|
||||
Emboss::apply_transformation(surface_drag->start_angle, tc.style.prop.distance, volume_new);
|
||||
}
|
||||
|
||||
// Update transformation for all instances
|
||||
|
|
|
@ -34,6 +34,9 @@ struct SurfaceDrag
|
|||
// condition for raycaster
|
||||
RaycastManager::AllowVolumes condition;
|
||||
|
||||
// initial rotation in Z axis of volume
|
||||
std::optional<float> start_angle;
|
||||
|
||||
// Flag whether coordinate hit some volume
|
||||
bool exist_hit = true;
|
||||
};
|
||||
|
@ -48,12 +51,14 @@ struct SurfaceDrag
|
|||
/// <param name="canvas">Contain gl_volumes and selection</param>
|
||||
/// <param name="raycast_manager">AABB trees for raycast in object
|
||||
/// Refresh state inside of function </param>
|
||||
/// <param name="up_limit">When set than use correction of up vector</param>
|
||||
/// <returns>True when event is processed otherwise false</returns>
|
||||
bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
||||
const Camera &camera,
|
||||
std::optional<SurfaceDrag> &surface_drag,
|
||||
GLCanvas3D &canvas,
|
||||
RaycastManager &raycast_manager);
|
||||
RaycastManager &raycast_manager,
|
||||
std::optional<double> up_limit = {});
|
||||
|
||||
/// <summary>
|
||||
/// Calculate translation of volume onto surface of model
|
||||
|
|
Loading…
Reference in a new issue