NEW: Support attaching 3D text to a surface
Change-Id: I13f234cf5f189b594a6277d623dfa9dee489d19f (cherry picked from commit 88ec90226aecb8203c105569a613d33c68a0602b)
This commit is contained in:
parent
85bcb8eae8
commit
1041b8b026
|
@ -650,6 +650,16 @@ private:
|
|||
friend class ModelVolume;
|
||||
};
|
||||
|
||||
struct RaycastResult
|
||||
{
|
||||
Vec2d mouse_position = Vec2d::Zero();
|
||||
int mesh_id = -1;
|
||||
Vec3f hit = Vec3f::Zero();
|
||||
Vec3f normal = Vec3f::Zero();
|
||||
|
||||
template<typename Archive> void serialize(Archive &ar) { ar(mouse_position, mesh_id, hit, normal); }
|
||||
};
|
||||
|
||||
struct TextInfo
|
||||
{
|
||||
std::string m_font_name;
|
||||
|
@ -658,9 +668,18 @@ struct TextInfo
|
|||
bool m_bold = true;
|
||||
bool m_italic = false;
|
||||
float m_thickness = 2.f;
|
||||
float m_embeded_depth = 0.f;
|
||||
float m_rotate_angle = 0;
|
||||
float m_text_gap = 0.f;
|
||||
bool m_is_surface_text = false;
|
||||
bool m_keep_horizontal = false;
|
||||
std::string m_text;
|
||||
|
||||
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_text); }
|
||||
RaycastResult m_rr;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
|
||||
|
@ -914,7 +933,8 @@ private:
|
|||
ObjectBase(other),
|
||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
||||
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||
supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets)
|
||||
supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets),
|
||||
m_text_info(other.m_text_info)
|
||||
{
|
||||
assert(this->id().valid());
|
||||
assert(this->config.id().valid());
|
||||
|
|
|
@ -2170,52 +2170,54 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name
|
|||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
void ObjectList::load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool center)
|
||||
int ObjectList::load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool is_temp)
|
||||
{
|
||||
wxDataViewItem item = GetSelection();
|
||||
// we can add volumes for Object or Instance
|
||||
if (!item || !(m_objects_model->GetItemType(item) & (itObject | itInstance)))
|
||||
return;
|
||||
return -1;
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
|
||||
if (obj_idx < 0) return;
|
||||
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);
|
||||
|
||||
take_snapshot("Load Mesh Part");
|
||||
|
||||
ModelObject* mo = (*m_objects)[obj_idx];
|
||||
|
||||
Geometry::Transformation instance_transformation = mo->instances[0]->get_transformation();
|
||||
|
||||
// apply the instance transform to all volumes and reset instance transform except the offset
|
||||
apply_object_instance_transfrom_to_all_volumes(mo);
|
||||
|
||||
double old_top_position = mo->mesh().bounding_box().max(2) - mo->instances[0]->get_offset().z();
|
||||
ModelVolume* mv = mo->add_volume(mesh);
|
||||
Vec3d offset = Vec3d(0, 0, old_top_position + mv->get_offset(Axis::Z));
|
||||
mv->set_offset(offset);
|
||||
ModelVolume *mv = mo->add_volume(mesh);
|
||||
mv->name = name.ToStdString();
|
||||
if (!text_info.m_text.empty())
|
||||
mv->set_text_info(text_info);
|
||||
|
||||
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(); });
|
||||
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);
|
||||
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);
|
||||
if (items.size() > 1) {
|
||||
m_selection_mode = smVolume;
|
||||
m_last_selected_item = wxDataViewItem(nullptr);
|
||||
}
|
||||
select_items(items);
|
||||
|
||||
selection_changed();
|
||||
}
|
||||
select_items(items);
|
||||
|
||||
selection_changed();
|
||||
|
||||
//BBS: notify partplate the modify
|
||||
notify_instance_updated(obj_idx);
|
||||
return mo->volumes.size() - 1;
|
||||
}
|
||||
|
||||
//BBS
|
||||
|
|
|
@ -284,7 +284,7 @@ public:
|
|||
void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true);
|
||||
// BBS
|
||||
void switch_to_object_process();
|
||||
void load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool center = true);
|
||||
int load_mesh_part(const TriangleMesh &mesh, const wxString &name, const TextInfo &text_info, bool is_temp);
|
||||
void 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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,8 @@
|
|||
#include "GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "../GLTexture.hpp"
|
||||
#include "../Camera.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -12,6 +14,7 @@ class ModelVolume;
|
|||
|
||||
namespace GUI {
|
||||
|
||||
enum class SLAGizmoEventType : unsigned char;
|
||||
class GLGizmoText : public GLGizmoBase
|
||||
{
|
||||
private:
|
||||
|
@ -23,10 +26,21 @@ private:
|
|||
bool m_bold = true;
|
||||
bool m_italic = false;
|
||||
float m_thickness = 2.f;
|
||||
float m_embeded_depth = 0.f;
|
||||
float m_rotate_angle = 0;
|
||||
float m_text_gap = 0.f;
|
||||
bool m_is_surface_text = false;
|
||||
bool m_keep_horizontal = false;
|
||||
mutable RaycastResult m_rr;
|
||||
|
||||
float m_combo_height = 0.0f;
|
||||
float m_combo_width = 0.0f;
|
||||
float m_scale;
|
||||
|
||||
Vec2d m_mouse_position = Vec2d::Zero();
|
||||
Vec2d m_origin_mouse_position = Vec2d::Zero();
|
||||
bool m_shift_down = false;
|
||||
|
||||
class TextureInfo {
|
||||
public:
|
||||
GLTexture* texture { nullptr };
|
||||
|
@ -42,8 +56,24 @@ private:
|
|||
std::vector<std::string> m_font_names;
|
||||
|
||||
bool m_is_modify = false;
|
||||
int m_object_idx;
|
||||
int m_volume_idx;
|
||||
bool m_need_update_text = false;
|
||||
|
||||
int m_object_idx = -1;
|
||||
int m_volume_idx = -1;
|
||||
|
||||
int m_preview_text_volume_id = -1;
|
||||
|
||||
Vec3d m_mouse_position_world = Vec3d::Zero();
|
||||
Vec3d m_mouse_normal_world = Vec3d::Zero();
|
||||
|
||||
Vec3d m_cut_plane_dir = Vec3d::UnitZ();
|
||||
|
||||
std::vector<Vec3d> m_position_points;
|
||||
std::vector<Vec3d> m_normal_points;
|
||||
|
||||
// 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;
|
||||
|
||||
public:
|
||||
GLGizmoText(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
@ -51,6 +81,11 @@ public:
|
|||
|
||||
void update_font_texture();
|
||||
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d &mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
bool is_mesh_point_clipped(const Vec3d &point, const Transform3d &trafo) const;
|
||||
BoundingBoxf3 bounding_box() const;
|
||||
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
|
@ -65,9 +100,20 @@ protected:
|
|||
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:
|
||||
ModelVolume *get_selected_single_volume(int& out_object_idx, int& out_volume_idx) const;
|
||||
void reset_text_info();
|
||||
bool update_text_positions(const std::vector<std::string>& texts);
|
||||
TriangleMesh get_text_mesh(const char* text_str, const Vec3d &position, const Vec3d &normal, const Vec3d &text_up_dir);
|
||||
|
||||
bool update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector<Transform3d> &trafo_matrices);
|
||||
void generate_text_volume(bool is_temp = true);
|
||||
void delete_temp_preview_text_volume();
|
||||
|
||||
TextInfo get_text_info();
|
||||
void load_from_text_info(const TextInfo &text_info);
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -625,6 +625,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
|
|||
return dynamic_cast<GLGizmoSeam*>(m_gizmos[Seam].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == MmuSegmentation)
|
||||
return dynamic_cast<GLGizmoMmuSegmentation*>(m_gizmos[MmuSegmentation].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == Text)
|
||||
return dynamic_cast<GLGizmoText*>(m_gizmos[Text].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -757,7 +759,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
// mouse anywhere
|
||||
if (evt.Moving()) {
|
||||
m_tooltip = update_hover_state(mouse_pos);
|
||||
if (m_current == MmuSegmentation || m_current == FdmSupports)
|
||||
if (m_current == MmuSegmentation || m_current == FdmSupports || m_current == Text)
|
||||
// BBS
|
||||
gizmo_event(SLAGizmoEventType::Moving, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
|
||||
} else if (evt.LeftUp()) {
|
||||
|
@ -870,7 +872,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
|||
m_tooltip.clear();
|
||||
|
||||
if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) {
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation)
|
||||
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports || m_current == Seam || m_current == MmuSegmentation || m_current == Text)
|
||||
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown()))
|
||||
// the gizmo got the event and took some action, there is no need to do anything more
|
||||
processed = true;
|
||||
|
|
Loading…
Reference in New Issue