mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-11 03:21:57 +08:00
Connect rotation by gizmo with angle inside of property
This commit is contained in:
parent
6a62462c7e
commit
05e795bd9e
@ -7,55 +7,87 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
// user defined font property
|
/// <summary>
|
||||||
|
/// User modifiable property of text style
|
||||||
|
/// </summary>
|
||||||
struct FontProp
|
struct FontProp
|
||||||
{
|
{
|
||||||
// define extra space between letters, negative mean closer letter
|
// define extra space between letters, negative mean closer letter
|
||||||
std::optional<int> char_gap;
|
// When not set value is zero and is not stored
|
||||||
|
std::optional<int> char_gap; // [in font point]
|
||||||
|
|
||||||
// define extra space between lines, negative mean closer lines
|
// define extra space between lines, negative mean closer lines
|
||||||
std::optional<int> line_gap;
|
// When not set value is zero and is not stored
|
||||||
// Z depth of text [in mm]
|
std::optional<int> line_gap; // [in font point]
|
||||||
float emboss;
|
|
||||||
|
// Z depth of text
|
||||||
|
float emboss; // [in mm]
|
||||||
|
|
||||||
// positive value mean wider character shape
|
// positive value mean wider character shape
|
||||||
// negative value mean tiner character shape
|
// negative value mean tiner character shape
|
||||||
|
// When not set value is zero and is not stored
|
||||||
std::optional<float> boldness; // [in mm]
|
std::optional<float> boldness; // [in mm]
|
||||||
|
|
||||||
// positive value mean italic of character (CW)
|
// positive value mean italic of character (CW)
|
||||||
// negative value mean CCW skew (unItalic)
|
// negative value mean CCW skew (unItalic)
|
||||||
std::optional<float> skew;
|
// When not set value is zero and is not stored
|
||||||
|
std::optional<float> skew; // [ration x:y]
|
||||||
|
|
||||||
// distance from surface point
|
// distance from surface point
|
||||||
// used for move over model surface
|
// used for move over model surface
|
||||||
std::optional<float> distance;
|
// When not set value is zero and is not stored
|
||||||
|
std::optional<float> distance; // [in mm]
|
||||||
|
|
||||||
// change up vector of font
|
// change up vector direction of font
|
||||||
std::optional<float> angle;
|
// When not set value is zero and is not stored
|
||||||
|
std::optional<float> angle; // [in radians]
|
||||||
|
|
||||||
// TODO: add enum class Align: center/left/right
|
//enum class Align {
|
||||||
|
// left,
|
||||||
|
// right,
|
||||||
|
// center,
|
||||||
|
// top_left,
|
||||||
|
// top_right,
|
||||||
|
// top_center,
|
||||||
|
// bottom_left,
|
||||||
|
// bottom_right,
|
||||||
|
// bottom_center
|
||||||
|
//};
|
||||||
|
//// change pivot of text
|
||||||
|
//// When not set, center is used and is not stored
|
||||||
|
//std::optional<Align> align;
|
||||||
|
|
||||||
//////
|
//////
|
||||||
// Duplicit data to wxFontDescriptor
|
// Duplicit data to wxFontDescriptor
|
||||||
// used for store/load .3mf file
|
// used for store/load .3mf file
|
||||||
//////
|
//////
|
||||||
|
|
||||||
// Height of letter [in mm],
|
// Height of text line (letters)
|
||||||
// duplicit to wxFont::PointSize
|
// duplicit to wxFont::PointSize
|
||||||
float size_in_mm;
|
float size_in_mm; // [in mm]
|
||||||
// Define type of font
|
|
||||||
|
// Additional data about font to be able to find substitution,
|
||||||
|
// when same font is not installed
|
||||||
std::optional<std::string> family;
|
std::optional<std::string> family;
|
||||||
std::optional<std::string> face_name;
|
std::optional<std::string> face_name;
|
||||||
std::optional<std::string> style;
|
std::optional<std::string> style;
|
||||||
std::optional<std::string> weight;
|
std::optional<std::string> weight;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Only constructor with restricted values
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="line_height">Y size of text [in mm]</param>
|
||||||
|
/// <param name="depth">Z size of text [in mm]</param>
|
||||||
FontProp(float line_height = 10.f, float depth = 2.f)
|
FontProp(float line_height = 10.f, float depth = 2.f)
|
||||||
: emboss(depth), size_in_mm(line_height)
|
: emboss(depth), size_in_mm(line_height)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator==(const FontProp& other) const {
|
bool operator==(const FontProp& other) const {
|
||||||
|
// compare float values
|
||||||
auto is_equal = [](const float &v1, const float &v2) {
|
auto is_equal = [](const float &v1, const float &v2) {
|
||||||
return fabs(v1 - v2) < std::numeric_limits<float>::epsilon();
|
return fabs(v1 - v2) < std::numeric_limits<float>::epsilon();
|
||||||
};
|
};
|
||||||
|
// compare optional float values
|
||||||
auto is_equal_ = [&is_equal](const std::optional<float> &v1,
|
auto is_equal_ = [&is_equal](const std::optional<float> &v1,
|
||||||
const std::optional<float> &v2) {
|
const std::optional<float> &v2) {
|
||||||
return (!v1.has_value() && !v2.has_value()) ||
|
return (!v1.has_value() && !v2.has_value()) ||
|
||||||
@ -71,22 +103,31 @@ struct FontProp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// undo / redo stack recovery
|
// undo / redo stack recovery
|
||||||
template<class Archive> void serialize(Archive &ar)
|
//template<class Archive> void serialize(Archive &ar)
|
||||||
{
|
//{
|
||||||
ar(char_gap, line_gap, emboss, boldness, skew, size_in_mm, family, face_name, style, weight);
|
// ar(char_gap, line_gap, emboss, boldness, skew, size_in_mm, family, face_name, style, weight);
|
||||||
}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
// represent selected font
|
/// <summary>
|
||||||
// Name must be human readable is visible in gui
|
/// Style of embossed text
|
||||||
// (Path + Type) must define how to open font for using on different OS
|
/// (Path + Type) must define how to open font for using on different OS
|
||||||
// NOTE: OnEdit fix serializations: FontListSerializable, TextConfigurationSerialization
|
/// NOTE: OnEdit fix serializations: FontListSerializable, TextConfigurationSerialization
|
||||||
|
/// </summary>
|
||||||
struct FontItem
|
struct FontItem
|
||||||
{
|
{
|
||||||
|
// Human readable name of style it is shown in GUI
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
// Define how to open font
|
||||||
|
// Meaning depend on type
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
enum class Type;
|
enum class Type;
|
||||||
|
// Define what is stored in path
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
|
// User modification of font style
|
||||||
FontProp prop;
|
FontProp prop;
|
||||||
|
|
||||||
FontItem() : type(Type::undefined){} // set undefined type
|
FontItem() : type(Type::undefined){} // set undefined type
|
||||||
@ -97,17 +138,23 @@ struct FontItem
|
|||||||
const std::string &path,
|
const std::string &path,
|
||||||
Type type,
|
Type type,
|
||||||
const FontProp & prop)
|
const FontProp & prop)
|
||||||
: name(name), path(path), type(type), prop(prop)
|
: name(name), path(path), type(type), prop(prop) // copy values
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// define data stored in path
|
// define data stored in path
|
||||||
|
// when wx change way of storing add new descriptor Type
|
||||||
enum class Type {
|
enum class Type {
|
||||||
undefined = 0,
|
undefined = 0,
|
||||||
file_path, // TrueTypeFont file loacation on computer - for privacy: path is NOT stored into 3mf
|
|
||||||
// wx font descriptors are platform dependent
|
// wx font descriptors are platform dependent
|
||||||
wx_win_font_descr, // path is font descriptor generated by wxWidgets on windows
|
// path is font descriptor generated by wxWidgets
|
||||||
wx_lin_font_descr, // path is font descriptor generated by wxWidgets on windows
|
wx_win_font_descr, // on Windows
|
||||||
wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows
|
wx_lin_font_descr, // on Linux
|
||||||
|
wx_mac_font_descr, // on Max OS
|
||||||
|
|
||||||
|
// TrueTypeFont file loacation on computer
|
||||||
|
// for privacy: only filename is stored into .3mf
|
||||||
|
file_path
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(const FontItem &other) const {
|
bool operator==(const FontItem &other) const {
|
||||||
@ -119,11 +166,11 @@ struct FontItem
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
// undo / redo stack recovery
|
//// undo / redo stack recovery
|
||||||
template<class Archive> void serialize(Archive &ar)
|
//template<class Archive> void serialize(Archive &ar)
|
||||||
{
|
//{
|
||||||
ar(name, path, (int) type, prop);
|
// ar(name, path, (int) type, prop);
|
||||||
}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Font item name inside list is unique
|
// Font item name inside list is unique
|
||||||
@ -131,14 +178,17 @@ struct FontItem
|
|||||||
// It is stored into AppConfig by FontListSerializable
|
// It is stored into AppConfig by FontListSerializable
|
||||||
using FontList = std::vector<FontItem>;
|
using FontList = std::vector<FontItem>;
|
||||||
|
|
||||||
// define how to create 'Text volume'
|
/// <summary>
|
||||||
// It is stored into .3mf by TextConfigurationSerialization
|
/// Define how to create 'Text volume'
|
||||||
// Also it is stored into undo / redo stack by cereal
|
/// It is stored into .3mf by TextConfigurationSerialization
|
||||||
|
/// It is part of ModelVolume optional data
|
||||||
|
/// </summary>
|
||||||
struct TextConfiguration
|
struct TextConfiguration
|
||||||
{
|
{
|
||||||
// define font
|
// Style of embossed text
|
||||||
FontItem font_item;
|
FontItem font_item;
|
||||||
|
|
||||||
|
// Embossed text value
|
||||||
std::string text = "None";
|
std::string text = "None";
|
||||||
|
|
||||||
TextConfiguration() = default; // optional needs empty constructor
|
TextConfiguration() = default; // optional needs empty constructor
|
||||||
@ -147,7 +197,7 @@ struct TextConfiguration
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
// undo / redo stack recovery
|
// undo / redo stack recovery
|
||||||
template<class Archive> void serialize(Archive &ar){ ar(text, font_item); }
|
//template<class Archive> void serialize(Archive &ar){ ar(text, font_item); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -179,19 +179,45 @@ static void draw_place_to_add_text() {
|
|||||||
|
|
||||||
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||||
{
|
{
|
||||||
|
if (mouse_event.Moving()) return false;
|
||||||
|
if (!m_dragging) return false;
|
||||||
|
|
||||||
|
assert(m_volume != nullptr);
|
||||||
|
assert(m_volume->text_configuration.has_value());
|
||||||
|
|
||||||
|
static std::optional<float> start_angle;
|
||||||
if (mouse_event.Dragging()) {
|
if (mouse_event.Dragging()) {
|
||||||
if (m_dragging) {
|
auto &angle_opt = m_volume->text_configuration->font_item.prop.angle;
|
||||||
// temporary rotation
|
if (!start_angle.has_value()) {
|
||||||
TransformationType transformation_type(
|
start_angle = angle_opt.has_value() ? *angle_opt : 0.f;
|
||||||
TransformationType::Local_Relative_Independent);
|
|
||||||
Vec3d rotation(0., 0., m_rotate_gizmo.get_angle());
|
|
||||||
m_parent.get_selection().rotate(rotation, transformation_type);
|
|
||||||
}
|
}
|
||||||
|
// temporary rotation
|
||||||
|
TransformationType transformation_type(
|
||||||
|
TransformationType::Local_Relative_Independent);
|
||||||
|
double angle = m_rotate_gizmo.get_angle();
|
||||||
|
m_parent.get_selection().rotate(Vec3d(0., 0., angle), transformation_type);
|
||||||
|
|
||||||
|
// propagate angle into property
|
||||||
|
angle_opt = static_cast<float>(*start_angle + angle);
|
||||||
|
// move to range <-M_PI, M_PI>
|
||||||
|
if (*angle_opt > M_PI) {
|
||||||
|
*angle_opt -= 2 * M_PI;
|
||||||
|
} else if (*angle_opt < -M_PI) {
|
||||||
|
*angle_opt += 2 * M_PI;
|
||||||
|
}
|
||||||
|
// do not store zero
|
||||||
|
if (std::fabs(*angle_opt) < std::numeric_limits<float>::epsilon())
|
||||||
|
angle_opt.reset();
|
||||||
|
|
||||||
|
// set into activ style
|
||||||
|
if (m_font_manager.is_activ_font()) {
|
||||||
|
m_font_manager.get_font_prop().angle = angle_opt;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (mouse_event.LeftUp()) {
|
} else if (mouse_event.LeftUp()) {
|
||||||
if (m_dragging) {
|
// apply rotation
|
||||||
// apply rotation
|
m_parent.do_rotate(L("Text-Rotate"));
|
||||||
m_parent.do_rotate(L("Text-Rotate"));
|
start_angle.reset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -252,7 +278,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||||||
|
|
||||||
const FontProp& font_prop = m_volume->text_configuration->font_item.prop;
|
const FontProp& font_prop = m_volume->text_configuration->font_item.prop;
|
||||||
if (font_prop.angle.has_value()) {
|
if (font_prop.angle.has_value()) {
|
||||||
double angle_z = M_PI / 180.0 * (*font_prop.angle);
|
double angle_z = *font_prop.angle;
|
||||||
trmat *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ());
|
trmat *= Eigen::AngleAxisd(angle_z, Vec3d::UnitZ());
|
||||||
}
|
}
|
||||||
if (font_prop.distance.has_value()) {
|
if (font_prop.distance.has_value()) {
|
||||||
@ -1308,19 +1334,19 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
if (m_imgui->slider_optional_float(_u8L("Italic [Skew ratio]").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("Italic strength ratio")))
|
if (m_imgui->slider_optional_float(_u8L("Italic [Skew ratio]").c_str(), font_prop.skew, -1.f, 1.f, "%.2f", 1.f, false, _L("Italic strength ratio")))
|
||||||
exist_change = true;
|
exist_change = true;
|
||||||
|
|
||||||
// Property of text configuration
|
|
||||||
FontProp &tc_prop = m_volume->text_configuration->font_item.prop;
|
|
||||||
|
|
||||||
float prev_distance = font_prop.distance.has_value() ?
|
float prev_distance = font_prop.distance.has_value() ?
|
||||||
*font_prop.distance : .0f;
|
*font_prop.distance : .0f;
|
||||||
float min_distance = -2 * font_prop.emboss,
|
float min_distance = -2 * font_prop.emboss,
|
||||||
max_distance = 2 * font_prop.emboss;
|
max_distance = 2 * font_prop.emboss;
|
||||||
ImGui::SetNextItemWidth(item_width);
|
ImGui::SetNextItemWidth(item_width);
|
||||||
if (m_imgui->slider_optional_float(_u8L("Surface distance").c_str(), font_prop.distance,
|
if (m_imgui->slider_optional_float(_u8L("Surface distance").c_str(), font_prop.distance,
|
||||||
min_distance, max_distance, "%.2f mm", 1.f, false, _L("Distance from model surface"))) {
|
min_distance, max_distance, "%.2f mm", 1.f, false, _L("Distance from model surface")) &&
|
||||||
|
m_volume != nullptr && m_volume->text_configuration.has_value()) {
|
||||||
|
|
||||||
|
FontProp& tc_prop = m_volume->text_configuration->font_item.prop;
|
||||||
tc_prop.distance = font_prop.distance;
|
tc_prop.distance = font_prop.distance;
|
||||||
float act_distance = font_prop.distance.has_value() ?
|
|
||||||
*font_prop.distance : .0f;
|
float act_distance = font_prop.distance.has_value() ? *font_prop.distance : .0f;
|
||||||
float diff = act_distance - prev_distance;
|
float diff = act_distance - prev_distance;
|
||||||
Vec3d displacement_rot = Vec3d::UnitZ() * diff;
|
Vec3d displacement_rot = Vec3d::UnitZ() * diff;
|
||||||
|
|
||||||
@ -1335,23 +1361,35 @@ void GLGizmoEmboss::draw_advanced()
|
|||||||
m_parent.do_move(snapshot_name);
|
m_parent.do_move(snapshot_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
float prev_angle = font_prop.angle.has_value() ? *font_prop.angle : .0f;
|
std::optional<float> &angle = font_prop.angle;
|
||||||
|
float prev_angle = angle.has_value() ? *angle : .0f;
|
||||||
|
float angle_deg = prev_angle * 180 / M_PI;
|
||||||
ImGui::SetNextItemWidth(item_width);
|
ImGui::SetNextItemWidth(item_width);
|
||||||
if (m_imgui->slider_optional_float(_u8L("Angle").c_str(), font_prop.angle,
|
if (m_imgui->slider_float(_u8L("Angle").c_str(), &angle_deg,
|
||||||
-180.f, 180.f, u8"%.2f °", 1.f, false, _L("Rotation of text"))) {
|
-180.f, 180.f, u8"%.2f °", 1.f, false, _L("Rotation of text")) ){
|
||||||
tc_prop.angle = font_prop.angle;
|
if (std::fabs(angle_deg) < std::numeric_limits<float>::epsilon()) {
|
||||||
float act_angle = font_prop.angle.has_value() ? *font_prop.angle : .0f;
|
angle.reset();
|
||||||
float diff = act_angle-prev_angle;
|
} else {
|
||||||
|
// convert to radians
|
||||||
|
angle = angle_deg * M_PI / 180.0;
|
||||||
|
}
|
||||||
|
if (m_volume != nullptr && m_volume->text_configuration.has_value()) {
|
||||||
|
m_volume->text_configuration->font_item.prop.angle = angle;
|
||||||
|
float act_angle = angle.has_value() ? *angle : .0f;
|
||||||
|
float diff = act_angle - prev_angle;
|
||||||
|
|
||||||
Selection &selection = m_parent.get_selection();
|
Selection &selection = m_parent.get_selection();
|
||||||
selection.start_dragging();
|
selection.start_dragging();
|
||||||
selection.rotate(Vec3d(0., 0., M_PI / 180.0 * diff), TransformationType::Local);
|
selection.rotate(Vec3d(0., 0., diff),
|
||||||
selection.stop_dragging();
|
TransformationType::Local);
|
||||||
|
selection.stop_dragging();
|
||||||
|
|
||||||
std::string snapshot_name; // empty meand no store undo / redo
|
std::string snapshot_name; // empty meand no store undo / redo
|
||||||
// NOTE: it use L instead of _L macro because prefix _ is appended inside function do_move
|
// NOTE: it use L instead of _L macro because prefix _ is appended
|
||||||
//snapshot_name = L("Set surface distance");
|
// inside function do_move
|
||||||
m_parent.do_rotate(snapshot_name);
|
// snapshot_name = L("Set surface distance");
|
||||||
|
m_parent.do_rotate(snapshot_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// when more collection add selector
|
// when more collection add selector
|
||||||
|
Loading…
x
Reference in New Issue
Block a user