mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 23:06:13 +08:00
Do not use RaycastManager inside job
Separate Jobs for Creation of volume from creation of Object
This commit is contained in:
parent
3b55de7e0b
commit
e8cfe35f78
@ -145,30 +145,18 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||||||
screen_coor.y() = screen_size.get_height() / 2.;
|
screen_coor.y() = screen_size.get_height() / 2.;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int> object_idx;
|
if (start_volume_creation(volume_type, screen_coor)) return;
|
||||||
|
|
||||||
std::optional<Transform3d> hit_vol_tr;
|
// start creation of new object
|
||||||
const Selection &selection = m_parent.get_selection();
|
|
||||||
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();
|
Plater* plater = wxGetApp().plater();
|
||||||
const Camera &camera = plater->get_camera();
|
const Camera &camera = plater->get_camera();
|
||||||
auto data = std::make_unique<EmbossDataCreate>(
|
const Pointfs &bed_shape = plater->build_volume().bed_shape();
|
||||||
m_font_manager.get_font().font_file_with_cache,
|
auto &worker = plater->get_ui_job_worker();
|
||||||
create_configuration(),
|
auto data = std::make_unique<EmbossDataCreateObject>(
|
||||||
create_volume_name(), volume_type, screen_coor, object_idx,
|
m_font_manager.get_font().font_file_with_cache,
|
||||||
hit_vol_tr, camera,
|
create_configuration(), create_volume_name(),
|
||||||
plater->build_volume().bed_shape(),
|
screen_coor, camera, bed_shape);
|
||||||
&m_raycast_manager);
|
queue_job(worker, std::make_unique<EmbossCreateObjectJob>(std::move(data)));
|
||||||
|
|
||||||
auto &worker = plater->get_ui_job_worker();
|
|
||||||
queue_job(worker, std::make_unique<EmbossCreateJob>(std::move(data)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
#ifdef DRAW_PLACE_TO_ADD_TEXT
|
||||||
@ -599,6 +587,58 @@ void GLGizmoEmboss::set_default_text()
|
|||||||
m_text = _u8L("Embossed text");
|
m_text = _u8L("Embossed text");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLGizmoEmboss::start_volume_creation(ModelVolumeType volume_type,
|
||||||
|
const Vec2d &screen_coor)
|
||||||
|
{
|
||||||
|
Plater* plater = wxGetApp().plater();
|
||||||
|
|
||||||
|
const Selection &selection = m_parent.get_selection();
|
||||||
|
if (selection.is_empty()) return false;
|
||||||
|
|
||||||
|
int hovered_id_signed = m_parent.get_first_hover_volume_idx();
|
||||||
|
if (hovered_id_signed < 0) return false;
|
||||||
|
|
||||||
|
size_t hovered_id = static_cast<size_t>(hovered_id_signed);
|
||||||
|
auto &volumes = m_parent.get_volumes().volumes;
|
||||||
|
if (hovered_id >= volumes.size()) return false;
|
||||||
|
|
||||||
|
int object_idx_signed = selection.get_object_idx();
|
||||||
|
if (object_idx_signed < 0) return false;
|
||||||
|
|
||||||
|
size_t object_idx = static_cast<size_t>(object_idx_signed);
|
||||||
|
auto &objects = plater->model().objects;
|
||||||
|
if (object_idx >= objects.size()) return false;
|
||||||
|
|
||||||
|
ModelObject *obj = objects[object_idx];
|
||||||
|
m_raycast_manager.actualize(obj);
|
||||||
|
|
||||||
|
const Camera &camera = plater->get_camera();
|
||||||
|
std::optional<RaycastManager::Hit> hit =
|
||||||
|
m_raycast_manager.unproject(screen_coor, 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
|
||||||
|
// 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()) return false;
|
||||||
|
|
||||||
|
Transform3d hit_object_trmat = m_raycast_manager.get_transformation(hit->tr_key);
|
||||||
|
|
||||||
|
GLVolume *gl_volume = volumes[hovered_id];
|
||||||
|
Transform3d hit_instance_trmat = gl_volume->get_instance_transformation().get_matrix();
|
||||||
|
|
||||||
|
// create volume
|
||||||
|
auto &worker = plater->get_ui_job_worker();
|
||||||
|
auto data = std::make_unique<EmbossDataCreateVolume>(
|
||||||
|
m_font_manager.get_font().font_file_with_cache,
|
||||||
|
create_configuration(), create_volume_name(), volume_type,
|
||||||
|
screen_coor, object_idx, camera, *hit, hit_object_trmat,
|
||||||
|
hit_instance_trmat);
|
||||||
|
queue_job(worker, std::make_unique<EmbossCreateVolumeJob>(std::move(data)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#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()
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,8 @@ private:
|
|||||||
static FontList create_default_font_list();
|
static FontList create_default_font_list();
|
||||||
void set_default_text();
|
void set_default_text();
|
||||||
|
|
||||||
|
bool start_volume_creation(ModelVolumeType volume_type, const Vec2d &screen_coor);
|
||||||
|
|
||||||
void check_selection();
|
void check_selection();
|
||||||
// more general function --> move to select
|
// more general function --> move to select
|
||||||
ModelVolume *get_selected_volume();
|
ModelVolume *get_selected_volume();
|
||||||
|
@ -19,14 +19,43 @@
|
|||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace GUI;
|
using namespace GUI;
|
||||||
|
|
||||||
|
// private namespace
|
||||||
|
namespace priv{
|
||||||
|
// <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>
|
||||||
|
/// <param name="ctl">Control for job, check of cancelation</param>
|
||||||
|
/// <returns>Triangle mesh model</returns>
|
||||||
|
static TriangleMesh create_mesh(const char *text,
|
||||||
|
Emboss::FontFileWithCache &font,
|
||||||
|
const FontProp &font_prop,
|
||||||
|
GUI::Job::Ctl &ctl);
|
||||||
|
/// <summary>
|
||||||
|
/// Create default mesh for embossed text
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Not empty model(index trinagle set - its)</returns>
|
||||||
|
static TriangleMesh create_default_mesh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
/// Update Volume
|
||||||
|
EmbossUpdateJob::EmbossUpdateJob(std::unique_ptr<EmbossDataUpdate> input)
|
||||||
|
: m_input(std::move(input))
|
||||||
|
{}
|
||||||
|
|
||||||
void EmbossUpdateJob::process(Ctl &ctl)
|
void EmbossUpdateJob::process(Ctl &ctl)
|
||||||
{
|
{
|
||||||
// check if exist valid font
|
// check if exist valid font
|
||||||
if (!m_input->font_file.has_value()) return;
|
if (!m_input->font_file.has_value()) return;
|
||||||
|
|
||||||
const TextConfiguration &cfg = m_input->text_configuration;
|
const TextConfiguration &cfg = m_input->text_configuration;
|
||||||
m_result = EmbossCreateJob::create_mesh(
|
m_result = priv::create_mesh(cfg.text.c_str(), m_input->font_file,
|
||||||
cfg.text.c_str(), m_input->font_file, cfg.font_item.prop, ctl);
|
cfg.font_item.prop, ctl);
|
||||||
if (m_result.its.empty()) return;
|
if (m_result.its.empty()) return;
|
||||||
if (ctl.was_canceled()) return;
|
if (ctl.was_canceled()) return;
|
||||||
|
|
||||||
@ -95,155 +124,169 @@ void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
|
|||||||
canvas->reload_scene(true);
|
canvas->reload_scene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbossCreateJob::process(Ctl &ctl) {
|
|
||||||
|
/////////////////
|
||||||
|
/// Create Volume
|
||||||
|
EmbossCreateVolumeJob::EmbossCreateVolumeJob(
|
||||||
|
std::unique_ptr<EmbossDataCreateVolume> input)
|
||||||
|
: m_input(std::move(input))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void EmbossCreateVolumeJob::process(Ctl &ctl) {
|
||||||
// It is neccessary to create some shape
|
// It is neccessary to create some shape
|
||||||
// Emboss text window is opened by creation new emboss text object
|
// Emboss text window is opened by creation new emboss text object
|
||||||
const char *text = m_input->text_configuration.text.c_str();
|
const char *text = m_input->text_configuration.text.c_str();
|
||||||
FontProp &prop = m_input->text_configuration.font_item.prop;
|
FontProp &prop = m_input->text_configuration.font_item.prop;
|
||||||
m_result = (m_input->font_file.has_value()) ?
|
|
||||||
create_mesh(text, m_input->font_file, prop, ctl):
|
m_result = priv::create_mesh(text, m_input->font_file, prop, ctl);
|
||||||
create_default_mesh();
|
if (m_result.its.empty()) m_result = priv::create_default_mesh();
|
||||||
if (m_result.its.empty()) m_result = create_default_mesh();
|
|
||||||
if (ctl.was_canceled()) return;
|
if (ctl.was_canceled()) return;
|
||||||
|
|
||||||
std::optional<RaycastManager::Hit> hit;
|
// Create new volume inside of object
|
||||||
if (m_input->object_idx.has_value()) {
|
const FontProp &font_prop = m_input->text_configuration.font_item.prop;
|
||||||
// By position of cursor create transformation to put text on surface of model
|
Transform3d surface_trmat = Emboss::create_transformation_onto_surface(
|
||||||
ModelObject *obj = wxGetApp().plater()->model().objects[*m_input->object_idx];
|
m_input->hit.position, m_input->hit.normal);
|
||||||
m_input->raycast_manager->actualize(obj);
|
Emboss::apply_transformation(font_prop, surface_trmat);
|
||||||
if (ctl.was_canceled()) return;
|
m_transformation = m_input->hit_instance_tr.inverse() *
|
||||||
hit = m_input->raycast_manager->unproject(m_input->screen_coor, m_input->camera);
|
m_input->hit_object_tr * surface_trmat;
|
||||||
|
|
||||||
// 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
|
|
||||||
Vec2d bed_coor = CameraUtils::get_z0_position(m_input->camera, m_input->screen_coor);
|
|
||||||
|
|
||||||
// check point is on build plate:
|
|
||||||
Points 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>()))
|
|
||||||
// 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);
|
|
||||||
assert(m_input->hit_vol_tr.has_value());
|
|
||||||
if (m_input->hit_vol_tr.has_value()) {
|
|
||||||
Transform3d object_trmat = m_input->raycast_manager->get_transformation(hit->tr_key);
|
|
||||||
const FontProp &font_prop = m_input->text_configuration.font_item.prop;
|
|
||||||
Transform3d surface_trmat = Emboss::create_transformation_onto_surface(hit->position, hit->normal);
|
|
||||||
Emboss::apply_transformation(font_prop, surface_trmat);
|
|
||||||
m_transformation = m_input->hit_vol_tr->inverse() * object_trmat * surface_trmat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbossCreateJob::finalize(bool canceled, std::exception_ptr &)
|
void EmbossCreateVolumeJob::finalize(bool canceled, std::exception_ptr &) {
|
||||||
{
|
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
GUI_App & app = wxGetApp();
|
GUI_App &app = wxGetApp();
|
||||||
Plater * plater = app.plater();
|
Plater *plater = app.plater();
|
||||||
ObjectList *obj_list = app.obj_list();
|
ObjectList *obj_list = app.obj_list();
|
||||||
GLCanvas3D *canvas = plater->canvas3D();
|
GLCanvas3D *canvas = plater->canvas3D();
|
||||||
|
Model &model = plater->model();
|
||||||
|
|
||||||
// decide if create object or volume
|
// create volume in object
|
||||||
bool create_object = !m_input->object_idx.has_value();
|
size_t object_idx = m_input->object_idx;
|
||||||
if (create_object) {
|
assert(model.objects.size() > object_idx);
|
||||||
Plater::TakeSnapshot snapshot(plater, _L("Add Emboss text object"));
|
if (model.objects.size() <= object_idx) return;
|
||||||
// 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.
|
Plater::TakeSnapshot snapshot(plater, _L("Add Emboss text Volume"));
|
||||||
// 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
|
ModelObject *obj = model.objects[object_idx];
|
||||||
Model &model = plater->model();
|
ModelVolumeType type = m_input->volume_type;
|
||||||
if (model.objects.size() <= object_idx) return;
|
ModelVolume *volume = obj->add_volume(std::move(m_result), type);
|
||||||
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
|
// set a default extruder value, since user can't add it manually
|
||||||
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
|
|
||||||
// do not allow model reload from disk
|
// do not allow model reload from disk
|
||||||
volume->source.is_from_builtin_objects = true;
|
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
|
volume->name = m_input->volume_name;
|
||||||
// updata selection after new volume added
|
volume->text_configuration = std::move(m_input->text_configuration);
|
||||||
// change name of volume in right panel
|
volume->set_transformation(m_transformation);
|
||||||
// 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
|
// update volume name in object list
|
||||||
if (type == ModelVolumeType::MODEL_PART)
|
// updata selection after new volume added
|
||||||
canvas->update_instance_printable_state_for_object(object_idx);
|
// 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());
|
||||||
|
|
||||||
obj_list->selection_changed();
|
// 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);
|
||||||
|
|
||||||
// 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
|
// redraw scene
|
||||||
canvas->reload_scene(true);
|
canvas->reload_scene(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMesh EmbossCreateJob::create_default_mesh()
|
|
||||||
|
/////////////////
|
||||||
|
/// Create Object
|
||||||
|
EmbossCreateObjectJob::EmbossCreateObjectJob(
|
||||||
|
std::unique_ptr<EmbossDataCreateObject> input)
|
||||||
|
: m_input(std::move(input))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void EmbossCreateObjectJob::process(Ctl &ctl)
|
||||||
{
|
{
|
||||||
// When cant load any font use default object loaded from file
|
// It is neccessary to create some shape
|
||||||
std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl";
|
// Emboss text window is opened by creation new emboss text object
|
||||||
TriangleMesh triangle_mesh;
|
const char *text = m_input->text_configuration.text.c_str();
|
||||||
if (!load_obj(path.c_str(), &triangle_mesh)) {
|
FontProp &prop = m_input->text_configuration.font_item.prop;
|
||||||
// when can't load mesh use cube
|
|
||||||
return TriangleMesh(its_make_cube(36., 4., 2.5));
|
m_result = priv::create_mesh(text, m_input->font_file, prop, ctl);
|
||||||
}
|
if (m_result.its.empty()) m_result = priv::create_default_mesh();
|
||||||
return triangle_mesh;
|
|
||||||
|
if (ctl.was_canceled()) return;
|
||||||
|
|
||||||
|
// Create new object
|
||||||
|
// calculate X,Y offset position for lay on platter in place of
|
||||||
|
// mouse click
|
||||||
|
Vec2d bed_coor = CameraUtils::get_z0_position(
|
||||||
|
m_input->camera, m_input->screen_coor);
|
||||||
|
|
||||||
|
// check point is on build plate:
|
||||||
|
Points 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>()))
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMesh EmbossCreateJob::create_mesh(const char *text,
|
void EmbossCreateObjectJob::finalize(bool canceled, std::exception_ptr &)
|
||||||
Emboss::FontFileWithCache &font,
|
{
|
||||||
const FontProp &font_prop,
|
if (canceled) return;
|
||||||
Ctl &ctl)
|
|
||||||
|
GUI_App &app = wxGetApp();
|
||||||
|
Plater *plater = app.plater();
|
||||||
|
ObjectList *obj_list = app.obj_list();
|
||||||
|
GLCanvas3D *canvas = plater->canvas3D();
|
||||||
|
|
||||||
|
Plater::TakeSnapshot snapshot(plater, _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 before end of creation object
|
||||||
|
GLGizmosManager &manager = canvas->get_gizmos_manager();
|
||||||
|
if (manager.get_current_type() != GLGizmosManager::Emboss)
|
||||||
|
manager.open_gizmo(GLGizmosManager::Emboss);
|
||||||
|
|
||||||
|
// redraw scene
|
||||||
|
canvas->reload_scene(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
/// private namespace implementation
|
||||||
|
TriangleMesh priv::create_mesh(const char *text,
|
||||||
|
Emboss::FontFileWithCache &font,
|
||||||
|
const FontProp &font_prop,
|
||||||
|
GUI::Job::Ctl &ctl)
|
||||||
{
|
{
|
||||||
assert(font.has_value());
|
assert(font.has_value());
|
||||||
if (!font.has_value()) return {};
|
if (!font.has_value()) return {};
|
||||||
@ -259,4 +302,16 @@ TriangleMesh EmbossCreateJob::create_mesh(const char *text,
|
|||||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||||
if (ctl.was_canceled()) return {};
|
if (ctl.was_canceled()) return {};
|
||||||
return TriangleMesh(Emboss::polygons2model(shapes, project));
|
return TriangleMesh(Emboss::polygons2model(shapes, project));
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh priv::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;
|
||||||
}
|
}
|
@ -15,46 +15,53 @@ class TriangleMesh;
|
|||||||
namespace Slic3r::GUI {
|
namespace Slic3r::GUI {
|
||||||
|
|
||||||
struct EmbossDataUpdate;
|
struct EmbossDataUpdate;
|
||||||
struct EmbossDataCreate;
|
struct EmbossDataCreateVolume;
|
||||||
|
struct EmbossDataCreateObject;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update text shape in existing text volume
|
||||||
|
/// </summary>
|
||||||
class EmbossUpdateJob : public Job
|
class EmbossUpdateJob : public Job
|
||||||
{
|
{
|
||||||
std::unique_ptr<EmbossDataUpdate> m_input;
|
std::unique_ptr<EmbossDataUpdate> m_input;
|
||||||
TriangleMesh m_result;
|
TriangleMesh m_result;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmbossUpdateJob(std::unique_ptr<EmbossDataUpdate> input) : m_input(std::move(input)) {}
|
EmbossUpdateJob(std::unique_ptr<EmbossDataUpdate> input);
|
||||||
void process(Ctl &ctl) override;
|
void process(Ctl &ctl) override;
|
||||||
void finalize(bool canceled, std::exception_ptr &) override;
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmbossCreateJob : public Job
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create new TextVolume on the surface of ModelObject
|
||||||
|
/// </summary>
|
||||||
|
class EmbossCreateVolumeJob : public Job
|
||||||
{
|
{
|
||||||
std::unique_ptr<EmbossDataCreate> m_input;
|
std::unique_ptr<EmbossDataCreateVolume> m_input;
|
||||||
TriangleMesh m_result;
|
TriangleMesh m_result;
|
||||||
Transform3d m_transformation;
|
Transform3d m_transformation;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmbossCreateJob(std::unique_ptr<EmbossDataCreate> input): m_input(std::move(input)){}
|
EmbossCreateVolumeJob(std::unique_ptr<EmbossDataCreateVolume> input);
|
||||||
void process(Ctl &ctl) override;
|
void process(Ctl &ctl) override;
|
||||||
void finalize(bool canceled, std::exception_ptr &) override;
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
|
|
||||||
// <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>
|
|
||||||
/// <param name="ctl">Control for job, check of cancelation</param>
|
|
||||||
/// <returns>Triangle mesh model</returns>
|
|
||||||
static TriangleMesh create_mesh(const char * text,
|
|
||||||
Emboss::FontFileWithCache &font,
|
|
||||||
const FontProp & font_prop,
|
|
||||||
Ctl & ctl);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static TriangleMesh create_default_mesh();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create new TextObject on the platter
|
||||||
|
/// </summary>
|
||||||
|
class EmbossCreateObjectJob : public Job
|
||||||
|
{
|
||||||
|
std::unique_ptr<EmbossDataCreateObject> m_input;
|
||||||
|
TriangleMesh m_result;
|
||||||
|
Transform3d m_transformation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EmbossCreateObjectJob(std::unique_ptr<EmbossDataCreateObject> input);
|
||||||
|
void process(Ctl &ctl) override;
|
||||||
|
void finalize(bool canceled, std::exception_ptr &) override;
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base data holder for embossing
|
/// Base data holder for embossing
|
||||||
@ -98,9 +105,10 @@ struct EmbossDataUpdate : public EmbossDataBase
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hold neccessary data to create embossed text object in job
|
/// Hold neccessary data to create ModelVolume in job
|
||||||
|
/// Volume is created on the surface of existing volume in object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct EmbossDataCreate: public EmbossDataBase
|
struct EmbossDataCreateVolume : public EmbossDataBase
|
||||||
{
|
{
|
||||||
// define embossed volume type
|
// define embossed volume type
|
||||||
ModelVolumeType volume_type;
|
ModelVolumeType volume_type;
|
||||||
@ -108,11 +116,47 @@ struct EmbossDataCreate: public EmbossDataBase
|
|||||||
// define position on screen where to create object
|
// define position on screen where to create object
|
||||||
Vec2d screen_coor;
|
Vec2d screen_coor;
|
||||||
|
|
||||||
// when exist ModelObject where to create volume
|
// parent ModelObject index where to create volume
|
||||||
std::optional<int> object_idx;
|
int object_idx;
|
||||||
|
|
||||||
// hitted instance transformation
|
// projection property
|
||||||
std::optional<Transform3d> hit_vol_tr;
|
Camera camera;
|
||||||
|
|
||||||
|
// used to find point on surface where to create new object
|
||||||
|
RaycastManager::SurfacePoint hit;
|
||||||
|
Transform3d hit_object_tr;
|
||||||
|
Transform3d hit_instance_tr;
|
||||||
|
|
||||||
|
EmbossDataCreateVolume(Emboss::FontFileWithCache font_file,
|
||||||
|
const TextConfiguration &text_configuration,
|
||||||
|
const std::string &volume_name,
|
||||||
|
ModelVolumeType volume_type,
|
||||||
|
Vec2d screen_coor,
|
||||||
|
int object_idx,
|
||||||
|
const Camera &camera,
|
||||||
|
const RaycastManager::SurfacePoint &hit,
|
||||||
|
const Transform3d &hit_object_tr,
|
||||||
|
const Transform3d &hit_instance_tr)
|
||||||
|
: EmbossDataBase(font_file, text_configuration, volume_name)
|
||||||
|
, volume_type(volume_type)
|
||||||
|
, screen_coor(screen_coor)
|
||||||
|
, object_idx(object_idx)
|
||||||
|
, camera(camera)
|
||||||
|
, hit(hit)
|
||||||
|
, hit_object_tr(hit_object_tr)
|
||||||
|
, hit_instance_tr(hit_instance_tr)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hold neccessary data to create ModelObject in job
|
||||||
|
/// Object is placed on bed under screen coor
|
||||||
|
/// OR to center of scene when it is out of bed shape
|
||||||
|
/// </summary>
|
||||||
|
struct EmbossDataCreateObject : public EmbossDataBase
|
||||||
|
{
|
||||||
|
// define position on screen where to create object
|
||||||
|
Vec2d screen_coor;
|
||||||
|
|
||||||
// projection property
|
// projection property
|
||||||
Camera camera;
|
Camera camera;
|
||||||
@ -120,29 +164,16 @@ struct EmbossDataCreate: public EmbossDataBase
|
|||||||
// shape of bed in case of create volume on bed
|
// shape of bed in case of create volume on bed
|
||||||
std::vector<Vec2d> bed_shape;
|
std::vector<Vec2d> bed_shape;
|
||||||
|
|
||||||
// used to find point on surface where to create new object
|
EmbossDataCreateObject(Emboss::FontFileWithCache font_file,
|
||||||
RaycastManager *raycast_manager;
|
const TextConfiguration &text_configuration,
|
||||||
// It is inside of GLGizmoEmboss object,
|
const std::string &volume_name,
|
||||||
// so I hope it will survive
|
Vec2d screen_coor,
|
||||||
|
const Camera &camera,
|
||||||
EmbossDataCreate(Emboss::FontFileWithCache font_file,
|
const std::vector<Vec2d> &bed_shape)
|
||||||
const TextConfiguration & text_configuration,
|
|
||||||
const std::string & volume_name,
|
|
||||||
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(font_file, text_configuration, volume_name)
|
: EmbossDataBase(font_file, text_configuration, volume_name)
|
||||||
, volume_type(volume_type)
|
|
||||||
, screen_coor(screen_coor)
|
, screen_coor(screen_coor)
|
||||||
, object_idx(object_idx)
|
|
||||||
, hit_vol_tr(hit_vol_tr)
|
|
||||||
, camera(camera)
|
, camera(camera)
|
||||||
, bed_shape(bed_shape)
|
, bed_shape(bed_shape)
|
||||||
, raycast_manager(raycast_manager)
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||||||
{
|
{
|
||||||
// check if volume was removed
|
// check if volume was removed
|
||||||
std::set<size_t> removed_casters;
|
std::set<size_t> removed_casters;
|
||||||
for (const auto &raycaster_item : raycasters)
|
for (const auto &raycaster_item : m_raycasters)
|
||||||
removed_casters.insert(raycaster_item.first);
|
removed_casters.insert(raycaster_item.first);
|
||||||
|
|
||||||
// check if inscance was removed
|
// check if inscance was removed
|
||||||
std::set<TrKey> removed_transformation;
|
std::set<TrKey> removed_transformation;
|
||||||
for (const auto &item : transformations)
|
for (const auto &item : m_transformations)
|
||||||
removed_transformation.insert(item.first);
|
removed_transformation.insert(item.first);
|
||||||
|
|
||||||
for (const ModelObject *object : objects) {
|
for (const ModelObject *object : objects) {
|
||||||
@ -28,8 +28,8 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||||||
removed_casters.erase(oid);
|
removed_casters.erase(oid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto item = raycasters.find(oid);
|
auto item = m_raycasters.find(oid);
|
||||||
if (item != raycasters.end()) {
|
if (item != m_raycasters.end()) {
|
||||||
removed_casters.erase(oid);
|
removed_casters.erase(oid);
|
||||||
// alredy in list only actualize
|
// alredy in list only actualize
|
||||||
// TODO: check triangles when change than actualize MeshRaycaster
|
// TODO: check triangles when change than actualize MeshRaycaster
|
||||||
@ -37,7 +37,7 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||||||
// add new raycaster
|
// add new raycaster
|
||||||
auto raycaster = std::make_unique<MeshRaycaster>(
|
auto raycaster = std::make_unique<MeshRaycaster>(
|
||||||
volume->mesh());
|
volume->mesh());
|
||||||
raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
m_raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,14 +52,14 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||||||
// transformation.translation()(2) += m_sla_shift_z;
|
// transformation.translation()(2) += m_sla_shift_z;
|
||||||
|
|
||||||
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
||||||
auto item = transformations.find(tr_key);
|
auto item = m_transformations.find(tr_key);
|
||||||
if (item != transformations.end()) {
|
if (item != m_transformations.end()) {
|
||||||
// actualize transformation all the time
|
// actualize transformation all the time
|
||||||
item->second = transformation;
|
item->second = transformation;
|
||||||
removed_transformation.erase(tr_key);
|
removed_transformation.erase(tr_key);
|
||||||
} else {
|
} else {
|
||||||
// add new transformation
|
// add new transformation
|
||||||
transformations.insert(
|
m_transformations.insert(
|
||||||
std::make_pair(tr_key, transformation));
|
std::make_pair(tr_key, transformation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,10 +67,10 @@ void RaycastManager::actualize(const ModelObjectPtrs &objects,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove non existing volumes
|
// remove non existing volumes
|
||||||
for (size_t volume_oid : removed_casters) raycasters.erase(volume_oid);
|
for (size_t volume_oid : removed_casters) m_raycasters.erase(volume_oid);
|
||||||
// remove non existing transformations
|
// remove non existing transformations
|
||||||
for (const TrKey& transformation_key : removed_transformation)
|
for (const TrKey& transformation_key : removed_transformation)
|
||||||
transformations.erase(transformation_key);
|
m_transformations.erase(transformation_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
||||||
@ -80,11 +80,11 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
|||||||
size_t oid = volume->id().id;
|
size_t oid = volume->id().id;
|
||||||
if (skip != nullptr && skip->skip(oid))
|
if (skip != nullptr && skip->skip(oid))
|
||||||
continue;
|
continue;
|
||||||
auto item = raycasters.find(oid);
|
auto item = m_raycasters.find(oid);
|
||||||
if (item == raycasters.end()) {
|
if (item == m_raycasters.end()) {
|
||||||
// add new raycaster
|
// add new raycaster
|
||||||
auto raycaster = std::make_unique<MeshRaycaster>(volume->mesh());
|
auto raycaster = std::make_unique<MeshRaycaster>(volume->mesh());
|
||||||
raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
m_raycasters.insert(std::make_pair(oid, std::move(raycaster)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,13 +98,14 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
|||||||
// TODO: add SLA shift Z
|
// TODO: add SLA shift Z
|
||||||
// transformation.translation()(2) += m_sla_shift_z;
|
// transformation.translation()(2) += m_sla_shift_z;
|
||||||
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
TrKey tr_key = std::make_pair(instance->id().id, volume->id().id);
|
||||||
auto item = transformations.find(tr_key);
|
auto item = m_transformations.find(tr_key);
|
||||||
if (item != transformations.end()) {
|
if (item != m_transformations.end()) {
|
||||||
// actualize transformation all the time
|
// actualize transformation all the time
|
||||||
item->second = transformation;
|
item->second = transformation;
|
||||||
} else {
|
} else {
|
||||||
// add new transformation
|
// add new transformation
|
||||||
transformations.insert(std::make_pair(tr_key, transformation));
|
m_transformations.insert(
|
||||||
|
std::make_pair(tr_key, transformation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,13 +125,13 @@ std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
std::optional<HitWithDistance> closest;
|
std::optional<HitWithDistance> closest;
|
||||||
for (const auto &item : transformations) {
|
for (const auto &item : m_transformations) {
|
||||||
const TrKey &key = item.first;
|
const TrKey &key = item.first;
|
||||||
size_t volume_id = key.second;
|
size_t volume_id = key.second;
|
||||||
if (skip != nullptr && skip->skip(volume_id)) continue;
|
if (skip != nullptr && skip->skip(volume_id)) continue;
|
||||||
const Transform3d &transformation = item.second;
|
const Transform3d &transformation = item.second;
|
||||||
auto raycaster_it = raycasters.find(volume_id);
|
auto raycaster_it = m_raycasters.find(volume_id);
|
||||||
if (raycaster_it == raycasters.end()) continue;
|
if (raycaster_it == m_raycasters.end()) continue;
|
||||||
const MeshRaycaster &raycaster = *(raycaster_it->second);
|
const MeshRaycaster &raycaster = *(raycaster_it->second);
|
||||||
SurfacePoint surface_point;
|
SurfacePoint surface_point;
|
||||||
bool success = raycaster.unproject_on_mesh(
|
bool success = raycaster.unproject_on_mesh(
|
||||||
@ -151,7 +152,7 @@ std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) const {
|
Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) const {
|
||||||
auto item = transformations.find(tr_key);
|
auto item = m_transformations.find(tr_key);
|
||||||
if (item == transformations.end()) return Transform3d::Identity();
|
if (item == m_transformations.end()) return Transform3d::Identity();
|
||||||
return item->second;
|
return item->second;
|
||||||
}
|
}
|
@ -11,19 +11,23 @@
|
|||||||
|
|
||||||
namespace Slic3r::GUI{
|
namespace Slic3r::GUI{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cast rays from camera to scene
|
||||||
|
/// Used for find hit point on model volume under mouse cursor
|
||||||
|
/// </summary>
|
||||||
class RaycastManager
|
class RaycastManager
|
||||||
{
|
{
|
||||||
// ModelVolume
|
// ModelVolume
|
||||||
std::map<size_t, std::unique_ptr<MeshRaycaster>> raycasters;
|
std::map<size_t, std::unique_ptr<MeshRaycaster>> m_raycasters;
|
||||||
|
|
||||||
// Key for transformation consist of unique volume and instance
|
// Key for transformation consist of unique volume and instance
|
||||||
// ModelInstance, ModelVolume
|
// ModelInstance, ModelVolume
|
||||||
using TrKey = std::pair<size_t, size_t>;
|
using TrKey = std::pair<size_t, size_t>;
|
||||||
std::map<TrKey, Transform3d> transformations;
|
std::map<TrKey, Transform3d> m_transformations;
|
||||||
|
|
||||||
// should contain shared pointer to camera but it is not shared pointer so it need it every time when casts rays
|
// should contain shared pointer to camera but it is not shared pointer so it need it every time when casts rays
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class ISkip{
|
class ISkip{
|
||||||
public:
|
public:
|
||||||
virtual ~ISkip() = default;
|
virtual ~ISkip() = default;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user