ENH:fix text coordinate system calculation

jira: STUDIO-6449
Change-Id: I36214c14c348e8f52b96501cd027205819b0dabc
(cherry picked from commit 44287812a0cb212f1bf6fe70e32e1075f532886d)
This commit is contained in:
zhou.xu 2024-08-07 11:22:42 +08:00 committed by Lane.Wei
parent 92c85a13d0
commit 4091f3e042
16 changed files with 466 additions and 325 deletions

View File

@ -808,5 +808,16 @@ Geometry::TransformationSVD::TransformationSVD(const Transform3d &trafo)
return curMat;
}
Transformation generate_transform(const Vec3d& x_dir, const Vec3d& y_dir, const Vec3d& z_dir, const Vec3d& origin) {
Matrix3d m;
m.col(0) = x_dir.normalized();
m.col(1) = y_dir.normalized();
m.col(2) = z_dir.normalized();
Transform3d mm(m);
Transformation tran(mm);
tran.set_offset(origin);
return tran;
}
} // namespace Geometry
} // namespace Slic3r

View File

@ -494,6 +494,7 @@ inline bool is_rotation_ninety_degrees(const Vec3d &rotation)
}
Transformation mat_around_a_point_rotate(const Transformation& innMat, const Vec3d &pt, const Vec3d &axis, float rotate_theta_radian);
Transformation generate_transform(const Vec3d &x_dir, const Vec3d &y_dir, const Vec3d &z_dir, const Vec3d &origin);
} } // namespace Slicer::Geometry
#endif

View File

@ -1193,23 +1193,27 @@ bool ModelObject::make_boolean(ModelObject *cut_object, const std::string &boole
return true;
}
ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
ModelVolume *ModelObject::add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry)
{
ModelVolume* v = new ModelVolume(this, mesh);
this->volumes.push_back(v);
if (modify_to_center_geometry) {
v->center_geometry_after_creation();
this->invalidate_bounding_box();
}
// BBS: backup
Slic3r::save_object_mesh(*this);
return v;
}
ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/)
ModelVolume *ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/, bool modify_to_center_geometry)
{
ModelVolume* v = new ModelVolume(this, std::move(mesh), type);
this->volumes.push_back(v);
if (modify_to_center_geometry) {
v->center_geometry_after_creation();
this->invalidate_bounding_box();
}
// BBS: backup
Slic3r::save_object_mesh(*this);
return v;

View File

@ -399,8 +399,8 @@ public:
return global_config.option<T>(config_option);
}
ModelVolume* add_volume(const TriangleMesh &mesh);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART);
ModelVolume* add_volume(const TriangleMesh &mesh, bool modify_to_center_geometry = true);
ModelVolume* add_volume(TriangleMesh &&mesh, ModelVolumeType type = ModelVolumeType::MODEL_PART, bool modify_to_center_geometry = true);
ModelVolume* add_volume(const ModelVolume &volume, ModelVolumeType type = ModelVolumeType::INVALID);
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
ModelVolume* add_volume_with_shared_mesh(const ModelVolume &other, ModelVolumeType type = ModelVolumeType::MODEL_PART);
@ -828,7 +828,6 @@ struct TextInfo
std::string m_text;
RaycastResult m_rr;
Vec3d m_hit_in_text; // for load use
template<typename Archive> void serialize(Archive &ar) {
ar(m_font_name, m_font_size, m_curr_font_idx, m_bold, m_italic, m_thickness, m_embeded_depth, m_rotate_angle, m_text_gap, m_is_surface_text, m_keep_horizontal, m_text, m_rr);
}

View File

@ -4616,30 +4616,6 @@ void GLCanvas3D::set_tooltip(const std::string& tooltip)
m_tooltip.set_text(tooltip);
}
void GLCanvas3D::generate_new_hit_in_text_info(ModelVolume * cur_mv,
ModelObject * model_object,
ModelInstance * mi,
const Transform3d &old_text_world_tran,
const Transform3d &cur_text_world_tran,
TextInfo * text_info,
int type)
{
Geometry::Transformation old_text_tran_(old_text_world_tran);
Geometry::Transformation cur_text_tran_(cur_text_world_tran);
bool is_changed = (type == 0 && old_text_tran_.get_offset() != cur_text_tran_.get_offset()) ||//move
(type == 1 && old_text_tran_.get_rotation() != cur_text_tran_.get_rotation()) ||// rotate
(type == 2 && old_text_tran_.get_scaling_factor() != cur_text_tran_.get_scaling_factor());
if (is_changed) {
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume *mv : model_object->volumes) {
if (mv->is_model_part()) { trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix()); }
}
if (text_info->m_rr.mesh_id < trafo_matrices.size()) {
text_info->m_rr.hit = (trafo_matrices[text_info->m_rr.mesh_id].inverse() * (cur_text_world_tran * text_info->m_hit_in_text)).cast<float>();
}
}
}
void GLCanvas3D::do_move(const std::string &snapshot_type)
{
if (m_model == nullptr)
@ -4682,18 +4658,7 @@ void GLCanvas3D::do_move(const std::string &snapshot_type)
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_offset() != v->get_volume_offset()) {
auto text_info = const_cast<TextInfo *>(&cur_mv->get_text_info());
auto mi = model_object->instances[instance_idx];
Transform3d old_text_world_tran;
bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0;
if (is_text_mv) { // deal text_info
old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
}
cur_mv->set_offset(v->get_volume_offset());
if (is_text_mv) { // deal text_info
auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 0);
}
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@ -4806,19 +4771,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_rotation() != v->get_volume_rotation()) {
auto text_info = const_cast<TextInfo *>(&cur_mv->get_text_info());
auto mi = model_object->instances[instance_idx];
Transform3d old_text_world_tran;
bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0;
if (is_text_mv) { // deal text_info
old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
}
cur_mv->set_transformation(v->get_volume_transformation());
if (is_text_mv) { // deal text_info
auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 1);
}
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
@ -4899,21 +4852,8 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_scaling_factor() != v->get_volume_scaling_factor()) {
auto text_info = const_cast<TextInfo *>(&cur_mv->get_text_info());
auto mi = model_object->instances[instance_idx];
Transform3d old_text_world_tran;
bool is_text_mv = text_info && !text_info->m_text.empty() && text_info->m_rr.mesh_id >= 0;
if (is_text_mv) { // deal text_info
old_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
}
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
if (is_text_mv) { // deal text_info
auto cur_text_world_tran = mi->get_transformation().get_matrix() * cur_mv->get_matrix();
generate_new_hit_in_text_info(cur_mv, model_object, mi, old_text_world_tran, cur_text_world_tran, text_info, 2);
}
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}

View File

@ -952,8 +952,6 @@ public:
void set_tooltip(const std::string& tooltip);
// the following methods add a snapshot to the undo/redo stack, unless the given string is empty
void generate_new_hit_in_text_info(ModelVolume *cur_mv, ModelObject *model_object,ModelInstance *mi,
const Transform3d &old_text_world_tran, const Transform3d &cur_text_world_tran, TextInfo *text_info,int type);
void do_move(const std::string& snapshot_type);
void do_rotate(const std::string& snapshot_type);
void do_scale(const std::string& snapshot_type);

