ENH:fix text coordinate system calculation
jira: STUDIO-6449 Change-Id: I36214c14c348e8f52b96501cd027205819b0dabc (cherry picked from commit 44287812a0cb212f1bf6fe70e32e1075f532886d)
This commit is contained in:
parent
92c85a13d0
commit
4091f3e042
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -488,27 +488,33 @@ 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 &selection = m_glcanvas.get_selection();
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue