mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 21:45:57 +08:00
Creation by jobs
This commit is contained in:
parent
53ee0092b0
commit
d10fd37b2f
@ -114,14 +114,12 @@ static void draw_fine_position(const Selection &selection)
|
|||||||
}
|
}
|
||||||
#endif // SHOW_FINE_POSITION
|
#endif // SHOW_FINE_POSITION
|
||||||
|
|
||||||
#include "libslic3r/BuildVolume.hpp"
|
|
||||||
void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos)
|
void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mouse_pos)
|
||||||
{
|
{
|
||||||
assert(volume_type == ModelVolumeType::MODEL_PART ||
|
assert(volume_type == ModelVolumeType::MODEL_PART ||
|
||||||
volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
|
volume_type == ModelVolumeType::NEGATIVE_VOLUME ||
|
||||||
volume_type == ModelVolumeType::PARAMETER_MODIFIER);
|
volume_type == ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
if (!m_is_initialized) initialize();
|
if (!m_is_initialized) initialize();
|
||||||
std::shared_ptr<Emboss::FontFile> &font_file = m_font_manager.get_font_file();
|
|
||||||
set_default_text();
|
set_default_text();
|
||||||
|
|
||||||
Vec2d screen_coor = mouse_pos;
|
Vec2d screen_coor = mouse_pos;
|
||||||
@ -135,71 +133,14 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||||||
std::optional<int> object_idx;
|
std::optional<int> object_idx;
|
||||||
const Selection &selection = m_parent.get_selection();
|
const Selection &selection = m_parent.get_selection();
|
||||||
if (!selection.is_empty()) object_idx = selection.get_object_idx();
|
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();
|
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
queue_job( worker, [volume_type,
|
queue_job(worker, std::make_unique<EmbossCreateJob>(std::move(data)));
|
||||||
screen_coor,
|
|
||||||
object_idx,
|
|
||||||
ff = font_file,
|
|
||||||
text = m_text,
|
|
||||||
&raycast_manager = m_raycast_manager,
|
|
||||||
name = create_volume_name(),
|
|
||||||
tc = create_configuration(),
|
|
||||||
fi = m_font_manager.get_font_item()
|
|
||||||
](Job::Ctl &ctl) {
|
|
||||||
// It is neccessary to create some shape
|
|
||||||
// Emboss text window is opened by creation new embosstext object
|
|
||||||
TriangleMesh tm = (ff == nullptr) ?
|
|
||||||
create_default_mesh() :
|
|
||||||
create_mesh(text.c_str(), *ff, fi.prop);
|
|
||||||
if (tm.its.empty()) tm = create_default_mesh();
|
|
||||||
if (ctl.was_canceled()) return;
|
|
||||||
|
|
||||||
std::optional<RaycastManager::Hit> hit;
|
|
||||||
if (object_idx.has_value()) {
|
|
||||||
// By position of cursor create transformation to put text on surface of model
|
|
||||||
const ModelObjectPtrs &objects = wxGetApp().plater()->model().objects;
|
|
||||||
raycast_manager.actualize(objects);
|
|
||||||
if (ctl.was_canceled()) return;
|
|
||||||
hit = raycast_manager.unproject(screen_coor);
|
|
||||||
|
|
||||||
// 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 also hit must exist.
|
|
||||||
// But there is proper behavior when hit doesn't exists.
|
|
||||||
// When this assert appear distquish remove of it.
|
|
||||||
assert(hit.has_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hit.has_value()) {
|
|
||||||
// create new object
|
|
||||||
// calculate X,Y offset position for lay on platter in place of
|
|
||||||
// mouse click
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
|
||||||
Vec2d bed_coor = CameraUtils::get_z0_position(camera, screen_coor);
|
|
||||||
|
|
||||||
// check point is on build plate:
|
|
||||||
Pointfs bed_shape = wxGetApp().plater()->build_volume().bed_shape();
|
|
||||||
Points bed_shape_;
|
|
||||||
bed_shape_.reserve(bed_shape.size());
|
|
||||||
for (const Vec2d &p : bed_shape)
|
|
||||||
bed_shape_.emplace_back(p.cast<int>());
|
|
||||||
Polygon bed(bed_shape_);
|
|
||||||
if (!bed.contains(bed_coor.cast<int>()))
|
|
||||||
// mouse pose is out of build plate so create object in center of plate
|
|
||||||
bed_coor = bed.centroid().cast<double>();
|
|
||||||
|
|
||||||
double z = tc.font_item.prop.emboss / 2;
|
|
||||||
Vec3d offset(bed_coor.x(), bed_coor.y(), z);
|
|
||||||
offset -= tm.center();
|
|
||||||
Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z());
|
|
||||||
Transform3d trmat(tt);
|
|
||||||
create_emboss_object(std::move(tm), trmat, name, tc);
|
|
||||||
// Gizmo will open when successfuly create new object
|
|
||||||
// Gizmo can't be open when selection is empty
|
|
||||||
} else {
|
|
||||||
Transform3d transformation = Emboss::create_transformation_onto_surface(hit->position, hit->normal);
|
|
||||||
create_emboss_volume(std::move(tm), transformation, name, tc, volume_type, *object_idx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
||||||
@ -561,42 +502,6 @@ void GLGizmoEmboss::set_default_text()
|
|||||||
m_text = _u8L("Embossed text");
|
m_text = _u8L("Embossed text");
|
||||||
}
|
}
|
||||||
|
|
||||||
Slic3r::TriangleMesh GLGizmoEmboss::create_default_mesh()
|
|
||||||
{
|
|
||||||
// When cant load any font use default object loaded from file
|
|
||||||
std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl";
|
|
||||||
TriangleMesh triangle_mesh;
|
|
||||||
if (!load_obj(path.c_str(), &triangle_mesh)) {
|
|
||||||
// when can't load mesh use cube
|
|
||||||
return TriangleMesh(its_make_cube(36., 4., 2.5));
|
|
||||||
}
|
|
||||||
return triangle_mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh()
|
|
||||||
{
|
|
||||||
// It is neccessary to create some shape
|
|
||||||
// Emboss text window is opened by creation new embosstext object
|
|
||||||
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
|
||||||
if (font_file == nullptr) return create_default_mesh();
|
|
||||||
const FontItem &fi = m_font_manager.get_font_item();
|
|
||||||
TriangleMesh result = create_mesh(m_text.c_str(), *font_file, fi.prop);
|
|
||||||
if (result.its.empty()) return create_default_mesh();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Slic3r::TriangleMesh GLGizmoEmboss::create_mesh(const char * text,
|
|
||||||
Emboss::FontFile &font,
|
|
||||||
const FontProp & font_prop)
|
|
||||||
{
|
|
||||||
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
|
||||||
float scale = font_prop.size_in_mm / font.ascent;
|
|
||||||
float depth = font_prop.emboss / scale;
|
|
||||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
|
|
||||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
|
||||||
return TriangleMesh(Emboss::polygons2model(shapes, project));
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID
|
#include "imgui/imgui_internal.h" // to unfocus input --> ClearActiveID
|
||||||
void GLGizmoEmboss::check_selection()
|
void GLGizmoEmboss::check_selection()
|
||||||
{
|
{
|
||||||
@ -665,12 +570,12 @@ bool GLGizmoEmboss::process()
|
|||||||
// exist loaded font?
|
// exist loaded font?
|
||||||
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file();
|
||||||
if (font_file == nullptr) return false;
|
if (font_file == nullptr) return false;
|
||||||
auto data = std::make_unique<EmbossData>(font_file,
|
auto data = std::make_unique<EmbossDataUpdate>(font_file,
|
||||||
create_configuration(),
|
create_configuration(),
|
||||||
create_volume_name(), m_volume);
|
create_volume_name(), m_volume);
|
||||||
|
|
||||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
replace_job(worker, std::make_unique<EmbossJob>(std::move(data)));
|
replace_job(worker, std::make_unique<EmbossUpdateJob>(std::move(data)));
|
||||||
|
|
||||||
// notification is removed befor object is changed by job
|
// notification is removed befor object is changed by job
|
||||||
remove_notification_not_valid_font();
|
remove_notification_not_valid_font();
|
||||||
@ -1672,216 +1577,5 @@ std::string GLGizmoEmboss::get_file_name(const std::string &file_path)
|
|||||||
return file_path.substr(offset, count);
|
return file_path.substr(offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r::GUI {
|
|
||||||
|
|
||||||
class Priv
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Priv() = delete;
|
|
||||||
struct EmbossObject
|
|
||||||
{
|
|
||||||
TriangleMesh mesh;
|
|
||||||
Transform3d transformation;
|
|
||||||
std::string name;
|
|
||||||
TextConfiguration cfg;
|
|
||||||
EmbossObject(TriangleMesh && mesh,
|
|
||||||
const Transform3d& transformation,
|
|
||||||
const std::string& name,
|
|
||||||
const TextConfiguration& cfg)
|
|
||||||
: mesh(std::move(mesh))
|
|
||||||
, transformation(transformation) // copy
|
|
||||||
, name(name) // copy
|
|
||||||
, cfg(cfg) // copy
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
struct EmbossVolume : public EmbossObject
|
|
||||||
{
|
|
||||||
ModelVolumeType type;
|
|
||||||
size_t object_idx;
|
|
||||||
EmbossVolume(TriangleMesh && mesh,
|
|
||||||
const Transform3d& transformation,
|
|
||||||
const std::string& name,
|
|
||||||
const TextConfiguration& cfg,
|
|
||||||
ModelVolumeType type,
|
|
||||||
size_t object_idx)
|
|
||||||
: EmbossObject(std::move(mesh), transformation, name, cfg)
|
|
||||||
, type(type)
|
|
||||||
, object_idx(object_idx)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
static void create_emboss_object(EmbossObject &data);
|
|
||||||
static void create_emboss_volume(EmbossVolume &data);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
|
|
||||||
void GLGizmoEmboss::create_emboss_object(TriangleMesh &&mesh,
|
|
||||||
const Transform3d& transformation,
|
|
||||||
const std::string& name,
|
|
||||||
const TextConfiguration& cfg)
|
|
||||||
{
|
|
||||||
// Move data to call after is not working
|
|
||||||
// data are owned by lambda
|
|
||||||
auto data = new Priv::EmbossObject(std::move(mesh), transformation, name, cfg);
|
|
||||||
wxGetApp().plater()->CallAfter([data]() {
|
|
||||||
ScopeGuard sg([data]() { delete data; });
|
|
||||||
Priv::create_emboss_object(*data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::create_emboss_volume(TriangleMesh && mesh,
|
|
||||||
Transform3d transformation,
|
|
||||||
std::string name,
|
|
||||||
TextConfiguration cfg,
|
|
||||||
ModelVolumeType type,
|
|
||||||
size_t object_idx)
|
|
||||||
{
|
|
||||||
// Move data to call after is not working
|
|
||||||
// data are owen by lambda
|
|
||||||
auto data = new Priv::EmbossVolume(std::move(mesh), transformation, name, cfg, type, object_idx);
|
|
||||||
wxGetApp().plater()->CallAfter([data]() {
|
|
||||||
ScopeGuard sg([data]() { delete data; });
|
|
||||||
Priv::create_emboss_volume(*data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Priv::create_emboss_object(EmbossObject &data)
|
|
||||||
{
|
|
||||||
GUI_App & app = wxGetApp();
|
|
||||||
Plater * plater = app.plater();
|
|
||||||
ObjectList * obj_list = app.obj_list();
|
|
||||||
GLCanvas3D * canvas = plater->canvas3D();
|
|
||||||
|
|
||||||
plater->take_snapshot(_L("Add Emboss text object"));
|
|
||||||
// Create new object and change selection
|
|
||||||
bool center = false;
|
|
||||||
obj_list->load_mesh_object(std::move(data.mesh), data.name, center, &data.cfg, &data.transformation);
|
|
||||||
|
|
||||||
// When add new object selection is empty.
|
|
||||||
// Gizmo is automaticaly close when Selection is empty
|
|
||||||
// new object successfuly added so open gizmo when it was closed
|
|
||||||
GLGizmosManager &manager = canvas->get_gizmos_manager();
|
|
||||||
if(manager.get_current_type() != GLGizmosManager::Emboss)
|
|
||||||
manager.open_gizmo(GLGizmosManager::Emboss);
|
|
||||||
|
|
||||||
// redraw scene
|
|
||||||
canvas->reload_scene(true);
|
|
||||||
|
|
||||||
// Gizmo is not open during time of creation object
|
|
||||||
// When cursor move and no one object is selected than Manager::reset_all()
|
|
||||||
}
|
|
||||||
|
|
||||||
void Priv::create_emboss_volume(EmbossVolume &data)
|
|
||||||
{
|
|
||||||
GUI_App & app = wxGetApp();
|
|
||||||
Plater * plater = app.plater();
|
|
||||||
ObjectList *obj_list = app.obj_list();
|
|
||||||
GLCanvas3D *canvas = plater->canvas3D();
|
|
||||||
|
|
||||||
size_t object_idx = data.object_idx;
|
|
||||||
ModelVolumeType type = data.type;
|
|
||||||
|
|
||||||
// create new volume inside of object
|
|
||||||
Model &model = plater->model();
|
|
||||||
if (model.objects.size() <= object_idx) return;
|
|
||||||
ModelObject *obj = model.objects[object_idx];
|
|
||||||
ModelVolume *volume = obj->add_volume(std::move(data.mesh));
|
|
||||||
|
|
||||||
// set a default extruder value, since user can't add it manually
|
|
||||||
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
|
||||||
|
|
||||||
// do not allow model reload from disk
|
|
||||||
volume->source.is_from_builtin_objects = true;
|
|
||||||
volume->set_type(type);
|
|
||||||
volume->name = data.name;
|
|
||||||
volume->text_configuration = data.cfg;
|
|
||||||
volume->set_transformation(data.transformation);
|
|
||||||
|
|
||||||
// update volume name in object list
|
|
||||||
// updata selection after new volume added
|
|
||||||
// change name of volume in right panel
|
|
||||||
// select only actual volume
|
|
||||||
// when new volume is created change selection to this volume
|
|
||||||
auto add_to_selection = [volume](const ModelVolume *vol) {
|
|
||||||
return vol == volume;
|
|
||||||
};
|
|
||||||
wxDataViewItemArray sel =
|
|
||||||
obj_list->reorder_volumes_and_get_selection((int) object_idx,
|
|
||||||
add_to_selection);
|
|
||||||
if (!sel.IsEmpty()) obj_list->select_item(sel.front());
|
|
||||||
|
|
||||||
// update printable state on canvas
|
|
||||||
if (type == ModelVolumeType::MODEL_PART)
|
|
||||||
canvas->update_instance_printable_state_for_object(object_idx);
|
|
||||||
|
|
||||||
obj_list->selection_changed();
|
|
||||||
|
|
||||||
// WHY selection_changed set manipulation to world ???
|
|
||||||
// so I set it back to local --> RotationGizmo need it
|
|
||||||
ObjectManipulation *manipul = wxGetApp().obj_manipul();
|
|
||||||
manipul->set_coordinates_type(ECoordinatesType::Local);
|
|
||||||
|
|
||||||
|
|
||||||
// redraw scene
|
|
||||||
canvas->reload_scene(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLGizmoEmboss::update_emboss_volume(TriangleMesh && mesh,
|
|
||||||
const std::string& name,
|
|
||||||
const TextConfiguration& cfg,
|
|
||||||
ModelVolume * volume)
|
|
||||||
{
|
|
||||||
// for sure that some object is created from shape
|
|
||||||
if (mesh.its.indices.empty()) return;
|
|
||||||
|
|
||||||
GUI_App & app = wxGetApp(); // may be move to input
|
|
||||||
Plater * plater = app.plater();
|
|
||||||
ObjectList * obj_list = app.obj_list();
|
|
||||||
GLCanvas3D * canvas = plater->canvas3D();
|
|
||||||
GLGizmosManager &manager = canvas->get_gizmos_manager();
|
|
||||||
|
|
||||||
// Check emboss gizmo is still open
|
|
||||||
if (manager.get_current_type() != GLGizmosManager::Emboss) return;
|
|
||||||
|
|
||||||
plater->take_snapshot(_L("Emboss text") + ": " + name);
|
|
||||||
|
|
||||||
// find volume by object id - NOT WORK
|
|
||||||
// -> edit text change volume id so could apper not found volume
|
|
||||||
// ModelVolume *volume = nullptr;
|
|
||||||
// Model &model = plater->model();
|
|
||||||
// for (auto obj : model.objects)
|
|
||||||
// for (auto vol : obj->volumes)
|
|
||||||
// if (vol->id() == volume_id) {
|
|
||||||
// volume = vol;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// if (volume == nullptr) return;
|
|
||||||
assert(volume != nullptr);
|
|
||||||
|
|
||||||
// update volume
|
|
||||||
volume->set_mesh(std::move(mesh));
|
|
||||||
volume->set_new_unique_id();
|
|
||||||
volume->calculate_convex_hull();
|
|
||||||
volume->get_object()->invalidate_bounding_box();
|
|
||||||
volume->name = name;
|
|
||||||
volume->text_configuration = cfg;
|
|
||||||
|
|
||||||
// update volume in right panel( volume / object name)
|
|
||||||
const Selection &selection = canvas->get_selection();
|
|
||||||
const GLVolume * gl_volume = selection.get_volume(
|
|
||||||
*selection.get_volume_idxs().begin());
|
|
||||||
int object_idx = gl_volume->object_idx();
|
|
||||||
int volume_idx = gl_volume->volume_idx();
|
|
||||||
obj_list->update_name_in_list(object_idx, volume_idx);
|
|
||||||
|
|
||||||
// update printable state on canvas
|
|
||||||
if (volume->type() == ModelVolumeType::MODEL_PART)
|
|
||||||
canvas->update_instance_printable_state_for_object(
|
|
||||||
(size_t) object_idx);
|
|
||||||
|
|
||||||
// redraw scene
|
|
||||||
canvas->reload_scene(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// any existing icon filename to not influence GUI
|
// any existing icon filename to not influence GUI
|
||||||
const std::string GLGizmoEmboss::M_ICON_FILENAME = "cut.svg";
|
const std::string GLGizmoEmboss::M_ICON_FILENAME = "cut.svg";
|
||||||
|
@ -28,12 +28,10 @@ namespace Slic3r{
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r::GUI {
|
namespace Slic3r::GUI {
|
||||||
class EmbossJob;
|
|
||||||
class MeshRaycaster;
|
class MeshRaycaster;
|
||||||
|
|
||||||
class GLGizmoEmboss : public GLGizmoBase
|
class GLGizmoEmboss : public GLGizmoBase
|
||||||
{
|
{
|
||||||
friend EmbossJob;
|
|
||||||
public:
|
public:
|
||||||
GLGizmoEmboss(GLCanvas3D& parent);
|
GLGizmoEmboss(GLCanvas3D& parent);
|
||||||
|
|
||||||
@ -76,20 +74,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void initialize();
|
void initialize();
|
||||||
void set_default_text();
|
void set_default_text();
|
||||||
static TriangleMesh create_default_mesh();
|
|
||||||
TriangleMesh create_mesh();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create mesh from text
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">Text to convert on mesh</param>
|
|
||||||
/// <param name="font">Define shape of characters.
|
|
||||||
/// NOTE: Can't be const cache glyphs</param>
|
|
||||||
/// <param name="font_prop">Property of font</param>
|
|
||||||
/// <returns>Triangle mesh model</returns>
|
|
||||||
static TriangleMesh create_mesh(const char * text,
|
|
||||||
Emboss::FontFile & font,
|
|
||||||
const FontProp &font_prop);
|
|
||||||
|
|
||||||
void check_selection();
|
void check_selection();
|
||||||
// more general function --> move to select
|
// more general function --> move to select
|
||||||
@ -219,22 +203,6 @@ private:
|
|||||||
void store_font_list_to_app_config() const;
|
void store_font_list_to_app_config() const;
|
||||||
void store_font_item_to_app_config() const;
|
void store_font_item_to_app_config() const;
|
||||||
|
|
||||||
// call after functions to work outside of drawing
|
|
||||||
static void create_emboss_object(TriangleMesh && mesh,
|
|
||||||
const Transform3d &transformation,
|
|
||||||
const std::string &name,
|
|
||||||
const TextConfiguration &cfg);
|
|
||||||
static void create_emboss_volume(TriangleMesh && mesh,
|
|
||||||
Transform3d transformation,
|
|
||||||
std::string name,
|
|
||||||
TextConfiguration cfg,
|
|
||||||
ModelVolumeType type,
|
|
||||||
size_t object_idx);
|
|
||||||
static void update_emboss_volume(TriangleMesh && mesh,
|
|
||||||
const std::string & name,
|
|
||||||
const TextConfiguration &cfg,
|
|
||||||
ModelVolume * volume);
|
|
||||||
|
|
||||||
// only temporary solution
|
// only temporary solution
|
||||||
static const std::string M_ICON_FILENAME;
|
static const std::string M_ICON_FILENAME;
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "EmbossJob.hpp"
|
#include "EmbossJob.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Model.hpp"
|
#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/Plater.hpp"
|
||||||
#include "slic3r/GUI/NotificationManager.hpp"
|
#include "slic3r/GUI/NotificationManager.hpp"
|
||||||
@ -9,12 +11,15 @@
|
|||||||
#include "slic3r/GUI/MainFrame.hpp"
|
#include "slic3r/GUI/MainFrame.hpp"
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
|
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||||
#include "slic3r/GUI/Gizmos/GLGizmoEmboss.hpp"
|
#include "slic3r/GUI/Gizmos/GLGizmoEmboss.hpp"
|
||||||
|
#include "slic3r/GUI/CameraUtils.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace GUI;
|
using namespace GUI;
|
||||||
|
|
||||||
void EmbossJob::process(Ctl &ctl) {
|
void EmbossUpdateJob::process(Ctl &ctl)
|
||||||
|
{
|
||||||
// Changing cursor to busy must be inside main thread
|
// Changing cursor to busy must be inside main thread
|
||||||
// GTK is not thread safe.
|
// GTK is not thread safe.
|
||||||
//wxBeginBusyCursor();
|
//wxBeginBusyCursor();
|
||||||
@ -24,7 +29,7 @@ void EmbossJob::process(Ctl &ctl) {
|
|||||||
assert(m_input != nullptr);
|
assert(m_input != nullptr);
|
||||||
|
|
||||||
// check if exist valid font
|
// check if exist valid font
|
||||||
if (m_input->font == nullptr) return;
|
if (m_input->font_file == nullptr) return;
|
||||||
|
|
||||||
const TextConfiguration &cfg = m_input->text_configuration;
|
const TextConfiguration &cfg = m_input->text_configuration;
|
||||||
const std::string & text = cfg.text;
|
const std::string & text = cfg.text;
|
||||||
@ -32,7 +37,7 @@ void EmbossJob::process(Ctl &ctl) {
|
|||||||
if (text.empty()) return;
|
if (text.empty()) return;
|
||||||
|
|
||||||
const FontProp &prop = cfg.font_item.prop;
|
const FontProp &prop = cfg.font_item.prop;
|
||||||
ExPolygons shapes = Emboss::text2shapes(*m_input->font, text.c_str(), prop);
|
ExPolygons shapes = Emboss::text2shapes(*m_input->font_file, text.c_str(), prop);
|
||||||
|
|
||||||
if (ctl.was_canceled()) return;
|
if (ctl.was_canceled()) return;
|
||||||
|
|
||||||
@ -40,7 +45,7 @@ void EmbossJob::process(Ctl &ctl) {
|
|||||||
// (no shape means that font hasn't any of text symbols)
|
// (no shape means that font hasn't any of text symbols)
|
||||||
if (shapes.empty()) return;
|
if (shapes.empty()) return;
|
||||||
|
|
||||||
float scale = prop.size_in_mm / m_input->font->ascent;
|
float scale = prop.size_in_mm / m_input->font_file->ascent;
|
||||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
|
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
|
||||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||||
m_result = TriangleMesh(Emboss::polygons2model(shapes, project));
|
m_result = TriangleMesh(Emboss::polygons2model(shapes, project));
|
||||||
@ -52,14 +57,213 @@ void EmbossJob::process(Ctl &ctl) {
|
|||||||
m_result.translate(-shift.cast<float>());
|
m_result.translate(-shift.cast<float>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbossJob::finalize(bool canceled, std::exception_ptr &) {
|
void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
|
||||||
|
{
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
// for sure that some object is created from shape
|
// for sure that some object is created from shape
|
||||||
if (m_result.its.indices.empty()) return;
|
if (m_result.its.indices.empty()) return;
|
||||||
|
|
||||||
GLGizmoEmboss::update_emboss_volume(std::move(m_result),
|
GUI_App & app = wxGetApp(); // may be move to input
|
||||||
m_input->volume_name,
|
Plater * plater = app.plater();
|
||||||
m_input->text_configuration,
|
ObjectList * obj_list = app.obj_list();
|
||||||
m_input->volume);
|
GLCanvas3D * canvas = plater->canvas3D();
|
||||||
|
GLGizmosManager &manager = canvas->get_gizmos_manager();
|
||||||
|
|
||||||
|
// Check emboss gizmo is still open
|
||||||
|
if (manager.get_current_type() != GLGizmosManager::Emboss) return;
|
||||||
|
|
||||||
|
plater->take_snapshot(_L("Emboss text") + ": " + m_input->volume_name);
|
||||||
|
|
||||||
|
ModelVolume *volume = m_input->volume;
|
||||||
|
// find volume by object id - NOT WORK
|
||||||
|
// -> edit text change volume id so could apper not found volume
|
||||||
|
// ModelVolume *volume = nullptr;
|
||||||
|
// Model &model = plater->model();
|
||||||
|
// for (auto obj : model.objects)
|
||||||
|
// for (auto vol : obj->volumes)
|
||||||
|
// if (vol->id() == volume_id) {
|
||||||
|
// volume = vol;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// if (volume == nullptr) return;
|
||||||
|
assert(volume != nullptr);
|
||||||
|
|
||||||
|
// update volume
|
||||||
|
volume->set_mesh(std::move(m_result));
|
||||||
|
volume->set_new_unique_id();
|
||||||
|
volume->calculate_convex_hull();
|
||||||
|
volume->get_object()->invalidate_bounding_box();
|
||||||
|
volume->name = m_input->volume_name;
|
||||||
|
volume->text_configuration = m_input->text_configuration;
|
||||||
|
|
||||||
|
// update volume in right panel( volume / object name)
|
||||||
|
const Selection &selection = canvas->get_selection();
|
||||||
|
const GLVolume * gl_volume = selection.get_volume(
|
||||||
|
*selection.get_volume_idxs().begin());
|
||||||
|
int object_idx = gl_volume->object_idx();
|
||||||
|
int volume_idx = gl_volume->volume_idx();
|
||||||
|
obj_list->update_name_in_list(object_idx, volume_idx);
|
||||||
|
|
||||||
|
// update printable state on canvas
|
||||||
|
if (volume->type() == ModelVolumeType::MODEL_PART)
|
||||||
|
canvas->update_instance_printable_state_for_object(
|
||||||
|
(size_t) object_idx);
|
||||||
|
|
||||||
|
// redraw scene
|
||||||
|
canvas->reload_scene(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmbossCreateJob::process(Ctl &ctl) {
|
||||||
|
// It is neccessary to create some shape
|
||||||
|
// Emboss text window is opened by creation new emboss text object
|
||||||
|
m_result = (m_input->font_file == nullptr) ?
|
||||||
|
create_default_mesh() :
|
||||||
|
create_mesh(m_input->text_configuration.text.c_str(),
|
||||||
|
*m_input->font_file,
|
||||||
|
m_input->text_configuration.font_item.prop);
|
||||||
|
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);
|
||||||
|
if (ctl.was_canceled()) return;
|
||||||
|
hit = m_input->raycast_manager->unproject(m_input->screen_coor);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// also hit must exist. But there is proper behavior when hit doesn't
|
||||||
|
// exists. When this assert appear distquish remove of it.
|
||||||
|
assert(hit.has_value());
|
||||||
|
if (!hit.has_value()) m_input->object_idx.reset();
|
||||||
|
}
|
||||||
|
if (!hit.has_value()) {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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_.emplace_back(p.cast<int>());
|
||||||
|
Polygon bed(bed_shape_);
|
||||||
|
if (!bed.contains(bed_coor.cast<int>()))
|
||||||
|
// mouse pose is out of build plate so create object in center of plate
|
||||||
|
bed_coor = bed.centroid().cast<double>();
|
||||||
|
|
||||||
|
double z = m_input->text_configuration.font_item.prop.emboss / 2;
|
||||||
|
Vec3d offset(bed_coor.x(), bed_coor.y(), z);
|
||||||
|
offset -= m_result.center();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmbossCreateJob::finalize(bool canceled, std::exception_ptr &)
|
||||||
|
{
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
GUI_App & app = wxGetApp();
|
||||||
|
Plater * plater = app.plater();
|
||||||
|
ObjectList *obj_list = app.obj_list();
|
||||||
|
GLCanvas3D *canvas = plater->canvas3D();
|
||||||
|
|
||||||
|
// decide if create object or volume
|
||||||
|
bool create_object = !m_input->object_idx.has_value();
|
||||||
|
if (create_object) {
|
||||||
|
plater->take_snapshot(_L("Add Emboss text object"));
|
||||||
|
// Create new object and change selection
|
||||||
|
bool center = false;
|
||||||
|
obj_list->load_mesh_object(std::move(m_result), m_input->volume_name, center,
|
||||||
|
&m_input->text_configuration, &m_transformation);
|
||||||
|
|
||||||
|
// When add new object selection is empty.
|
||||||
|
// When cursor move and no one object is selected than Manager::reset_all()
|
||||||
|
// So Gizmo could be closed on end of creation object
|
||||||
|
GLGizmosManager &manager = canvas->get_gizmos_manager();
|
||||||
|
if (manager.get_current_type() != GLGizmosManager::Emboss)
|
||||||
|
manager.open_gizmo(GLGizmosManager::Emboss);
|
||||||
|
} else {
|
||||||
|
// create volume in object
|
||||||
|
size_t object_idx = *m_input->object_idx;
|
||||||
|
ModelVolumeType type = m_input->volume_type;
|
||||||
|
|
||||||
|
// create new volume inside of object
|
||||||
|
Model &model = plater->model();
|
||||||
|
if (model.objects.size() <= object_idx) return;
|
||||||
|
ModelObject *obj = model.objects[object_idx];
|
||||||
|
ModelVolume *volume = obj->add_volume(std::move(m_result));
|
||||||
|
|
||||||
|
// set a default extruder value, since user can't add it manually
|
||||||
|
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
|
|
||||||
|
// do not allow model reload from disk
|
||||||
|
volume->source.is_from_builtin_objects = true;
|
||||||
|
volume->set_type(type);
|
||||||
|
volume->name = m_input->volume_name;
|
||||||
|
volume->text_configuration = m_input->text_configuration;
|
||||||
|
volume->set_transformation(m_transformation);
|
||||||
|
|
||||||
|
// update volume name in object list
|
||||||
|
// updata selection after new volume added
|
||||||
|
// change name of volume in right panel
|
||||||
|
// select only actual volume
|
||||||
|
// when new volume is created change selection to this volume
|
||||||
|
auto add_to_selection = [volume](const ModelVolume *vol) {
|
||||||
|
return vol == volume;
|
||||||
|
};
|
||||||
|
wxDataViewItemArray sel =
|
||||||
|
obj_list->reorder_volumes_and_get_selection((int) object_idx,
|
||||||
|
add_to_selection);
|
||||||
|
if (!sel.IsEmpty()) obj_list->select_item(sel.front());
|
||||||
|
|
||||||
|
// update printable state on canvas
|
||||||
|
if (type == ModelVolumeType::MODEL_PART)
|
||||||
|
canvas->update_instance_printable_state_for_object(object_idx);
|
||||||
|
|
||||||
|
obj_list->selection_changed();
|
||||||
|
|
||||||
|
// WHY selection_changed set manipulation to world ???
|
||||||
|
// so I set it back to local --> RotationGizmo need it
|
||||||
|
ObjectManipulation *manipul = wxGetApp().obj_manipul();
|
||||||
|
manipul->set_coordinates_type(ECoordinatesType::Local);
|
||||||
|
}
|
||||||
|
// redraw scene
|
||||||
|
canvas->reload_scene(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh EmbossCreateJob::create_default_mesh()
|
||||||
|
{
|
||||||
|
// When cant load any font use default object loaded from file
|
||||||
|
std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl";
|
||||||
|
TriangleMesh triangle_mesh;
|
||||||
|
if (!load_obj(path.c_str(), &triangle_mesh)) {
|
||||||
|
// when can't load mesh use cube
|
||||||
|
return TriangleMesh(its_make_cube(36., 4., 2.5));
|
||||||
|
}
|
||||||
|
return triangle_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh EmbossCreateJob::create_mesh(const char * text,
|
||||||
|
Emboss::FontFile &font,
|
||||||
|
const FontProp & font_prop)
|
||||||
|
{
|
||||||
|
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
|
||||||
|
float scale = font_prop.size_in_mm / font.ascent;
|
||||||
|
float depth = font_prop.emboss / scale;
|
||||||
|
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
|
||||||
|
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||||
|
return TriangleMesh(Emboss::polygons2model(shapes, project));
|
||||||
}
|
}
|
@ -1,7 +1,9 @@
|
|||||||
#ifndef slic3r_EmbossJob_hpp_
|
#ifndef slic3r_EmbossJob_hpp_
|
||||||
#define slic3r_EmbossJob_hpp_
|
#define slic3r_EmbossJob_hpp_
|
||||||
|
|
||||||
#include "libslic3r/Emboss.hpp"
|
#include <libslic3r/Emboss.hpp>
|
||||||
|
#include <libslic3r/ModelVolumeType.hpp>
|
||||||
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
#include "Job.hpp"
|
#include "Job.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -11,15 +13,71 @@ class TriangleMesh;
|
|||||||
|
|
||||||
namespace Slic3r::GUI {
|
namespace Slic3r::GUI {
|
||||||
|
|
||||||
struct EmbossData
|
struct EmbossDataUpdate;
|
||||||
|
struct EmbossDataCreate;
|
||||||
|
|
||||||
|
class EmbossUpdateJob : public Job
|
||||||
|
{
|
||||||
|
std::unique_ptr<EmbossDataUpdate> m_input;
|
||||||
|
TriangleMesh m_result;
|
||||||
|
public:
|
||||||
|
EmbossUpdateJob(std::unique_ptr<EmbossDataUpdate> input) : m_input(std::move(input)) {}
|
||||||
|
void process(Ctl &ctl) override;
|
||||||
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EmbossCreateJob : public Job
|
||||||
|
{
|
||||||
|
std::unique_ptr<EmbossDataCreate> m_input;
|
||||||
|
TriangleMesh m_result;
|
||||||
|
Transform3d m_transformation;
|
||||||
|
public:
|
||||||
|
EmbossCreateJob(std::unique_ptr<EmbossDataCreate> input): m_input(std::move(input)){}
|
||||||
|
void process(Ctl &ctl) override;
|
||||||
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TriangleMesh create_default_mesh();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create mesh from text
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Text to convert on mesh</param>
|
||||||
|
/// <param name="font">Define shape of characters.
|
||||||
|
/// NOTE: Can't be const cache glyphs</param>
|
||||||
|
/// <param name="font_prop">Property of font</param>
|
||||||
|
/// <returns>Triangle mesh model</returns>
|
||||||
|
static TriangleMesh create_mesh(const char * text,
|
||||||
|
Emboss::FontFile &font,
|
||||||
|
const FontProp & font_prop);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base data holder for embossing
|
||||||
|
/// </summary>
|
||||||
|
struct EmbossDataBase
|
||||||
{
|
{
|
||||||
// Pointer on Data of font (glyph shapes)
|
// Pointer on Data of font (glyph shapes)
|
||||||
std::shared_ptr<Emboss::FontFile> font;
|
std::shared_ptr<Emboss::FontFile> font_file;
|
||||||
// font item is not used for create object
|
// font item is not used for create object
|
||||||
TextConfiguration text_configuration;
|
TextConfiguration text_configuration;
|
||||||
// new volume name created from text
|
// new volume name created from text
|
||||||
std::string volume_name;
|
std::string volume_name;
|
||||||
|
EmbossDataBase(std::shared_ptr<Emboss::FontFile> font_file,
|
||||||
|
TextConfiguration text_configuration,
|
||||||
|
std::string volume_name)
|
||||||
|
: font_file(std::move(font_file))
|
||||||
|
, text_configuration(text_configuration)
|
||||||
|
, volume_name(volume_name)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hold neccessary data to update embossed text object in job
|
||||||
|
/// </summary>
|
||||||
|
struct EmbossDataUpdate : public EmbossDataBase
|
||||||
|
{
|
||||||
// unique identifier of volume to change
|
// unique identifier of volume to change
|
||||||
// I can't proove of alive pointer
|
// I can't proove of alive pointer
|
||||||
ModelVolume *volume;
|
ModelVolume *volume;
|
||||||
@ -27,26 +85,47 @@ struct EmbossData
|
|||||||
// unique identifier of volume to change
|
// unique identifier of volume to change
|
||||||
// Change of volume change id, last change could disapear
|
// Change of volume change id, last change could disapear
|
||||||
// ObjectID volume_id;
|
// ObjectID volume_id;
|
||||||
|
EmbossDataUpdate(std::shared_ptr<Emboss::FontFile> font_file,
|
||||||
EmbossData(std::shared_ptr<Emboss::FontFile> font,
|
|
||||||
TextConfiguration text_configuration,
|
TextConfiguration text_configuration,
|
||||||
std::string volume_name,
|
std::string volume_name,
|
||||||
ModelVolume * volume)
|
ModelVolume * volume)
|
||||||
: font(std::move(font))
|
: EmbossDataBase(std::move(font_file), text_configuration, volume_name)
|
||||||
, text_configuration(text_configuration)
|
|
||||||
, volume_name(volume_name)
|
|
||||||
, volume(volume)
|
, volume(volume)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmbossJob : public Job
|
/// <summary>
|
||||||
|
/// Hold neccessary data to create embossed text object in job
|
||||||
|
/// </summary>
|
||||||
|
struct EmbossDataCreate: public EmbossDataBase
|
||||||
{
|
{
|
||||||
std::unique_ptr<EmbossData> m_input;
|
// define embossed volume type
|
||||||
TriangleMesh m_result;
|
ModelVolumeType volume_type;
|
||||||
public:
|
|
||||||
EmbossJob(std::unique_ptr<EmbossData> input) : m_input(std::move(input)) {}
|
// define position on screen where to create object
|
||||||
void process(Ctl &ctl) override;
|
Vec2d screen_coor;
|
||||||
void finalize(bool canceled, std::exception_ptr &) override;
|
|
||||||
|
// when exist ModelObject where to create volume
|
||||||
|
std::optional<int> object_idx;
|
||||||
|
|
||||||
|
// used to find point on surface where to create new object
|
||||||
|
RaycastManager *raycast_manager;
|
||||||
|
// It is inside of GLGizmoEmboss object,
|
||||||
|
// so I hope it will survive
|
||||||
|
|
||||||
|
EmbossDataCreate(std::shared_ptr<Emboss::FontFile> font_file,
|
||||||
|
const TextConfiguration & text_configuration,
|
||||||
|
const std::string & volume_name,
|
||||||
|
ModelVolumeType volume_type,
|
||||||
|
Vec2d screen_coor,
|
||||||
|
std::optional<int> object_idx,
|
||||||
|
RaycastManager * raycast_manager)
|
||||||
|
: EmbossDataBase(std::move(font_file), text_configuration, volume_name)
|
||||||
|
, volume_type(volume_type)
|
||||||
|
, screen_coor(screen_coor)
|
||||||
|
, object_idx(object_idx)
|
||||||
|
, raycast_manager(raycast_manager)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
} // namespace Slic3r::GUI
|
||||||
|
Loading…
x
Reference in New Issue
Block a user