View File

@ -2361,6 +2361,55 @@ int ObjectList::load_mesh_part(const TriangleMesh &mesh, const wxString &name, c
return mo->volumes.size() - 1;
}
int GUI::ObjectList::add_text_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, const Transform3d &text_in_object_tran, bool is_temp)
{
wxDataViewItem item = GetSelection();
// we can add volumes for Object or Instance
if (!item || !(m_objects_model->GetItemType(item) & (itObject | itInstance)))
return -1;
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
if (obj_idx < 0)
return -1;
// Get object item, if Instance is selected
if (m_objects_model->GetItemType(item) & itInstance)
item = m_objects_model->GetItemById(obj_idx);
ModelObject *mo = (*m_objects)[obj_idx];
Geometry::Transformation instance_transformation = mo->instances[0]->get_transformation();
ModelVolume *mv = mo->add_volume(mesh,false);
mv->set_transformation(text_in_object_tran);
mo->invalidate_bounding_box();
mv->name = name.ToStdString();
if (!text_info.m_text.empty())
mv->set_text_info(text_info);
if (!is_temp) {
std::vector<ModelVolume *> volumes;
volumes.push_back(mv);
wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [volumes](const ModelVolume *volume) {
return std::find(volumes.begin(), volumes.end(), volume) != volumes.end();
});
wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_object((size_t) obj_idx);
if (items.size() > 1) {
m_selection_mode = smVolume;
m_last_selected_item = wxDataViewItem(nullptr);
}
select_items(items);
selection_changed();
}
// BBS: notify partplate the modify
notify_instance_updated(obj_idx);
return mo->volumes.size() - 1;
}
//BBS
bool ObjectList::del_object(const int obj_idx, bool refresh_immediately)
{

View File

@ -291,6 +291,7 @@ public:
// BBS
void switch_to_object_process();
int load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool is_temp);
int add_text_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info,const Transform3d& text_in_object_tran, bool is_temp);
bool del_object(const int obj_idx, bool refresh_immediately = true);
void del_subobject_item(wxDataViewItem& item);
void del_settings_from_config(const wxDataViewItem& parent_item);

View File

@ -489,6 +489,22 @@ void GLGizmoRotate3D::on_set_state()
g.set_state(m_state);
if (get_state() == On && m_object_manipulation) {
m_object_manipulation->set_coordinates_type(ECoordinatesType::World);
m_last_volume = nullptr;
}
}
void GLGizmoRotate3D::data_changed(bool is_serializing) {
const Selection &selection = m_parent.get_selection();
const GLVolume * volume = selection.get_first_volume();
if (m_last_volume != volume) {
m_last_volume = volume;
Geometry::Transformation tran;
if (selection.is_single_full_instance()) {
tran = volume->get_instance_transformation();
} else {
tran = volume->get_volume_transformation();
}
m_object_manipulation->set_init_rotation(tran);
}
}

View File

