Create text on second Part(volume) of object
This commit is contained in:
parent
936ba6c28c
commit
1078fe55ec
7 changed files with 151 additions and 52 deletions
|
@ -103,6 +103,15 @@ struct FontItem
|
|||
wx_mac_font_descr // path is font descriptor generated by wxWidgets on windows
|
||||
};
|
||||
|
||||
bool operator==(const FontItem &other) const {
|
||||
return
|
||||
type == other.type &&
|
||||
prop == other.prop &&
|
||||
name == other.name &&
|
||||
path == other.path
|
||||
;
|
||||
}
|
||||
|
||||
// undo / redo stack recovery
|
||||
template<class Archive> void serialize(Archive &ar)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "libslic3r/AppConfig.hpp" // store/load font list
|
||||
#include "libslic3r/MapUtils.hpp"
|
||||
#include "libslic3r/Format/OBJ.hpp" // load obj file for default object
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
|
||||
#include "imgui/imgui_stdlib.h" // using std::string for inputs
|
||||
#include "nanosvg/nanosvg.h" // load SVG file
|
||||
|
@ -133,15 +134,28 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||
}
|
||||
|
||||
std::optional<int> object_idx;
|
||||
|
||||
std::optional<Transform3d> hit_vol_tr;
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
if (!selection.is_empty()) object_idx = selection.get_object_idx();
|
||||
auto data =
|
||||
std::make_unique<EmbossDataCreate>(m_font_manager.get_font_file(),
|
||||
create_configuration(),
|
||||
create_volume_name(), volume_type,
|
||||
screen_coor, object_idx,
|
||||
&m_raycast_manager);
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
if (!selection.is_empty()) {
|
||||
object_idx = selection.get_object_idx();
|
||||
int hovered_id = m_parent.get_first_hover_volume_idx();
|
||||
if (hovered_id >= 0) {
|
||||
GLVolume *gl_volume = m_parent.get_volumes().volumes[hovered_id];
|
||||
hit_vol_tr = gl_volume->get_instance_transformation().get_matrix();
|
||||
}
|
||||
}
|
||||
Plater* plater = wxGetApp().plater();
|
||||
const Camera &camera = plater->get_camera();
|
||||
auto data = std::make_unique<EmbossDataCreate>(
|
||||
m_font_manager.get_font_file(),
|
||||
create_configuration(),
|
||||
create_volume_name(), volume_type, screen_coor, object_idx,
|
||||
hit_vol_tr, camera,
|
||||
plater->build_volume().bed_shape(),
|
||||
&m_raycast_manager);
|
||||
|
||||
auto &worker = plater->get_ui_job_worker();
|
||||
queue_job(worker, std::make_unique<EmbossCreateJob>(std::move(data)));
|
||||
}
|
||||
|
||||
|
@ -206,14 +220,15 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
|||
// initialize raycasters
|
||||
// IMPROVE: move to job, for big scene it slows down
|
||||
ModelObject *act_model_object = act_model_volume->get_object();
|
||||
m_raycast_manager.actualize({act_model_object}, &skip);
|
||||
m_raycast_manager.actualize(act_model_object, &skip);
|
||||
return false;
|
||||
}
|
||||
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
auto hit = m_raycast_manager.unproject(mouse_pos, &skip);
|
||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||
auto hit = m_raycast_manager.unproject(mouse_pos, camera, &skip);
|
||||
if (!hit.has_value()) {
|
||||
// there is no hit
|
||||
// show common translation of object
|
||||
|
@ -325,7 +340,7 @@ void GLGizmoEmboss::on_render_for_picking() {
|
|||
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
initialize();
|
||||
check_selection();
|
||||
check_selection();
|
||||
|
||||
// TODO: fix width - showing scroll in first draw of advanced.
|
||||
const ImVec2 &min_window_size = get_minimal_window_size();
|
||||
|
@ -480,6 +495,12 @@ void GLGizmoEmboss::initialize()
|
|||
cfg.max_style_image_width = cfg.max_font_name_width -
|
||||
2 * style.FramePadding.x;
|
||||
|
||||
// initialize default font
|
||||
FontList default_font_list = create_default_font_list();
|
||||
for (const FontItem &fi : default_font_list) {
|
||||
assert(cfg.default_styles.find(fi.name) == cfg.default_styles.end());
|
||||
cfg.default_styles[fi.name] = fi; // copy
|
||||
}
|
||||
m_gui_cfg.emplace(cfg);
|
||||
|
||||
// TODO: What to do when icon was NOT loaded? Generate them?
|
||||
|
@ -489,39 +510,28 @@ void GLGizmoEmboss::initialize()
|
|||
const AppConfig *app_cfg = wxGetApp().app_config;
|
||||
FontList font_list = load_font_list_from_app_config(app_cfg);
|
||||
m_font_manager.add_fonts(font_list);
|
||||
// TODO: select last session sellected font index
|
||||
|
||||
if (!m_font_manager.load_first_valid_font()) {
|
||||
FontList font_list = create_default_font_list();
|
||||
m_font_manager.add_fonts(font_list);
|
||||
m_font_manager.add_fonts(default_font_list);
|
||||
// TODO: What to do when default fonts are not loadable?
|
||||
bool success = m_font_manager.load_first_valid_font();
|
||||
assert(success);
|
||||
}
|
||||
set_default_text();
|
||||
select_stored_font_item();
|
||||
}
|
||||
|
||||
FontList GLGizmoEmboss::create_default_font_list()
|
||||
{
|
||||
// https://docs.wxwidgets.org/3.0/classwx_font.html
|
||||
// Predefined objects/pointers: wxNullFont, wxNORMAL_FONT, wxSMALL_FONT, wxITALIC_FONT, wxSWISS_FONT
|
||||
|
||||
FontItem par_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Parallel to bed"));
|
||||
|
||||
FontItem perp_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Perpendicular to bed"));
|
||||
|
||||
FontItem fix_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Fixed size"));
|
||||
|
||||
FontItem negative_fi = WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("Negative"));
|
||||
|
||||
return {
|
||||
par_fi,
|
||||
perp_fi,
|
||||
fix_fi,
|
||||
negative_fi,
|
||||
WxFontUtils::get_font_item(*wxNORMAL_FONT), // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)
|
||||
WxFontUtils::get_font_item(*wxSMALL_FONT), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT.
|
||||
WxFontUtils::get_font_item(*wxITALIC_FONT), // A font using the wxFONTFAMILY_ROMAN family and wxFONTSTYLE_ITALIC style and of the same size of wxNORMAL_FONT.
|
||||
WxFontUtils::get_font_item(*wxSWISS_FONT), // A font identic to wxNORMAL_FONT except for the family used which is wxFONTFAMILY_SWISS.
|
||||
WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD))
|
||||
WxFontUtils::get_font_item(*wxNORMAL_FONT, _u8L("NORMAL")), // wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)
|
||||
WxFontUtils::get_font_item(*wxSMALL_FONT, _u8L("SMALL")), // A font using the wxFONTFAMILY_SWISS family and 2 points smaller than wxNORMAL_FONT.
|
||||
WxFontUtils::get_font_item(*wxITALIC_FONT, _u8L("ITALIC")), // A font using the wxFONTFAMILY_ROMAN family and wxFONTSTYLE_ITALIC style and of the same size of wxNORMAL_FONT.
|
||||
WxFontUtils::get_font_item(*wxSWISS_FONT, _u8L("SWISS")), // A font identic to wxNORMAL_FONT except for the family used which is wxFONTFAMILY_SWISS.
|
||||
WxFontUtils::get_font_item(wxFont(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD), _u8L("MODERN"))
|
||||
//, WxFontUtils::get_os_font() == wxNORMAL_FONT
|
||||
};
|
||||
}
|
||||
|
@ -617,6 +627,18 @@ void GLGizmoEmboss::close()
|
|||
m_parent.get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss);
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::select_stored_font_item()
|
||||
{
|
||||
const std::string &name = m_font_manager.get_font_item().name;
|
||||
const auto &styles = m_gui_cfg->default_styles;
|
||||
const auto &it = styles.find(name);
|
||||
if (it == styles.end()) {
|
||||
m_stored_font_item.reset();
|
||||
return;
|
||||
}
|
||||
m_stored_font_item = it->second;
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_window()
|
||||
{
|
||||
#ifdef ALLOW_DEBUG_MODE
|
||||
|
@ -899,6 +921,7 @@ void GLGizmoEmboss::draw_rename_style(bool start_rename)
|
|||
m_font_manager.get_truncated_name() = "";
|
||||
m_font_manager.free_style_images();
|
||||
ImGui::CloseCurrentPopup();
|
||||
select_stored_font_item();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
@ -936,7 +959,10 @@ void GLGizmoEmboss::draw_style_list() {
|
|||
const FontManager::StyleImage &img = *item.image;
|
||||
ImVec2 select_size(0.f, std::max(img.tex_size.y, m_gui_cfg->min_style_image_height));
|
||||
if (ImGui::Selectable("##style_select", is_selected, flags, select_size)) {
|
||||
if (m_font_manager.load_font(index)) process();
|
||||
if (m_font_manager.load_font(index)) {
|
||||
process();
|
||||
select_stored_font_item();
|
||||
}
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", actual_style_name.c_str());
|
||||
|
||||
|
@ -991,9 +1017,10 @@ void GLGizmoEmboss::draw_style_list() {
|
|||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Duplicate style.").c_str());
|
||||
|
||||
|
||||
// TODO: Is style changed against stored one
|
||||
bool is_changed = false;
|
||||
bool is_stored = m_stored_font_item.has_value();
|
||||
bool is_changed = (is_stored) ?
|
||||
!(*m_stored_font_item == m_font_manager.get_font_item()) : true;
|
||||
|
||||
ImGui::SameLine();
|
||||
if (draw_button(IconType::save, !is_changed)) {
|
||||
|
@ -1025,7 +1052,10 @@ void GLGizmoEmboss::draw_style_list() {
|
|||
m_font_manager.add_fonts(font_list);
|
||||
// TODO: What to do when default fonts are not loadable?
|
||||
bool success = m_font_manager.load_first_valid_font();
|
||||
select_stored_font_item();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Revert all styles").c_str());
|
||||
#endif // ALLOW_REVERT_ALL_STYLES
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "libslic3r/Emboss.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TextConfiguration.hpp"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
|
@ -148,6 +149,9 @@ private:
|
|||
std::string depth;
|
||||
};
|
||||
Translations translations;
|
||||
|
||||
std::map<std::string, FontItem> default_styles;
|
||||
|
||||
GuiCfg() = default;
|
||||
};
|
||||
std::optional<const GuiCfg> m_gui_cfg;
|
||||
|
@ -157,7 +161,8 @@ private:
|
|||
bool m_is_advanced_edit_style = false;
|
||||
|
||||
FontManager m_font_manager;
|
||||
|
||||
std::optional<FontItem> m_stored_font_item;
|
||||
void select_stored_font_item();
|
||||
//FontList m_font_list;
|
||||
//size_t m_font_selected;// index to m_font_list
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <libslic3r/Model.hpp>
|
||||
#include <libslic3r/Format/OBJ.hpp> // load_obj for default mesh
|
||||
#include <libslic3r/BuildVolume.hpp>
|
||||
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
|
@ -102,15 +101,13 @@ void EmbossCreateJob::process(Ctl &ctl) {
|
|||
if (m_result.its.empty()) m_result = create_default_mesh();
|
||||
if (ctl.was_canceled()) return;
|
||||
|
||||
Plater * plater = wxGetApp().plater(); // may be move to input
|
||||
|
||||
std::optional<RaycastManager::Hit> hit;
|
||||
if (m_input->object_idx.has_value()) {
|
||||
// By position of cursor create transformation to put text on surface of model
|
||||
const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects;
|
||||
m_input->raycast_manager->actualize(objects);
|
||||
ModelObject *obj = wxGetApp().plater()->model().objects[*m_input->object_idx];
|
||||
m_input->raycast_manager->actualize(obj);
|
||||
if (ctl.was_canceled()) return;
|
||||
hit = m_input->raycast_manager->unproject(m_input->screen_coor);
|
||||
hit = m_input->raycast_manager->unproject(m_input->screen_coor, m_input->camera);
|
||||
|
||||
// context menu for add text could be open only by right click on an
|
||||
// object. After right click, object is selected and object_idx is set
|
||||
|
@ -123,14 +120,12 @@ void EmbossCreateJob::process(Ctl &ctl) {
|
|||
// create new object
|
||||
// calculate X,Y offset position for lay on platter in place of
|
||||
// mouse click
|
||||
const Camera &camera = plater->get_camera();
|
||||
Vec2d bed_coor = CameraUtils::get_z0_position(camera, m_input->screen_coor);
|
||||
Vec2d bed_coor = CameraUtils::get_z0_position(m_input->camera, m_input->screen_coor);
|
||||
|
||||
// check point is on build plate:
|
||||
Pointfs bed_shape = plater->build_volume().bed_shape();
|
||||
Points bed_shape_;
|
||||
bed_shape_.reserve(bed_shape.size());
|
||||
for (const Vec2d &p : bed_shape)
|
||||
bed_shape_.reserve(m_input->bed_shape.size());
|
||||
for (const Vec2d &p : m_input->bed_shape)
|
||||
bed_shape_.emplace_back(p.cast<int>());
|
||||
Polygon bed(bed_shape_);
|
||||
if (!bed.contains(bed_coor.cast<int>()))
|
||||
|
@ -143,8 +138,13 @@ void EmbossCreateJob::process(Ctl &ctl) {
|
|||
Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z());
|
||||
m_transformation = Transform3d(tt);
|
||||
} else {
|
||||
m_transformation = Emboss::create_transformation_onto_surface(
|
||||
hit->position, hit->normal);
|
||||
// TODO: Disable apply common transformation after draggig
|
||||
// Call after is used for apply transformation after common dragging to rewrite it
|
||||
m_transformation = Emboss::create_transformation_onto_surface(hit->position, hit->normal);
|
||||
if (m_input->hit_vol_tr.has_value()) {
|
||||
Transform3d object_trmat = m_input->raycast_manager->get_transformation(hit->tr_key);
|
||||
m_transformation = m_input->hit_vol_tr->inverse() * object_trmat * m_transformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <libslic3r/Emboss.hpp>
|
||||
#include <libslic3r/ModelVolumeType.hpp>
|
||||
#include "slic3r/Utils/RaycastManager.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "Job.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -110,6 +111,15 @@ struct EmbossDataCreate: public EmbossDataBase
|
|||
// when exist ModelObject where to create volume
|
||||
std::optional<int> object_idx;
|
||||
|
||||
// hitted instance transformation
|
||||
std::optional<Transform3d> hit_vol_tr;
|
||||
|
||||
// projection property
|
||||
Camera camera;
|
||||
|
||||
// shape of bed in case of create volume on bed
|
||||
std::vector<Vec2d> bed_shape;
|
||||
|
||||
// used to find point on surface where to create new object
|
||||
RaycastManager *raycast_manager;
|
||||
// It is inside of GLGizmoEmboss object,
|
||||
|
@ -121,11 +131,17 @@ struct EmbossDataCreate: public EmbossDataBase
|
|||
ModelVolumeType volume_type,
|
||||
Vec2d screen_coor,
|
||||
std::optional<int> object_idx,
|
||||
const std::optional<Transform3d>& hit_vol_tr,
|
||||
const Camera& camera,
|
||||
const std::vector<Vec2d> & bed_shape,
|
||||
RaycastManager * raycast_manager)
|
||||
: EmbossDataBase(std::move(font_file), text_configuration, volume_name)
|
||||
, volume_type(volume_type)
|
||||
, screen_coor(screen_coor)
|
||||
, object_idx(object_idx)
|
||||
, hit_vol_tr(hit_vol_tr)
|
||||
, camera(camera)
|
||||
, bed_shape(bed_shape)
|
||||
, raycast_manager(raycast_manager)
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -73,8 +73,45 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||
transformations.erase(transformation_key);
|
||||
}
|
||||
|
||||
void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
||||
{
|
||||
// actualize MeshRaycaster
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
size_t oid = volume->id().id;
|
||||
if (skip != nullptr && skip->skip(oid))
|
||||
continue;
|
||||
auto item = raycasters.find(oid);
|
||||
if (item == raycasters.end()) {
|
||||
// add new raycaster
|
||||
auto raycaster = std::make_unique<MeshRaycaster>(volume->mesh());
|
||||
raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
||||
}
|
||||
}
|
||||
|
||||
// actualize transformation matrices
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
if (skip != nullptr && skip->skip(volume->id().id)) continue;
|
||||
const Transform3d &volume_tr = volume->get_matrix();
|
||||
for (const ModelInstance *instance : object->instances) {
|
||||
const Transform3d &instrance_tr = instance->get_matrix();
|
||||
Transform3d transformation = instrance_tr * volume_tr;
|
||||
// TODO: add SLA shift Z
|
||||
// transformation.translation()(2) += m_sla_shift_z;
|
||||
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
||||
auto item = transformations.find(tr_key);
|
||||
if (item != transformations.end()) {
|
||||
// actualize transformation all the time
|
||||
item->second = transformation;
|
||||
} else {
|
||||
// add new transformation
|
||||
transformations.insert(std::make_pair(tr_key, transformation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
||||
const Vec2d &mouse_pos, const ISkip *skip) const
|
||||
const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const
|
||||
{
|
||||
struct HitWithDistance: public Hit
|
||||
{
|
||||
|
@ -87,8 +124,6 @@ std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
|||
{}
|
||||
};
|
||||
std::optional<HitWithDistance> closest;
|
||||
|
||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||
for (const auto &item : transformations) {
|
||||
const TrKey &key = item.first;
|
||||
size_t volume_id = key.second;
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
void actualize(const ModelObjectPtrs &objects,
|
||||
const ISkip * skip = nullptr);
|
||||
|
||||
void actualize(const ModelObject *object, const ISkip *skip = nullptr);
|
||||
|
||||
// TODO: it is more general object move outside of this class
|
||||
struct SurfacePoint
|
||||
{
|
||||
|
@ -85,9 +87,11 @@ public:
|
|||
/// Note: Function use current camera position from wxGetApp()
|
||||
/// </summary>
|
||||
/// <param name="mouse_pos">Position of mouse on screen</param>
|
||||
/// <param name="camera">Projection params</param>
|
||||
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
||||
/// <returns>Position on surface, normal direction and transformation key, which define hitted object instance</returns>
|
||||
std::optional<Hit> unproject(const Vec2d &mouse_pos,
|
||||
std::optional<Hit> unproject(const Vec2d &mouse_pos,
|
||||
const Camera &camera,
|
||||
const ISkip *skip = nullptr) const;
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Add table
Reference in a new issue