@ -137,6 +137,7 @@ protected:
if (id < 3)
m_gizmos[id].disable_grabber(0);
}
void data_changed(bool is_serializing) override;
bool on_is_activable() const override;
void on_start_dragging() override;
void on_stop_dragging() override;
@ -157,7 +158,7 @@ protected:
void on_render_input_window(float x, float y, float bottom_limit) override;
private:
const GLVolume *m_last_volume;
class RotoptimzeWindow {
ImGuiWrapper *m_imgui = nullptr;
public:

View File

@ -38,7 +38,16 @@ static const int FONT_SIZE = 12;
static const float SELECTABLE_INNER_OFFSET = 8.0f;
static const wxFontEncoding font_encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
const std::array<float, 4> TEXT_GRABBER_COLOR = {1.0, 1.0, 0.0, 1.0};
const std::array<float, 4> TEXT_GRABBER_HOVER_COLOR = {0.7, 0.7, 0.0, 1.0};
#ifdef DEBUG_TEXT
std::string formatFloat(float val)
{
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << val;
return ss.str();
}
#endif
std::vector<std::string> init_face_names()
{
std::vector<std::string> valid_font_names;
@ -216,7 +225,6 @@ bool GLGizmoText::on_init()
m_desc["rotate_text_caption"] = _L("Shift + Mouse move up or down");
m_desc["rotate_text"] = _L("Rotate text");
m_grabbers.push_back(Grabber());
return true;
}
@ -285,15 +293,12 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit
if (text.empty())
return true;
const ModelObject * mo = m_c->selection_info()->model_object();
if (m_is_modify) {
const Selection &selection = m_parent.get_selection();
mo = selection.get_model()->objects[m_object_idx];
}
auto mo = selection.get_model()->objects[m_object_idx];
if (mo == nullptr)
return true;
const Selection & selection = m_parent.get_selection();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Camera & camera = wxGetApp().plater()->get_camera();
@ -376,10 +381,10 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit
if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero())
return true;
m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_normal};
m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_normal};//left down
m_is_modify = true;
generate_text_volume(false);
m_is_modify = true;
plater->update();
}
@ -389,18 +394,13 @@ bool GLGizmoText::gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_posit
void GLGizmoText::on_set_state()
{
if (m_state == EState::On) {
if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) {
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(m_object_idx, m_volume_idx);
if (model_volume) {
TextInfo text_info = model_volume->get_text_info();
if (!text_info.m_text.empty()) {
load_from_text_info(text_info);
m_is_modify = true;
}
}
}
m_last_text_mv = nullptr;
m_need_fix = false;
load_init_text();
}
else if (m_state == EState::Off) {
m_show_warning = false;
m_edit_text_again = false;
reset_text_info();
delete_temp_preview_text_volume();
m_parent.use_slope(false);
@ -408,6 +408,59 @@ void GLGizmoText::on_set_state()
}
}
void GLGizmoText::load_init_text()
{
Plater *plater = wxGetApp().plater();
if (m_parent.get_selection().is_single_volume() || m_parent.get_selection().is_single_modifier()) {
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(m_object_idx, m_volume_idx);
if (model_volume) {
TextInfo text_info = model_volume->get_text_info();
if (!text_info.m_text.empty()) {
if (m_last_text_mv == model_volume) {
m_last_text_mv = model_volume;
return;
}
m_need_fix = false;
if (plater) {
plater->take_snapshot("enter Text");
}
m_last_text_mv = model_volume;
load_from_text_info(text_info);
m_edit_text_again = true;
m_text_volume_tran = model_volume->get_matrix();
m_text_tran_in_object.set_matrix(m_text_volume_tran);
int temp_object_idx;
auto mo = m_parent.get_selection().get_selected_single_object(temp_object_idx);
const ModelInstance *mi = mo->instances[m_parent.get_selection().get_instance_idx()];
auto world_tran = mi->get_transformation().get_matrix() * m_text_volume_tran;
m_text_tran_in_world.set_matrix(world_tran);
m_text_position_in_world = m_text_tran_in_world.get_offset();
m_text_normal_in_world = -m_text_tran_in_world.get_matrix().linear().col(1).cast<float>();
{
TriangleMesh text_attach_mesh(mo->volumes[m_rr.mesh_id]->mesh());
text_attach_mesh.transform(mo->volumes[m_rr.mesh_id]->get_matrix());
MeshRaycaster temp_ray_caster(text_attach_mesh);
Vec3f local_center = m_text_tran_in_object.get_offset().cast<float>();
Vec3f temp_normal;
Vec3f closest_pt = temp_ray_caster.get_closest_point(local_center, &temp_normal);
m_fix_text_position_in_world = mi->get_transformation().get_matrix() * closest_pt.cast<double>();
m_fix_text_normal_in_world = (mi->get_transformation().get_matrix_no_offset().cast<float>() * temp_normal).normalized();
if ((m_fix_text_position_in_world - m_text_position_in_world).norm() > 0.1) {
m_need_fix = true;
}
}
// m_rr.mesh_id
m_need_update_text = false;
m_is_modify = true;
}
}
}
}
void GLGizmoText::data_changed(bool is_serializing) {
load_init_text();
m_rr.normal = Vec3f::Zero();
}
CommonGizmosDataID GLGizmoText::on_get_requirements() const
{
return CommonGizmosDataID(
@ -453,31 +506,54 @@ void GLGizmoText::on_render()
}
ModelObject *mo = nullptr;
mo = m_c->selection_info()->model_object();
if (mo == nullptr) {
const Selection &selection = m_parent.get_selection();
mo = selection.get_model()->objects[m_object_idx];
}
if (mo == nullptr) {
BOOST_LOG_TRIVIAL(info) << boost::format("Text: selected object is null");
return;
}
// First check that the mouse pointer is on an object.
const Selection & selection = m_parent.get_selection();
const ModelInstance *mi = mo->instances[0];
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
Plater *plater = wxGetApp().plater();
if (!plater)
return;
#ifdef DEBUG_TEXT
if (m_text_normal_in_world.norm() > 0.1) { // debug
Geometry::Transformation tran(m_text_volume_tran);
if (tran.get_offset().norm() > 1) {
auto text_volume_tran_world = mi->get_transformation().get_matrix() * m_text_volume_tran;
glsafe(::glPushMatrix());
glsafe(::glMultMatrixd(text_volume_tran_world.data()));
render_cross_mark(Vec3f::Zero(), true);
glsafe(::glPopMatrix());
}
if (!m_is_modify || m_shift_down) {
glsafe(::glPushMatrix());
glsafe(::glMultMatrixd(m_text_tran_in_world.get_matrix().data()));
render_cross_mark(Vec3f::Zero(), true);
glsafe(::glPopMatrix());
glsafe(::glLineWidth(2.0f));
::glBegin(GL_LINES);
glsafe(::glColor3f(1.0f, 0.0f, 0.0f));
for (size_t i = 1; i < m_cut_points_in_world.size(); i++) {//draw points
auto target0 = m_cut_points_in_world[i - 1].cast<float>();
auto target1 = m_cut_points_in_world[i].cast<float>();
glsafe(::glVertex3f(target0(0), target0(1), target0(2)));
glsafe(::glVertex3f(target1(0), target1(1), target1(2)));
}
glsafe(::glEnd());
}
#endif
if (!m_is_modify || m_shift_down) {//for temp text
const Camera &camera = wxGetApp().plater()->get_camera();
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
if (mv->is_model_part())
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
}
// Raycast and return if there's no hit.
Vec2d mouse_pos;
@ -500,25 +576,32 @@ void GLGizmoText::on_render()
if (!position_changed && !m_need_update_text && !m_shift_down)
return;
update_text_pos_normal();
}
if (m_is_modify && m_grabbers.size() == 1) {
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) {
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
if (m_is_modify) {
update_text_pos_normal();
Geometry::Transformation tran;//= m_text_tran_in_world;
{
double phi;
Vec3d rotation_axis;
Matrix3d rotation_matrix;
Geometry::rotation_from_two_vectors(Vec3d::UnitZ(), m_text_normal_in_world.cast<double>(), rotation_axis, phi, &rotation_matrix);
tran.set_matrix((Transform3d) rotation_matrix);
}
}
m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2));
float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize);
m_grabbers[0].center = m_mouse_position_world;
m_grabbers[0].enabled = true;
std::array<float, 4> color = picking_color_component(0);
m_grabbers[0].color = color;
m_grabbers[0].render_for_picking(mean_size);
tran.set_offset(m_text_position_in_world);
bool hover = (m_hover_id == m_move_cube_id);
std::array<float, 4> render_color;
if (hover) {
render_color = TEXT_GRABBER_HOVER_COLOR;
} else
render_color = TEXT_GRABBER_COLOR;
float fullsize = 8.0f;
if (GLGizmoBase::INV_ZOOM > 0) { fullsize = m_move_grabber.FixedGrabberSize * GLGizmoBase::INV_ZOOM; }
m_move_grabber.center = tran.get_offset();
Transform3d rotate_matrix = tran.get_rotation_matrix();
Transform3d cube_mat = Geometry::translation_transform(m_move_grabber.center) * rotate_matrix * Geometry::scale_transform(fullsize);
render_glmodel(m_move_grabber.get_cube(), render_color, cube_mat);
}
delete_temp_preview_text_volume();
@ -537,48 +620,37 @@ void GLGizmoText::on_render_for_picking()
int obejct_idx, volume_idx;
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(obejct_idx, volume_idx);
if (model_volume && !model_volume->get_text_info().m_text.empty()) {
if (m_grabbers.size() == 1) {
ModelObject *mo = m_c->selection_info()->model_object();
if (m_is_modify) {
const Selection &selection = m_parent.get_selection();
mo = selection.get_model()->objects[m_object_idx];
}
if (mo == nullptr) return;
const Selection & selection = m_parent.get_selection();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) {
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
}
}
m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2));
auto mo = selection.get_model()->objects[m_object_idx];
if (mo == nullptr)
return;
auto color = picking_color_component(m_move_cube_id);
m_move_grabber.color[0] = color[0];
m_move_grabber.color[1] = color[1];
m_move_grabber.color[2] = color[2];
m_move_grabber.color[3] = color[3];
float mean_size = (float) (GLGizmoBase::Grabber::FixedGrabberSize);
m_grabbers[0].center = m_mouse_position_world;
m_grabbers[0].enabled = true;
std::array<float, 4> color = picking_color_component(0);
m_grabbers[0].color = color;
m_grabbers[0].render_for_picking(mean_size);
m_move_grabber.render_for_picking(mean_size);
}
}
void GLGizmoText::on_start_dragging()
{
}
void GLGizmoText::on_stop_dragging()
{
}
void GLGizmoText::on_update(const UpdateData &data)
{
Vec2d mouse_pos = Vec2d(data.mouse_pos.x(), data.mouse_pos.y());
const ModelObject *mo = m_c->selection_info()->model_object();
if (m_is_modify) {
const Selection &selection = m_parent.get_selection();
mo = selection.get_model()->objects[m_object_idx];
}
if (mo == nullptr) return;
const Selection &selection = m_parent.get_selection();
auto mo = selection.get_model()->objects[m_object_idx];
if (mo == nullptr)
return;
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
const Camera & camera = wxGetApp().plater()->get_camera();
@ -621,7 +693,7 @@ void GLGizmoText::on_update(const UpdateData &data)
if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero()) return;
if (closest_hit_mesh_id != -1) {
m_rr = {mouse_pos, closest_hit_mesh_id, closest_hit, closest_normal};
m_rr = {mouse_pos, closest_hit_mesh_id, closest_hit, closest_normal};//on drag
m_need_update_text = true;
}
}
@ -724,9 +796,9 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit)
ModelVolume *model_volume = m_parent.get_selection().get_selected_single_volume(object_idx, volume_idx);
if ((object_idx != m_object_idx || (object_idx == m_object_idx && volume_idx != m_volume_idx))
&& model_volume) {
m_hit_in_text = Vec3d::Zero();
m_last_text_mv = model_volume;
TextInfo text_info = model_volume->get_text_info();
load_from_text_info(text_info);
load_from_text_info(text_info);//mouse click down
m_is_modify = true;
m_volume_idx = volume_idx;
m_object_idx = object_idx;
@ -745,7 +817,14 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit)
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0,5.0) * currt_scale);
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 4.0f * currt_scale);
GizmoImguiBegin("Text", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
#ifdef DEBUG_TEXT
std::string hit = "hit x:" + formatFloat(m_rr.hit[0]) + " y:" + formatFloat(m_rr.hit[1]) + " z:" + formatFloat(m_rr.hit[2]);
std::string normal = "normal x:" + formatFloat(m_rr.normal[0]) + " y:" + formatFloat(m_rr.normal[1]) + " z:" + formatFloat(m_rr.normal[2]);
auto cut_dir = "cut_dir x:" + formatFloat(m_cut_plane_dir_in_world[0]) + " y:" + formatFloat(m_cut_plane_dir_in_world[1]) + " z:" + formatFloat(m_cut_plane_dir_in_world[2]);
m_imgui->text(hit);
m_imgui->text(normal);
m_imgui->text(cut_dir);
#endif
float space_size = m_imgui->get_style_scaling() * 8;
float font_cap = m_imgui->calc_text_size(_L("Font")).x;
float size_cap = m_imgui->calc_text_size(_L("Size")).x;
@ -899,7 +978,13 @@ void GLGizmoText::on_render_input_window(float x, float y, float bottom_limit)
if(ImGui::InputText("", m_text, sizeof(m_text)))
m_need_update_text = true;
std::string text = std::string(m_text);
if (text.empty() && m_is_modify) {
m_imgui->warning_text(_L("Warning:Input cannot be empty!"));
}
if (m_show_warning) {
m_imgui->warning_text(_L("Warning:create text fail."));
}
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
@ -987,11 +1072,39 @@ void GLGizmoText::reset_text_info()
m_text_gap = 0.f;
m_is_surface_text = true;
m_keep_horizontal = false;
m_rr = RaycastResult();
m_is_modify = false;
}
void GLGizmoText::update_font_status() {
void GLGizmoText::update_text_pos_normal() {
if (m_rr.mesh_id < 0) { return; }
if (m_rr.normal.norm() < 0.1) { return; }
const Selection &selection = m_parent.get_selection();
auto mo = selection.get_model()->objects[m_object_idx];
if (mo == nullptr) {
BOOST_LOG_TRIVIAL(info) << boost::format("Text: selected object is null");
return;
}
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
std::vector<Geometry::Transformation> w_matrices;
std::vector<Geometry::Transformation> mv_trans;
for (const ModelVolume *mv : mo->volumes) {
if (mv->is_model_part()) {
w_matrices.emplace_back(Geometry::Transformation(mi->get_transformation().get_matrix() * mv->get_matrix()));
mv_trans.emplace_back(Geometry::Transformation(mv->get_matrix()));
}
}
#ifdef DEBUG_TEXT_VALUE
m_rr.hit = Vec3f(-0.58, -1.70, -12.8);
m_rr.normal = Vec3f(0,0,-1);//just rotate cube
#endif
m_text_position_in_world = w_matrices[m_rr.mesh_id].get_matrix() * m_rr.hit.cast<double>();
m_text_normal_in_world = (w_matrices[m_rr.mesh_id].get_matrix_no_offset().cast<float>() * m_rr.normal).normalized();
}
void GLGizmoText::update_font_status()
{
std::unique_lock<std::mutex> lock(m_mutex);
m_font_status.reserve(m_avail_font_names.size());
for (std::string font_name : m_avail_font_names) {
@ -1023,17 +1136,13 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
int text_num = texts.size();
m_position_points.clear();
m_normal_points.clear();
ModelObject *mo = m_c->selection_info()->model_object();
if (m_is_modify) {
const Selection &selection = m_parent.get_selection();
mo = selection.get_model()->objects[m_object_idx];
}
auto mo = selection.get_model()->objects[m_object_idx];
if (mo == nullptr)
return false;
const Selection & selection = m_parent.get_selection();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
m_model_object_in_world_tran = mi->get_transformation();
// Precalculate transformations of individual meshes.
std::vector<Transform3d> trafo_matrices;
std::vector<Transform3d> rotate_trafo_matrices;
@ -1048,9 +1157,18 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
BOOST_LOG_TRIVIAL(info) << boost::format("Text: mrr_mesh_id is -1");
return false;
}
m_mouse_position_world = trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2));
m_mouse_normal_world = rotate_trafo_matrices[m_rr.mesh_id] * Vec3d(m_rr.normal(0), m_rr.normal(1), m_rr.normal(2));
if (m_text_normal_in_world.norm() < 0.1) {
BOOST_LOG_TRIVIAL(info) << "m_text_normal_in_object is error";
return false;
}
// mouse_position_world may is error after user modified
if (m_need_fix) {
m_need_fix = false;
m_text_position_in_world = m_fix_text_position_in_world;
m_text_normal_in_world = m_fix_text_normal_in_world;
}
auto mouse_position_world = m_text_position_in_world.cast<double>();
auto mouse_normal_world = m_text_normal_in_world.cast<double>();
TriangleMesh slice_meshs;
int mesh_index = 0;
@ -1074,34 +1192,27 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
ModelVolume* volume = mo->volumes[volume_index];
Vec3d temp_position = m_mouse_position_world;
Vec3d temp_normal = m_mouse_normal_world;
Vec3d cut_plane = Vec3d::UnitY();
Vec3d temp_normal = m_text_normal_in_world.cast<double>();
Vec3d cut_plane_in_world = Vec3d::UnitY();
double epson = 1e-6;
if (!(abs(temp_normal.x()) <= epson && abs(temp_normal.y()) <= epson && abs(temp_normal.z()) > epson)) { // temp_normal != Vec3d::UnitZ()
Vec3d v_plane = temp_normal.cross(Vec3d::UnitZ());
cut_plane = v_plane.cross(temp_normal);
cut_plane_in_world = v_plane.cross(temp_normal);
}
Transform3d rotate_trans;
rotate_trans.setIdentity();
rotate_trans.rotate(Eigen::AngleAxisd(Geometry::deg2rad(m_rotate_angle), temp_normal));
cut_plane = rotate_trans * cut_plane;
m_cut_plane_dir_in_world = cut_plane_in_world;
m_cut_plane_dir = cut_plane;
if (m_keep_horizontal && m_mouse_normal_world != Vec3d::UnitZ())
m_cut_plane_dir = Vec3d::UnitZ();
if (m_keep_horizontal && mouse_normal_world != Vec3d::UnitZ())
m_cut_plane_dir_in_world = Vec3d::UnitZ();
if (!m_is_surface_text) {
m_position_points.resize(text_num);
m_normal_points.resize(text_num);
Vec3d pos_dir = m_cut_plane_dir.cross(m_mouse_normal_world);
Vec3d pos_dir = m_cut_plane_dir_in_world.cross(mouse_normal_world);
pos_dir.normalize();
if (text_num % 2 == 1) {
m_position_points[text_num / 2] = m_mouse_position_world;
m_position_points[text_num / 2] = mouse_position_world;
for (int i = 0; i < text_num / 2; ++i) {
double left_gap = text_lengths[text_num / 2 - i - 1] + m_text_gap + text_lengths[text_num / 2 - i];
if (left_gap < 0)
@ -1127,8 +1238,8 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
right_gap = 0;
if (i == 0) {
m_position_points[text_num / 2 - 1 - i] = m_mouse_position_world - left_gap * pos_dir;
m_position_points[text_num / 2 + i] = m_mouse_position_world + right_gap * pos_dir;
m_position_points[text_num / 2 - 1 - i] = mouse_position_world - left_gap * pos_dir;
m_position_points[text_num / 2 + i] = mouse_position_world + right_gap * pos_dir;
continue;
}
@ -1138,51 +1249,36 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
}
for (int i = 0; i < text_num; ++i) {
m_normal_points[i] = m_mouse_normal_world;
m_normal_points[i] = mouse_normal_world;
}
return true;
}
auto y_dir = -m_text_normal_in_world.cast<double>();
Vec3d x_dir_world = y_dir.cross(m_cut_plane_dir_in_world);
m_text_tran_in_world = Geometry::generate_transform(x_dir_world, y_dir, m_cut_plane_dir_in_world.cast<double>(), m_text_position_in_world);
Geometry::Transformation rotate_trans;
rotate_trans.set_rotation(Vec3d(0, Geometry::deg2rad(m_rotate_angle), 0)); //m_rotate_angle
m_text_tran_in_world.set_matrix(m_text_tran_in_world.get_matrix() * rotate_trans.get_matrix());
m_cut_plane_dir_in_world = m_text_tran_in_world.get_matrix().linear().col(2);
double phi;
Vec3d rotation_axis;
Matrix3d rotation_matrix;
Geometry::rotation_from_two_vectors(m_cut_plane_dir, Vec3d::UnitZ(), rotation_axis, phi, &rotation_matrix);
if (abs(phi - PI) < 1e-6) {
Transform3d transform = Transform3d::Identity();
transform.rotate(Eigen::AngleAxisd(phi, m_mouse_normal_world));
rotation_matrix = transform.matrix().block<3, 3>(0, 0);
}
// generate clip cs at click pos
auto text_position_in_object = mi->get_transformation().get_matrix().inverse() * m_text_position_in_world.cast<double>();
auto rotate_mat_inv = mi->get_transformation().get_matrix_no_offset().inverse();
Transform3d transfo1;
transfo1.setIdentity();
transfo1.translate(-(mi->get_transformation().get_offset() + volume->get_transformation().get_offset()));
transfo1 = rotation_matrix * transfo1;
Transform3d transfo2;
transfo2.setIdentity();
transfo2.translate(mi->get_transformation().get_offset() + volume->get_transformation().get_offset());
Transform3d transfo = transfo2 * transfo1;
Vec3d click_point = transfo * temp_position;
auto text_tran_in_object = mi->get_transformation().get_matrix().inverse() * m_text_tran_in_world.get_matrix(); // Geometry::generate_transform(cs_x_dir, cs_y_dir, cs_z_dir, text_position_in_object); // todo modify by m_text_tran_in_world
m_text_tran_in_object.set_matrix(text_tran_in_object);
m_text_cs_to_world_tran = mi->get_transformation().get_matrix() * m_text_tran_in_object.get_matrix();
MeshSlicingParams slicing_params;
slicing_params.trafo = transfo * mi->get_transformation().get_matrix() /** volume->get_transformation().get_matrix()*/;
slicing_params.trafo = m_text_tran_in_object.get_matrix().inverse();
// for debug
// its_write_obj(slice_meshs.its, "D:/debug_files/mesh.obj");
// generate polygons
const Polygons temp_polys = slice_mesh(slice_meshs.its, click_point.z(), slicing_params);
m_mouse_position_world = click_point;
m_mouse_normal_world = transfo * temp_normal;
m_mouse_position_world.x() *= 1e6;
m_mouse_position_world.y() *= 1e6;
const Polygons temp_polys = slice_mesh(slice_meshs.its, 0, slicing_params);
Vec3d scale_click_pt(scale_(0), scale_(0), 0);
// for debug
//export_regions_to_svg(Point(m_mouse_position_world.x(), m_mouse_position_world.y()), temp_polys);
// export_regions_to_svg(Point(scale_pt.x(), scale_pt.y()), temp_polys);
Polygons polys = union_(temp_polys);
auto point_in_line_rectange = [](const Line &line, const Point &point, double& distance) {
@ -1201,7 +1297,7 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
for (int i = 0; i < lines.size(); ++i) {
Line line = lines[i];
double distance = min_distance;
if (point_in_line_rectange(line, Point(m_mouse_position_world.x(), m_mouse_position_world.y()), distance)) {
if (point_in_line_rectange(line, Point(scale_click_pt.x(), scale_click_pt.y()), distance)) {
if (distance < min_distance) {
min_distance = distance;
index = i;
@ -1216,30 +1312,22 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
return false;
}
auto make_trafo_for_slicing = [](const Transform3d &trafo) -> Transform3d {
auto t = trafo;
static constexpr const double s = 1. / SCALING_FACTOR;
t.prescale(Vec3d(s, s, 1.));
return t.cast<double>();
};
transfo = make_trafo_for_slicing(transfo);
Transform3d transfo_inv = transfo.inverse();
std::vector<Vec3d> new_points;
m_cut_points_in_world.clear();
m_cut_points_in_world.reserve(hit_ploy.points.size());
for (int i = 0; i < hit_ploy.points.size(); ++i) {
new_points.emplace_back(transfo_inv * Vec3d(hit_ploy.points[i].x(), hit_ploy.points[i].y(), click_point.z()));
m_cut_points_in_world.emplace_back(m_text_cs_to_world_tran * Vec3d(unscale_(hit_ploy.points[i].x()), unscale_(hit_ploy.points[i].y()), 0));
}
m_mouse_position_world = transfo_inv * m_mouse_position_world;
Polygon_3D new_polygon(new_points);
Polygon_3D new_polygon(m_cut_points_in_world);
m_position_points.resize(text_num);
if (text_num % 2 == 1) {
m_position_points[text_num / 2] = Vec3d(m_mouse_position_world.x(), m_mouse_position_world.y(), m_mouse_position_world.z());
m_position_points[text_num / 2] = Vec3d(mouse_position_world.x(), mouse_position_world.y(), mouse_position_world.z());
std::vector<Line_3D> lines = new_polygon.get_lines();
Line_3D line = lines[index];
{
int index1 = index;
double left_length = (m_mouse_position_world - line.a).cast<double>().norm();
double left_length = (mouse_position_world - line.a).cast<double>().norm();
int left_num = text_num / 2;
while (left_num > 0) {
double gap_length = (text_lengths[left_num] + m_text_gap + text_lengths[left_num - 1]);
@ -1273,7 +1361,7 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
{
int index2 = index;
double right_length = (line.b - m_mouse_position_world).cast<double>().norm();
double right_length = (line.b - mouse_position_world).cast<double>().norm();
int right_num = text_num / 2;
while (right_num > 0) {
double gap_length = (text_lengths[text_num - right_num] + m_text_gap + text_lengths[text_num - right_num - 1]);
@ -1313,7 +1401,7 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
Line_3D line = lines[index];
{
int index1 = index;
double left_length = (m_mouse_position_world - line.a).cast<double>().norm();
double left_length = (mouse_position_world - line.a).cast<double>().norm();
int left_num = text_num / 2;
for (int i = 0; i < text_num / 2; ++i) {
double gap_length = 0;
@ -1353,7 +1441,7 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
{
int index2 = index;
double right_length = (line.b - m_mouse_position_world).cast<double>().norm();
double right_length = (line.b - mouse_position_world).cast<double>().norm();
int right_num = text_num / 2;
double gap_length = 0;
for (int i = 0; i < text_num / 2; ++i) {
@ -1412,6 +1500,7 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
return abs(s0 + s1 + s2 - s);
};
bool is_mirrored =m_model_object_in_world_tran.is_left_handed();
for (int i = 0; i < m_position_points.size(); ++i) {
for (auto indice : mesh.its.indices) {
stl_vertex stl_point0 = mesh.its.vertices[indice[0]];
@ -1434,6 +1523,9 @@ bool GLGizmoText::update_text_positions(const std::vector<std::string>& texts)
Vec3d s2 = point2 - point0;
m_normal_points[i] = s1.cross(s2);
m_normal_points[i].normalize();
if(is_mirrored){
m_normal_points[i] = -m_normal_points[i];
}
}
}
}
@ -1446,9 +1538,8 @@ TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &posit
load_text_shape(text_str, m_font_name.c_str(), m_font_size, m_thickness + m_embeded_depth, m_bold, m_italic, text_result);
TriangleMesh mesh = text_result.text_mesh;
auto center = mesh.bounding_box().center();
double mesh_offset = center.z();
mesh.translate(-text_result.text_width / 2, -m_font_size / 4, -center.z());
mesh.translate(-text_result.text_width / 2, -m_font_size / 4, 0);
double phi;
Vec3d rotation_axis;
@ -1471,15 +1562,11 @@ TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &posit
mesh.rotate(phi, rotation_axis);
const Selection & selection = m_parent.get_selection();
ModelObject * model_object = selection.get_model()->objects[m_object_idx];
Geometry::Transformation instance_transformation = model_object->instances[0]->get_transformation();
Vec3d offset = position - instance_transformation.get_offset();
offset = offset + mesh_offset * normal;
offset = offset - m_embeded_depth * normal;
Vec3d offset = position - m_embeded_depth * normal;
mesh.translate(offset.x(), offset.y(), offset.z());
return mesh;
return mesh;//mesh in object cs
}
bool GLGizmoText::update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector<Transform3d> &trafo_matrices)
@ -1520,7 +1607,7 @@ bool GLGizmoText::update_raycast_cache(const Vec2d &mouse_position, const Camera
}
}
m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal};
m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal};//update_raycast_cache berfor click down
return true;
}
@ -1537,20 +1624,22 @@ void GLGizmoText::generate_text_volume(bool is_temp)
alphas.push_back(str_cnv.to_bytes(w));
}
update_text_positions(alphas);
update_text_positions(alphas);//update m_model_object_in_world_tran
if (m_position_points.size() == 0)
return;
auto inv_text_cs_in_object = (m_model_object_in_world_tran.get_matrix() * m_text_tran_in_object.get_matrix()).inverse();
auto inv_text_cs_in_object_no_offset = (m_model_object_in_world_tran.get_matrix_no_offset() * m_text_tran_in_object.get_matrix_no_offset()).inverse();
TriangleMesh mesh;
for (int i = 0; i < alphas.size(); ++i) {
TriangleMesh sub_mesh = get_text_mesh(alphas[i].c_str(), m_position_points[i], m_normal_points[i], m_cut_plane_dir);
auto position = inv_text_cs_in_object * m_position_points[i];
auto normal = inv_text_cs_in_object_no_offset * m_normal_points[i];
auto cut_plane_dir = inv_text_cs_in_object_no_offset * m_cut_plane_dir_in_world;
TriangleMesh sub_mesh = get_text_mesh(alphas[i].c_str(), position, normal, cut_plane_dir);
mesh.merge(sub_mesh);
}
if (mesh.empty())
return;
Plater *plater = wxGetApp().plater();
if (!plater)
return;
@ -1558,36 +1647,41 @@ void GLGizmoText::generate_text_volume(bool is_temp)
TextInfo text_info = get_text_info();
const Selection &selection = m_parent.get_selection();
ModelObject * model_object = selection.get_model()->objects[m_object_idx];
int cur_volume_id;
if (m_is_modify && m_need_update_text) {
if (m_object_idx == -1 || m_volume_idx == -1) {
BOOST_LOG_TRIVIAL(error) << boost::format("Text: selected object_idx = %1%, volume_idx = %2%") % m_object_idx % m_volume_idx;
return;
}
if (!is_temp) {
plater->take_snapshot("Modify Text");
}
ModelVolume * model_volume = model_object->volumes[m_volume_idx];
ModelVolume * new_model_volume = model_object->add_volume(std::move(mesh));
ModelVolume * new_model_volume = model_object->add_volume(std::move(mesh),false);
new_model_volume->set_transformation(m_text_tran_in_object.get_matrix());
new_model_volume->set_text_info(text_info);
new_model_volume->name = model_volume->name;
new_model_volume->set_type(model_volume->type());
new_model_volume->config.apply(model_volume->config);
std::swap(model_object->volumes[m_volume_idx], model_object->volumes.back());
model_object->delete_volume(model_object->volumes.size() - 1);
model_object->invalidate_bounding_box();
plater->update();
auto cur_text_info = const_cast<TextInfo*> (&new_model_volume->get_text_info());
m_text_volume_tran = new_model_volume->get_matrix();
update_hit_in_text();
cur_text_info->m_hit_in_text = m_hit_in_text;
} else {
if (m_need_update_text)
if (!is_temp && m_need_update_text)
plater->take_snapshot("Add Text");
ObjectList *obj_list = wxGetApp().obj_list();
int volume_id = obj_list->load_mesh_part(mesh, "text_shape", text_info, is_temp);
m_preview_text_volume_id = is_temp ? volume_id : -1;
ModelVolume *text_model_volume = model_object->volumes[volume_id];
cur_volume_id = obj_list->add_text_part(mesh, "text_shape", text_info, m_text_tran_in_object.get_matrix(), is_temp);
m_preview_text_volume_id = is_temp ? cur_volume_id : -1;
if (cur_volume_id >= 0) {
m_show_warning = false;
ModelVolume *text_model_volume = model_object->volumes[cur_volume_id];
m_text_volume_tran = text_model_volume->get_matrix();
auto cur_text_info = const_cast<TextInfo *>(&text_model_volume->get_text_info());
update_hit_in_text();
cur_text_info->m_hit_in_text = m_hit_in_text;
}
else {
m_show_warning = true;
}
}
m_need_update_text = false;
}
@ -1620,8 +1714,7 @@ TextInfo GLGizmoText::get_text_info()
text_info.m_italic = m_italic;
text_info.m_thickness = m_thickness;
text_info.m_text = m_text;
text_info.m_rr = m_rr;
text_info.m_hit_in_text = m_hit_in_text;
text_info.m_rr.mesh_id = m_rr.mesh_id;
text_info.m_embeded_depth = m_embeded_depth;
text_info.m_rotate_angle = m_rotate_angle;
text_info.m_text_gap = m_text_gap;
@ -1630,16 +1723,6 @@ TextInfo GLGizmoText::get_text_info()
return text_info;
}
void GLGizmoText::update_hit_in_text() {
{
const std::vector<Transform3d> &trafo_matrices = m_parent.get_selection().get_all_tran_of_selected_volumes();
auto mi = m_parent.get_selection().get_selected_single_intance();
if (mi && trafo_matrices.size() > 0) {
auto text_world_tran = mi->get_transformation().get_matrix() * m_text_volume_tran;
m_hit_in_text = text_world_tran.inverse() * (trafo_matrices[m_rr.mesh_id] * m_rr.hit.cast<double>());
}
}
}
void GLGizmoText::load_from_text_info(const TextInfo &text_info)
{
m_font_name = text_info.m_font_name;
@ -1655,7 +1738,7 @@ void GLGizmoText::load_from_text_info(const TextInfo &text_info)
m_italic = text_info.m_italic;
m_thickness = text_info.m_thickness;
strcpy(m_text, text_info.m_text.c_str());
m_rr = text_info.m_rr;
m_rr.mesh_id = text_info.m_rr.mesh_id;
m_embeded_depth = text_info.m_embeded_depth;
m_rotate_angle = text_info.m_rotate_angle;
m_text_gap = text_info.m_text_gap;

View File

@ -13,7 +13,8 @@ enum class ModelVolumeType : int;
class ModelVolume;
namespace GUI {
//#define DEBUG_TEXT
//#define DEBUG_TEXT_VALUE
enum class SLAGizmoEventType : unsigned char;
class GLGizmoText : public GLGizmoBase
{
@ -34,7 +35,6 @@ private:
bool m_is_surface_text = false;
bool m_keep_horizontal = false;
mutable RaycastResult m_rr;
mutable Vec3d m_hit_in_text;
float m_combo_height = 0.0f;
float m_combo_width = 0.0f;
@ -63,26 +63,41 @@ private:
std::mutex m_mutex;
std::thread m_thread;
bool m_edit_text_again = false;
bool m_is_modify = false;
bool m_need_update_text = false;
bool m_show_warning = false;
int m_object_idx = -1;
int m_volume_idx = -1;
int m_preview_text_volume_id = -1;
Vec3d m_fix_text_position_in_world = Vec3d::Zero();
Vec3f m_fix_text_normal_in_world = Vec3f::Zero();
bool m_need_fix;
Vec3d m_text_position_in_world = Vec3d::Zero();
Vec3f m_text_normal_in_world = Vec3f::Zero();
Geometry::Transformation m_text_tran_in_object;
Geometry::Transformation m_text_tran_in_world;
Geometry::Transformation m_model_object_in_world_tran;
Transform3d m_text_cs_to_world_tran;
Vec3d m_mouse_position_world = Vec3d::Zero();
Vec3d m_mouse_normal_world = Vec3d::Zero();
Vec3d m_cut_plane_dir = Vec3d::UnitZ();
Vec3d m_cut_plane_dir_in_world = Vec3d::UnitZ();
std::vector<Vec3d> m_position_points;
std::vector<Vec3d> m_normal_points;
std::vector<Vec3d> m_cut_points_in_world;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
std::map<std::string, wxString> m_desc;
Transform3d m_text_volume_tran;
ModelVolume * m_last_text_mv;
// move gizmo
Grabber m_move_grabber;
const int m_move_cube_id = 1;
// TRN - Title in Undo/Redo stack after move with SVG along emboss axe - From surface
const std::string move_snapshot_name = "Text move";
public:
GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
@ -102,18 +117,23 @@ protected:
virtual bool on_is_activable() const override;
virtual void on_render() override;
virtual void on_render_for_picking() override;
virtual void on_start_dragging() override;
virtual void on_stop_dragging() override;
virtual void on_update(const UpdateData &data) override;
void push_combo_style(const float scale);
void pop_combo_style();
void push_button_style(bool pressed);
void pop_button_style();
virtual void on_set_state() override;
virtual void data_changed(bool is_serializing) override;
virtual CommonGizmosDataID on_get_requirements() const override;
virtual void on_render_input_window(float x, float y, float bottom_limit);
void show_tooltip_information(float x, float y);
private:
void load_init_text();
void update_text_pos_normal();
void update_font_status();
void reset_text_info();
bool update_text_positions(const std::vector<std::string>& texts);
@ -124,7 +144,6 @@ private:
void delete_temp_preview_text_volume();
TextInfo get_text_info();
void update_hit_in_text();
void load_from_text_info(const TextInfo &text_info);
};

View File

@ -263,7 +263,7 @@ void GizmoObjectManipulation::update_reset_buttons_visibility()
scale = volume->get_volume_scaling_factor();
min_z = get_volume_min_z(volume);
}
m_show_clear_rotation = !rotation.isApprox(Vec3d::Zero());
m_show_clear_rotation = !rotation.isApprox(m_init_rotation);
m_show_clear_scale = (m_cache.scale / 100.0f - Vec3d::Ones()).norm() > 0.001;
m_show_drop_to_bed = (std::abs(min_z) > EPSILON);
}
@ -489,26 +489,32 @@ void GizmoObjectManipulation::reset_position_value()
void GizmoObjectManipulation::reset_rotation_value()
{
Selection &selection = m_glcanvas.get_selection();
if (selection.is_single_volume() || selection.is_single_modifier()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
volume->set_volume_rotation(Vec3d::Zero());
}
else if (selection.is_single_full_instance()) {
selection.setup_cache();
if (selection.is_single_volume_or_modifier()) {
GLVolume * vol = const_cast<GLVolume *>(selection.get_first_volume());
Geometry::Transformation trafo = vol->get_volume_transformation();
auto offset = trafo.get_offset();
trafo.set_from_transform(m_init_rotation_scale_tran);
trafo.set_offset(offset);
vol->set_volume_transformation(trafo);
} else if (selection.is_single_full_instance()) {
Geometry::Transformation trafo = selection.get_first_volume()->get_instance_transformation();
auto offset = trafo.get_offset();
trafo.set_from_transform(m_init_rotation_scale_tran);
trafo.set_offset(offset);
for (unsigned int idx : selection.get_volume_idxs()) {
GLVolume* volume = const_cast<GLVolume*>(selection.get_volume(idx));
volume->set_instance_rotation(Vec3d::Zero());
const_cast<GLVolume *>(selection.get_volume(idx))->set_instance_transformation(trafo);
}
}
else
} else
return;
// Update rotation at the GLVolumes.
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
// Synchronize instances/volumes.
selection.synchronize_unselected_instances(Selection::SyncRotationType::RESET);
selection.synchronize_unselected_volumes();
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
wxGetApp().plater()->take_snapshot(_u8L("Reset Rotation"), UndoRedo::SnapshotType::GizmoAction);
m_glcanvas.do_rotate("");
m_glcanvas.do_rotate(L("Reset Rotation"));
UpdateAndShow(true);
}
@ -699,6 +705,11 @@ void GizmoObjectManipulation::show_scale_tooltip_information(ImGuiWrapper *imgui
ImGui::PopStyleVar(2);
}
void GizmoObjectManipulation::set_init_rotation(const Geometry::Transformation &value) {
m_init_rotation_scale_tran = value.get_matrix_no_offset();
m_init_rotation = value.get_rotation();
}
void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper, std::string window_name, float x, float y, float bottom_limit)
{
// BBS: GUI refactor: move gizmo to the right

View File

@ -133,6 +133,8 @@ public:
void show_move_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void show_rotate_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void show_scale_tooltip_information(ImGuiWrapper *imgui_wrapper, float caption_max, float x, float y);
void set_init_rotation(const Geometry::Transformation &value);
private:
void reset_settings_value();
void update_settings_value(const Selection& selection);
@ -158,6 +160,8 @@ private:
std::map<std::string, wxString> m_desc_move;
std::map<std::string, wxString> m_desc_rotate;
std::map<std::string, wxString> m_desc_scale;
Vec3d m_init_rotation;
Transform3d m_init_rotation_scale_tran;
};
}}

View File

@ -422,7 +422,7 @@ ModelVolume *Selection::get_selected_single_volume(int &out_object_idx, int &out
ModelObject *Selection::get_selected_single_object(int &out_object_idx)
{
if (is_single_volume() || is_single_modifier()) {
if (is_single_volume() || is_single_modifier() || is_single_full_object()) {
const GLVolume *gl_volume = get_volume(*get_volume_idxs().begin());
out_object_idx = gl_volume->object_idx();
return get_model()->objects[out_object_idx];
@ -1222,7 +1222,7 @@ void Selection::translate(const Vec3d &displacement, bool local)
#if !DISABLE_INSTANCES_SYNCH
if (translation_type == Instance)
synchronize_unselected_instances(SYNC_ROTATION_NONE);
synchronize_unselected_instances(SyncRotationType::NONE);
else if (translation_type == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
@ -1292,7 +1292,7 @@ void Selection::translate(const Vec3d &displacement, TransformationType transfor
#if !DISABLE_INSTANCES_SYNCH
if (m_mode == Instance)
synchronize_unselected_instances(SYNC_ROTATION_NONE);
synchronize_unselected_instances(SyncRotationType::NONE);
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
@ -1425,7 +1425,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
#if !DISABLE_INSTANCES_SYNCH
if (m_mode == Instance)
synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL);
synchronize_unselected_instances((rot_axis_max == 2) ? SyncRotationType::NONE : SyncRotationType::GENERAL);
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
@ -1483,7 +1483,7 @@ void Selection::flattening_rotate(const Vec3d& normal)
// Apply the same transformation also to other instances,
// but respect their possibly diffrent z-rotation.
if (m_mode == Instance)
synchronize_unselected_instances(SYNC_ROTATION_GENERAL);
synchronize_unselected_instances(SyncRotationType::GENERAL);
#endif // !DISABLE_INSTANCES_SYNCH
this->set_bounding_boxes_dirty();
@ -1669,7 +1669,11 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans
} else
transform_instance_relative(v, volume_data, transformation_type, Geometry::translation_transform(world_translation) * Geometry::scale_transform(relative_scale),
m_cache.dragging_center);
std::cout << "";
// update the instance assemble transform
ModelObject * object = m_model->objects[v.object_idx()];
Geometry::Transformation assemble_transform = object->instances[v.instance_idx()]->get_assemble_transformation();
assemble_transform.set_scaling_factor(v.get_instance_scaling_factor());
object->instances[v.instance_idx()]->set_assemble_transformation(assemble_transform);
} else {
if (!is_single_volume_or_modifier()) {
assert(transformation_type.world());
@ -1695,7 +1699,7 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans
if (m_mode == Instance)
// even if there is no rotation, we pass SyncRotationType::GENERAL to force
// synchronize_unselected_instances() to apply the scale to the other instances
synchronize_unselected_instances(SyncRotationType::SYNC_ROTATION_GENERAL);
synchronize_unselected_instances(SyncRotationType::GENERAL);
else if (m_mode == Volume)
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
@ -2910,7 +2914,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()));
switch (sync_rotation_type) {
case SYNC_ROTATION_NONE: {
case SyncRotationType::NONE: {
// z only rotation -> synch instance z
// The X,Y rotations should be synchronized from start to end of the rotation.
assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation()));
@ -2918,7 +2922,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
v->set_instance_offset(Z, volume->get_instance_offset().z());
break;
}
case SYNC_ROTATION_GENERAL:
case SyncRotationType::GENERAL:
// generic rotation -> update instance z with the delta of the rotation.
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation());
v->set_instance_rotation({ rotation.x(), rotation.y(), rotation.z() + z_diff });

View File

@ -502,13 +502,13 @@ private:
void render_sidebar_layers_hints(const std::string& sidebar_field) const;
public:
enum SyncRotationType {
enum class SyncRotationType {
// Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
SYNC_ROTATION_NONE = 0,
NONE = 0,
// Synchronize after rotation by an axis not parallel with Z.
SYNC_ROTATION_GENERAL = 1,
GENERAL = 1,
// Synchronize after rotation reset.
SYNC_ROTATION_RESET = 2
RESET = 2
};
void synchronize_unselected_instances(SyncRotationType sync_rotation_type);
void synchronize_unselected_volumes();