mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-11 03:01:48 +08:00
Refactor for easier use of emboss shape
This commit is contained in:
parent
c2f348ee19
commit
07181b4f37
@ -21,10 +21,10 @@ struct EmbossShape
|
|||||||
ExPolygons shapes;
|
ExPolygons shapes;
|
||||||
|
|
||||||
// scale of shape, multiplier to get 3d point in mm from integer shape
|
// scale of shape, multiplier to get 3d point in mm from integer shape
|
||||||
double scale;
|
double scale = 1.;
|
||||||
|
|
||||||
// Emboss depth, Size in local Z direction
|
// Emboss depth, Size in local Z direction
|
||||||
double depth; // [in loacal mm]
|
double depth = 1.; // [in loacal mm]
|
||||||
// NOTE: User should see and modify mainly world size not local
|
// NOTE: User should see and modify mainly world size not local
|
||||||
|
|
||||||
// Flag that result volume use surface cutted from source objects
|
// Flag that result volume use surface cutted from source objects
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
#include "slic3r/GUI/Jobs/NotificationProgressIndicator.hpp"
|
||||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||||
#include "slic3r/Utils/UndoRedo.hpp"
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
#include "slic3r/Utils/EmbossGui.hpp"
|
||||||
|
|
||||||
// TODO: remove include
|
// TODO: remove include
|
||||||
#include "libslic3r/SVG.hpp" // debug store
|
#include "libslic3r/SVG.hpp" // debug store
|
||||||
@ -107,67 +108,6 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
|
|||||||
|
|
||||||
// Private namespace with helper function for create volume
|
// Private namespace with helper function for create volume
|
||||||
namespace priv {
|
namespace priv {
|
||||||
/// <summary>
|
|
||||||
/// Data for emboss job to create shape
|
|
||||||
/// </summary>
|
|
||||||
struct TextDataBase : public DataBase
|
|
||||||
{
|
|
||||||
TextDataBase(DataBase &&parent, const FontFileWithCache& font_file, TextConfiguration &&text_configuration)
|
|
||||||
: DataBase(std::move(parent)), font_file(font_file) /* copy */, text_configuration(std::move(text_configuration))
|
|
||||||
{
|
|
||||||
assert(this->font_file.has_value());
|
|
||||||
|
|
||||||
// partialy fill shape from text configuration
|
|
||||||
const FontProp &fp = this->text_configuration.style.prop;
|
|
||||||
shape.depth = fp.emboss;
|
|
||||||
shape.use_surface = fp.use_surface;
|
|
||||||
shape.distance = fp.distance;
|
|
||||||
|
|
||||||
const FontFile &ff = *this->font_file.font_file;
|
|
||||||
shape.scale = get_text_shape_scale(fp, ff);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Create shape from text and font
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Text shape defined by configuration and font file</returns>
|
|
||||||
EmbossShape &create_shape() override {
|
|
||||||
if (!shape.shapes.empty())
|
|
||||||
return shape;
|
|
||||||
|
|
||||||
// create shape by configuration
|
|
||||||
const char *text = text_configuration.text.c_str();
|
|
||||||
const FontProp &fp = text_configuration.style.prop;
|
|
||||||
auto was_canceled = [&c = cancel]() -> bool { return c->load(); };
|
|
||||||
shape.shapes = text2shapes(font_file, text, fp, was_canceled);
|
|
||||||
|
|
||||||
// TEST
|
|
||||||
const FontProp &prop = text_configuration.style.prop;
|
|
||||||
const std::optional<unsigned int> &cn = prop.collection_number;
|
|
||||||
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
|
||||||
const FontFileWithCache &font = font_file;
|
|
||||||
assert(font_index < font.font_file->infos.size());
|
|
||||||
int unit_per_em = font.font_file->infos[font_index].unit_per_em;
|
|
||||||
float scale = prop.size_in_mm / unit_per_em;
|
|
||||||
float depth = prop.emboss / scale;
|
|
||||||
|
|
||||||
return shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(ModelVolume &volume) const override
|
|
||||||
{
|
|
||||||
volume.text_configuration = text_configuration; // copy
|
|
||||||
|
|
||||||
// discard information about rotation, should not be stored in volume
|
|
||||||
volume.text_configuration->style.prop.angle.reset();
|
|
||||||
|
|
||||||
DataBase::write(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep pointer on Data of font (glyph shapes)
|
|
||||||
FontFileWithCache font_file;
|
|
||||||
// font item is not used for create object
|
|
||||||
TextConfiguration text_configuration;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if volume type is possible use for new text volume
|
/// Check if volume type is possible use for new text volume
|
||||||
@ -187,16 +127,28 @@ static std::unique_ptr<DataBase> create_emboss_data_base(
|
|||||||
const std::string &text, StyleManager &style_manager, std::shared_ptr<std::atomic<bool>> &cancel);
|
const std::string &text, StyleManager &style_manager, std::shared_ptr<std::atomic<bool>> &cancel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start job for add new volume to object with given transformation
|
/// Data for emboss job to create shape
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="object">Define where to add</param>
|
struct TextDataBase : public DataBase
|
||||||
/// <param name="volume_trmat">Volume transformation</param>
|
{
|
||||||
/// <param name="emboss_data">Define text</param>
|
TextDataBase(DataBase &&parent, const FontFileWithCache &font_file, TextConfiguration &&text_configuration);
|
||||||
/// <param name="volume_type">Type of volume</param>
|
// Create shape from text + font configuration
|
||||||
static void start_create_volume_job(const ModelObject *object,
|
EmbossShape &create_shape() override;
|
||||||
const Transform3d volume_trmat,
|
void write(ModelVolume &volume) const override;
|
||||||
std::unique_ptr<DataBase> emboss_data,
|
|
||||||
ModelVolumeType volume_type);
|
// private:
|
||||||
|
// Keep pointer on Data of font (glyph shapes)
|
||||||
|
FontFileWithCache font_file;
|
||||||
|
// font item is not used for create object
|
||||||
|
TextConfiguration text_configuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start job for add object with text into scene
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="emboss_data">Define params of text</param>
|
||||||
|
/// <param name="coor">Screen coordinat, where to create new object laying on bed</param>
|
||||||
|
static void start_create_object_job(std::unique_ptr<DataBase> emboss_data, const Vec2d &coor);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start job for add new volume on surface of object defined by screen coor
|
/// Start job for add new volume on surface of object defined by screen coor
|
||||||
@ -208,35 +160,13 @@ static void start_create_volume_job(const ModelObject *object,
|
|||||||
/// <param name="raycaster">Ability to ray cast to model</param>
|
/// <param name="raycaster">Ability to ray cast to model</param>
|
||||||
/// <param name="canvas">Contain already used scene RayCasters</param>
|
/// <param name="canvas">Contain already used scene RayCasters</param>
|
||||||
/// <returns>True when start creation, False when there is no hit surface by screen coor</returns>
|
/// <returns>True when start creation, False when there is no hit surface by screen coor</returns>
|
||||||
static bool start_create_volume_on_surface_job(std::unique_ptr<DataBase> emboss_data,
|
static bool start_create_volume_on_surface_job(const FontProp &fp,
|
||||||
ModelVolumeType volume_type,
|
std::unique_ptr<DataBase> emboss_data,
|
||||||
const Vec2d &screen_coor,
|
ModelVolumeType volume_type,
|
||||||
const GLVolume *gl_volume,
|
const Vec2d &screen_coor,
|
||||||
RaycastManager &raycaster,
|
const GLVolume &gl_volume,
|
||||||
GLCanvas3D &canvas);
|
RaycastManager &raycaster,
|
||||||
|
GLCanvas3D &canvas);
|
||||||
/// <summary>
|
|
||||||
/// Find volume in selected object with closest convex hull to screen center.
|
|
||||||
/// Return
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selection">Define where to search for closest</param>
|
|
||||||
/// <param name="screen_center">Canvas center(dependent on camera settings)</param>
|
|
||||||
/// <param name="objects">Actual objects</param>
|
|
||||||
/// <param name="closest_center">OUT: coordinate of controid of closest volume</param>
|
|
||||||
/// <param name="closest_volume">OUT: closest volume</param>
|
|
||||||
static void find_closest_volume(const Selection &selection,
|
|
||||||
const Vec2d &screen_center,
|
|
||||||
const Camera &camera,
|
|
||||||
const ModelObjectPtrs &objects,
|
|
||||||
Vec2d *closest_center,
|
|
||||||
const GLVolume **closest_volume);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start job for add object with text into scene
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="emboss_data">Define params of text</param>
|
|
||||||
/// <param name="coor">Screen coordinat, where to create new object laying on bed</param>
|
|
||||||
static void start_create_object_job(std::unique_ptr<DataBase> emboss_data, const Vec2d &coor);
|
|
||||||
|
|
||||||
// Loaded icons enum
|
// Loaded icons enum
|
||||||
// Have to match order of files in function GLGizmoEmboss::init_icons()
|
// Have to match order of files in function GLGizmoEmboss::init_icons()
|
||||||
@ -270,19 +200,15 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
|
|||||||
m_style_manager.discard_style_changes();
|
m_style_manager.discard_style_changes();
|
||||||
set_default_text();
|
set_default_text();
|
||||||
|
|
||||||
GLVolume *gl_volume = get_first_hovered_gl_volume(m_parent);
|
|
||||||
std::unique_ptr<DataBase> emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
|
std::unique_ptr<DataBase> emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
|
||||||
if (gl_volume != nullptr) {
|
GLVolume *gl_volume = get_first_hovered_gl_volume(m_parent);
|
||||||
// Try to cast ray into scene and find object for add volume
|
if (gl_volume == nullptr)
|
||||||
if (!priv::start_create_volume_on_surface_job(std::move(emboss_data), volume_type, mouse_pos, gl_volume, m_raycast_manager, m_parent)) {
|
|
||||||
// When model is broken. It could appear that hit miss the object.
|
|
||||||
// So add part near by in simmilar manner as right panel do
|
|
||||||
create_volume(volume_type);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// object is not under mouse position soo create object on plater
|
// object is not under mouse position soo create object on plater
|
||||||
priv::start_create_object_job(std::move(emboss_data), mouse_pos);
|
return priv::start_create_object_job(std::move(emboss_data), mouse_pos);
|
||||||
}
|
|
||||||
|
const FontProp &fp = m_style_manager.get_style().prop;
|
||||||
|
if (!priv::start_create_volume_on_surface_job(fp, std::move(emboss_data), volume_type, mouse_pos, *gl_volume, m_raycast_manager, m_parent))
|
||||||
|
return create_volume(volume_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Designed for create volume without information of mouse in scene
|
// Designed for create volume without information of mouse in scene
|
||||||
@ -310,34 +236,26 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
|
|||||||
|
|
||||||
// create volume inside of selected object
|
// create volume inside of selected object
|
||||||
Vec2d coor;
|
Vec2d coor;
|
||||||
const GLVolume *vol = nullptr;
|
|
||||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||||
priv::find_closest_volume(selection, screen_center, camera, objects, &coor, &vol);
|
const GLVolume *gl_volume = find_closest(selection, screen_center, camera, objects, &coor);
|
||||||
if (vol == nullptr) {
|
|
||||||
priv::start_create_object_job(std::move(emboss_data), screen_center);
|
FontProp &fp = m_style_manager.get_style().prop;
|
||||||
} else if (!priv::start_create_volume_on_surface_job(std::move(emboss_data), volume_type, coor, vol, m_raycast_manager, m_parent)) {
|
if (gl_volume == nullptr) {
|
||||||
// in centroid of convex hull is not hit with object
|
return priv::start_create_object_job(std::move(emboss_data), screen_center);
|
||||||
|
} else if (!priv::start_create_volume_on_surface_job(fp, std::move(emboss_data), volume_type, coor, *gl_volume, m_raycast_manager, m_parent)){
|
||||||
|
// In centroid of convex hull is not hit with object. e.g. torid
|
||||||
// soo create transfomation on border of object
|
// soo create transfomation on border of object
|
||||||
|
|
||||||
// unique pointer is already destoyed need to create again
|
// unique pointer is already destoyed need to create again
|
||||||
std::unique_ptr<DataBase> emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
|
std::unique_ptr<DataBase> emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
|
||||||
// TODO: do it better way
|
|
||||||
FontProp &fp = static_cast<TextDataBase *>(emboss_data.get())->text_configuration.style.prop;
|
|
||||||
// there is no point on surface so no use of surface will be applied
|
// there is no point on surface so no use of surface will be applied
|
||||||
if (fp.use_surface)
|
if (emboss_data->shape.use_surface)
|
||||||
fp.use_surface = false;
|
emboss_data->shape.use_surface = false;
|
||||||
|
|
||||||
// Transformation is inspired add generic volumes in ObjectList::load_generic_subobject
|
const ModelObject *object = get_model_object(*gl_volume, objects);
|
||||||
const ModelObject *obj = objects[vol->object_idx()];
|
Worker &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||||
BoundingBoxf3 instance_bb = obj->instance_bounding_box(vol->instance_idx());
|
Transform3d volume_trmat = create_volume_transformation(*gl_volume, objects, fp.size_in_mm, fp.emboss);
|
||||||
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
|
start_create_volume_job(worker, *object, volume_trmat, std::move(emboss_data), volume_type);
|
||||||
Transform3d tr = vol->get_instance_transformation().get_matrix_no_offset().inverse();
|
|
||||||
Vec3d offset_tr(0, // center of instance - Can't suggest width of text before it will be created
|
|
||||||
- instance_bb.size().y() / 2 - fp.size_in_mm / 2, // under
|
|
||||||
fp.emboss / 2 - instance_bb.size().z() / 2 // lay on bed
|
|
||||||
);
|
|
||||||
Transform3d volume_trmat = tr * Eigen::Translation3d(offset_tr);
|
|
||||||
priv::start_create_volume_job(obj, volume_trmat, std::move(emboss_data), volume_type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3347,6 +3265,59 @@ bool priv::is_valid(ModelVolumeType volume_type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv::TextDataBase::TextDataBase(DataBase &&parent, const FontFileWithCache &font_file, TextConfiguration &&text_configuration)
|
||||||
|
: DataBase(std::move(parent)), font_file(font_file) /* copy */, text_configuration(std::move(text_configuration))
|
||||||
|
{
|
||||||
|
assert(this->font_file.has_value());
|
||||||
|
|
||||||
|
// partialy fill shape from text configuration
|
||||||
|
const FontProp &fp = this->text_configuration.style.prop;
|
||||||
|
shape.depth = fp.emboss;
|
||||||
|
shape.use_surface = fp.use_surface;
|
||||||
|
shape.distance = fp.distance;
|
||||||
|
|
||||||
|
const FontFile &ff = *this->font_file.font_file;
|
||||||
|
shape.scale = get_text_shape_scale(fp, ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbossShape &priv::TextDataBase::create_shape()
|
||||||
|
{
|
||||||
|
if (!shape.shapes.empty())
|
||||||
|
return shape;
|
||||||
|
|
||||||
|
// create shape by configuration
|
||||||
|
const char *text = text_configuration.text.c_str();
|
||||||
|
const FontProp &fp = text_configuration.style.prop;
|
||||||
|
auto was_canceled = [&c = cancel]() -> bool { return c->load(); };
|
||||||
|
shape.shapes = text2shapes(font_file, text, fp, was_canceled);
|
||||||
|
|
||||||
|
// TEST
|
||||||
|
const FontProp &prop = text_configuration.style.prop;
|
||||||
|
const std::optional<unsigned int> &cn = prop.collection_number;
|
||||||
|
unsigned int font_index = (cn.has_value()) ? *cn : 0;
|
||||||
|
const FontFileWithCache &font = font_file;
|
||||||
|
assert(font_index < font.font_file->infos.size());
|
||||||
|
int unit_per_em = font.font_file->infos[font_index].unit_per_em;
|
||||||
|
float scale = prop.size_in_mm / unit_per_em;
|
||||||
|
float depth = prop.emboss / scale;
|
||||||
|
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
void priv::TextDataBase::write(ModelVolume &volume) const
|
||||||
|
{
|
||||||
|
volume.text_configuration = text_configuration; // copy
|
||||||
|
|
||||||
|
// discard information about rotation, should not be stored in volume
|
||||||
|
volume.text_configuration->style.prop.angle.reset();
|
||||||
|
|
||||||
|
// only temporary solution
|
||||||
|
volume.text_configuration->style.prop.use_surface = shape.use_surface;
|
||||||
|
volume.text_configuration->style.prop.distance = shape.distance;
|
||||||
|
|
||||||
|
DataBase::write(volume);
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<DataBase> priv::create_emboss_data_base(const std::string &text, StyleManager &style_manager, std::shared_ptr<std::atomic<bool>>& cancel)
|
std::unique_ptr<DataBase> priv::create_emboss_data_base(const std::string &text, StyleManager &style_manager, std::shared_ptr<std::atomic<bool>>& cancel)
|
||||||
{
|
{
|
||||||
// create volume_name
|
// create volume_name
|
||||||
@ -3380,143 +3351,48 @@ std::unique_ptr<DataBase> priv::create_emboss_data_base(const std::string &text,
|
|||||||
return std::make_unique<TextDataBase>(std::move(base), font, std::move(tc));
|
return std::make_unique<TextDataBase>(std::move(base), font, std::move(tc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void priv::start_create_object_job(std::unique_ptr<DataBase> emboss_data, const Vec2d &coor)
|
void priv::start_create_object_job(std::unique_ptr<DataBase> emboss_data, const Vec2d &coor) {
|
||||||
{
|
|
||||||
// start creation of new object
|
|
||||||
Plater *plater = wxGetApp().plater();
|
Plater *plater = wxGetApp().plater();
|
||||||
const Camera &camera = plater->get_camera();
|
const Camera &camera = plater->get_camera();
|
||||||
const Pointfs &bed_shape = plater->build_volume().bed_shape();
|
const Pointfs &bed_shape = plater->build_volume().bed_shape();
|
||||||
|
Worker &worker = plater->get_ui_job_worker();
|
||||||
// can't create new object with distance from surface
|
|
||||||
// TODO: do it better way
|
|
||||||
FontProp &fp = static_cast<TextDataBase *>(emboss_data.get())->text_configuration.style.prop;
|
|
||||||
if (fp.distance.has_value()) fp.distance.reset();
|
|
||||||
|
|
||||||
// can't create new object with using surface
|
|
||||||
if (fp.use_surface)
|
|
||||||
fp.use_surface = false;
|
|
||||||
|
|
||||||
// Transform3d volume_tr = priv::create_transformation_on_bed(mouse_pos, camera, bed_shape, prop.emboss / 2);
|
|
||||||
DataCreateObject data{std::move(emboss_data), coor, camera, bed_shape};
|
DataCreateObject data{std::move(emboss_data), coor, camera, bed_shape};
|
||||||
auto job = std::make_unique<CreateObjectJob>(std::move(data));
|
auto job = std::make_unique<CreateObjectJob>(std::move(data));
|
||||||
Worker &worker = plater->get_ui_job_worker();
|
|
||||||
queue_job(worker, std::move(job));
|
queue_job(worker, std::move(job));
|
||||||
}
|
}
|
||||||
|
|
||||||
void priv::start_create_volume_job(const ModelObject *object,
|
bool priv::start_create_volume_on_surface_job(const FontProp &fp,
|
||||||
const Transform3d volume_trmat,
|
std::unique_ptr<DataBase> emboss_data,
|
||||||
std::unique_ptr<DataBase> emboss_data,
|
ModelVolumeType volume_type,
|
||||||
ModelVolumeType volume_type)
|
const Vec2d &screen_coor,
|
||||||
|
const GLVolume &gl_volume,
|
||||||
|
RaycastManager &raycaster,
|
||||||
|
GLCanvas3D &canvas)
|
||||||
{
|
{
|
||||||
// TODO: do it better way
|
const ModelObjectPtrs &objects = canvas.get_model()->objects;
|
||||||
FontProp &fp = static_cast<TextDataBase *>(emboss_data.get())->text_configuration.style.prop;
|
const ModelVolume* volume = get_model_volume(gl_volume, objects);
|
||||||
bool &use_surface = fp.use_surface;
|
const ModelInstance *instance = get_model_instance(gl_volume, objects);
|
||||||
|
if (volume == nullptr || instance == nullptr ||
|
||||||
std::unique_ptr<GUI::Job> job;
|
volume->get_object() == nullptr) {
|
||||||
if (use_surface) {
|
// weird situation
|
||||||
// Model to cut surface from.
|
assert(false);
|
||||||
SurfaceVolumeData::ModelSources sources = create_sources(object->volumes);
|
|
||||||
if (sources.empty()) {
|
|
||||||
use_surface = false;
|
|
||||||
} else {
|
|
||||||
bool is_outside = volume_type == ModelVolumeType::MODEL_PART;
|
|
||||||
// check that there is not unexpected volume type
|
|
||||||
assert(is_outside || volume_type == ModelVolumeType::NEGATIVE_VOLUME || volume_type == ModelVolumeType::PARAMETER_MODIFIER);
|
|
||||||
SurfaceVolumeData sfvd{volume_trmat, is_outside, std::move(sources)};
|
|
||||||
CreateSurfaceVolumeData surface_data{std::move(sfvd), std::move(emboss_data), volume_type, object->id()};
|
|
||||||
job = std::make_unique<CreateSurfaceVolumeJob>(std::move(surface_data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!use_surface) {
|
|
||||||
// create volume
|
|
||||||
DataCreateVolume data{std::move(emboss_data), volume_type, object->id(), volume_trmat};
|
|
||||||
job = std::make_unique<CreateVolumeJob>(std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
Plater *plater = wxGetApp().plater();
|
|
||||||
Worker &worker = plater->get_ui_job_worker();
|
|
||||||
queue_job(worker, std::move(job));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool priv::start_create_volume_on_surface_job(std::unique_ptr<DataBase> emboss_data,
|
|
||||||
ModelVolumeType volume_type,
|
|
||||||
const Vec2d &screen_coor,
|
|
||||||
const GLVolume *gl_volume,
|
|
||||||
RaycastManager &raycaster,
|
|
||||||
GLCanvas3D &canvas)
|
|
||||||
{
|
|
||||||
assert(gl_volume != nullptr);
|
|
||||||
if (gl_volume == nullptr) return false;
|
|
||||||
|
|
||||||
Plater *plater = wxGetApp().plater();
|
|
||||||
const ModelObjectPtrs &objects = plater->model().objects;
|
|
||||||
|
|
||||||
int object_idx = gl_volume->object_idx();
|
|
||||||
if (object_idx < 0 || static_cast<size_t>(object_idx) >= objects.size()) return false;
|
|
||||||
ModelObject *obj = objects[object_idx];
|
|
||||||
size_t vol_id = obj->volumes[gl_volume->volume_idx()]->id().id;
|
|
||||||
auto cond = RaycastManager::AllowVolumes({vol_id});
|
|
||||||
|
|
||||||
RaycastManager::Meshes meshes = create_meshes(canvas, cond);
|
|
||||||
raycaster.actualize(*obj, &cond, &meshes);
|
|
||||||
|
|
||||||
const Camera &camera = plater->get_camera();
|
|
||||||
std::optional<RaycastManager::Hit> hit = ray_from_camera(raycaster, screen_coor, camera, &cond);
|
|
||||||
|
|
||||||
// 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 options to add text by object list
|
|
||||||
if (!hit.has_value())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// priv::reset_skew(hit_to_world);
|
|
||||||
Transform3d instance = gl_volume->get_instance_transformation().get_matrix();
|
|
||||||
|
|
||||||
// Create result volume transformation
|
|
||||||
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, Slic3r::GUI::up_limit);
|
|
||||||
|
|
||||||
// TODO: find better way !!!
|
|
||||||
const FontProp &fp = static_cast<TextDataBase *>(emboss_data.get())->text_configuration.style.prop;
|
|
||||||
|
|
||||||
apply_transformation(fp, surface_trmat);
|
|
||||||
// new transformation in world coor is surface_trmat
|
|
||||||
Transform3d volume_trmat = instance.inverse() * surface_trmat;
|
|
||||||
start_create_volume_job(obj, volume_trmat, std::move(emboss_data), volume_type);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void priv::find_closest_volume(const Selection &selection,
|
|
||||||
const Vec2d &screen_center,
|
|
||||||
const Camera &camera,
|
|
||||||
const ModelObjectPtrs &objects,
|
|
||||||
Vec2d *closest_center,
|
|
||||||
const GLVolume **closest_volume)
|
|
||||||
{
|
|
||||||
assert(closest_center != nullptr);
|
|
||||||
assert(closest_volume != nullptr);
|
|
||||||
assert(*closest_volume == nullptr);
|
|
||||||
const Selection::IndicesList &indices = selection.get_volume_idxs();
|
|
||||||
assert(!indices.empty()); // no selected volume
|
|
||||||
if (indices.empty()) return;
|
|
||||||
|
|
||||||
double center_sq_distance = std::numeric_limits<double>::max();
|
|
||||||
for (unsigned int id : indices) {
|
|
||||||
const GLVolume *gl_volume = selection.get_volume(id);
|
|
||||||
const ModelVolume *volume = get_model_volume(*gl_volume, objects);
|
|
||||||
if (!volume->is_model_part()) continue;
|
|
||||||
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *gl_volume);
|
|
||||||
Vec2d c = hull.centroid().cast<double>();
|
|
||||||
Vec2d d = c - screen_center;
|
|
||||||
bool is_bigger_x = std::fabs(d.x()) > std::fabs(d.y());
|
|
||||||
if ((is_bigger_x && d.x() * d.x() > center_sq_distance) ||
|
|
||||||
(!is_bigger_x && d.y() * d.y() > center_sq_distance)) continue;
|
|
||||||
|
|
||||||
double distance = d.squaredNorm();
|
|
||||||
if (center_sq_distance < distance) continue;
|
|
||||||
center_sq_distance = distance;
|
|
||||||
*closest_center = c;
|
|
||||||
*closest_volume = gl_volume;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Plater* plater = wxGetApp().plater();
|
||||||
|
const Camera &camera = plater->get_camera();
|
||||||
|
std::optional<Transform3d> transform = create_volume_transformation_on_surface(
|
||||||
|
screen_coor, camera, *volume, *instance, raycaster, canvas, fp.distance, fp.angle);
|
||||||
|
|
||||||
|
if (!transform.has_value()) {
|
||||||
|
// When model is broken. It could appear that hit miss the object.
|
||||||
|
// So add part near by in simmilar manner as right panel do
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to cast ray into scene and find object for add volume
|
||||||
|
Worker &worker = plater->get_ui_job_worker();
|
||||||
|
return start_create_volume_job(worker, *volume->get_object(), *transform, std::move(emboss_data), volume_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImVec2 priv::calc_fine_position(const Selection &selection, const ImVec2 &windows_size, const Size &canvas_size)
|
ImVec2 priv::calc_fine_position(const Selection &selection, const ImVec2 &windows_size, const Size &canvas_size)
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "libslic3r/Emboss.hpp"
|
#include "libslic3r/Emboss.hpp"
|
||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
|
||||||
#include "libslic3r/TextConfiguration.hpp"
|
#include "libslic3r/TextConfiguration.hpp"
|
||||||
|
|
||||||
#include <imgui/imgui.h>
|
#include <imgui/imgui.h>
|
||||||
|
@ -14,9 +14,13 @@
|
|||||||
#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/Gizmos/GLGizmoEmboss.hpp"
|
#include "slic3r/GUI/Gizmos/GLGizmoEmboss.hpp"
|
||||||
|
#include "slic3r/GUI/Selection.hpp"
|
||||||
#include "slic3r/GUI/CameraUtils.hpp"
|
#include "slic3r/GUI/CameraUtils.hpp"
|
||||||
#include "slic3r/GUI/format.hpp"
|
#include "slic3r/GUI/format.hpp"
|
||||||
|
#include "slic3r/GUI/3DScene.hpp"
|
||||||
|
#include "slic3r/GUI/Jobs/Worker.hpp"
|
||||||
#include "slic3r/Utils/UndoRedo.hpp"
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::Emboss;
|
using namespace Slic3r::Emboss;
|
||||||
@ -168,6 +172,13 @@ void CreateObjectJob::process(Ctl &ctl)
|
|||||||
if (!priv::check(m_input))
|
if (!priv::check(m_input))
|
||||||
throw std::runtime_error("Bad input data for EmbossCreateObjectJob.");
|
throw std::runtime_error("Bad input data for EmbossCreateObjectJob.");
|
||||||
|
|
||||||
|
if (m_input.base->shape.distance.has_value())
|
||||||
|
m_input.base->shape.distance.reset();
|
||||||
|
|
||||||
|
// can't create new object with using surface
|
||||||
|
if (m_input.base->shape.use_surface)
|
||||||
|
m_input.base->shape.use_surface = false;
|
||||||
|
|
||||||
auto was_canceled = priv::was_canceled(ctl, *m_input.base);
|
auto was_canceled = priv::was_canceled(ctl, *m_input.base);
|
||||||
m_result = priv::create_mesh(*m_input.base, was_canceled, ctl);
|
m_result = priv::create_mesh(*m_input.base, was_canceled, ctl);
|
||||||
if (was_canceled()) return;
|
if (was_canceled()) return;
|
||||||
@ -277,36 +288,6 @@ void UpdateJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
priv::update_volume(std::move(m_result), m_input);
|
priv::update_volume(std::move(m_result), m_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r::GUI::Emboss {
|
|
||||||
|
|
||||||
SurfaceVolumeData::ModelSources create_sources(const ModelVolumePtrs &volumes, std::optional<size_t> text_volume_id)
|
|
||||||
{
|
|
||||||
SurfaceVolumeData::ModelSources result;
|
|
||||||
result.reserve(volumes.size() - 1);
|
|
||||||
for (const ModelVolume *v : volumes) {
|
|
||||||
if (text_volume_id.has_value() && v->id().id == *text_volume_id) continue;
|
|
||||||
// skip modifiers and negative volumes, ...
|
|
||||||
if (!v->is_model_part()) continue;
|
|
||||||
const TriangleMesh &tm = v->mesh();
|
|
||||||
if (tm.empty()) continue;
|
|
||||||
if (tm.its.empty()) continue;
|
|
||||||
result.push_back({v->get_mesh_shared_ptr(), v->get_matrix()});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume *text_volume)
|
|
||||||
{
|
|
||||||
if (text_volume == nullptr) return {};
|
|
||||||
if (!text_volume->text_configuration.has_value()) return {};
|
|
||||||
const ModelVolumePtrs &volumes = text_volume->get_object()->volumes;
|
|
||||||
// no other volume in object
|
|
||||||
if (volumes.size() <= 1) return {};
|
|
||||||
return create_sources(volumes, text_volume->id().id);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r::GUI::Emboss
|
|
||||||
|
|
||||||
/////////////////
|
/////////////////
|
||||||
/// Create Surface volume
|
/// Create Surface volume
|
||||||
CreateSurfaceVolumeJob::CreateSurfaceVolumeJob(CreateSurfaceVolumeData &&input)
|
CreateSurfaceVolumeJob::CreateSurfaceVolumeJob(CreateSurfaceVolumeData &&input)
|
||||||
@ -354,6 +335,147 @@ void UpdateSurfaceVolumeJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
priv::update_volume(std::move(m_result), m_input, tr);
|
priv::update_volume(std::move(m_result), m_input, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Slic3r::GUI::Emboss {
|
||||||
|
|
||||||
|
SurfaceVolumeData::ModelSources create_sources(const ModelVolumePtrs &volumes, std::optional<size_t> text_volume_id)
|
||||||
|
{
|
||||||
|
SurfaceVolumeData::ModelSources result;
|
||||||
|
result.reserve(volumes.size() - 1);
|
||||||
|
for (const ModelVolume *v : volumes) {
|
||||||
|
if (text_volume_id.has_value() && v->id().id == *text_volume_id)
|
||||||
|
continue;
|
||||||
|
// skip modifiers and negative volumes, ...
|
||||||
|
if (!v->is_model_part())
|
||||||
|
continue;
|
||||||
|
const TriangleMesh &tm = v->mesh();
|
||||||
|
if (tm.empty())
|
||||||
|
continue;
|
||||||
|
if (tm.its.empty())
|
||||||
|
continue;
|
||||||
|
result.push_back({v->get_mesh_shared_ptr(), v->get_matrix()});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume *text_volume)
|
||||||
|
{
|
||||||
|
if (text_volume == nullptr)
|
||||||
|
return {};
|
||||||
|
if (!text_volume->text_configuration.has_value())
|
||||||
|
return {};
|
||||||
|
const ModelVolumePtrs &volumes = text_volume->get_object()->volumes;
|
||||||
|
// no other volume in object
|
||||||
|
if (volumes.size() <= 1)
|
||||||
|
return {};
|
||||||
|
return create_sources(volumes, text_volume->id().id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_create_volume_job(
|
||||||
|
Worker &worker, const ModelObject &object, const Transform3d volume_tr, DataBasePtr data, ModelVolumeType volume_type)
|
||||||
|
{
|
||||||
|
bool &use_surface = data->shape.use_surface;
|
||||||
|
std::unique_ptr<GUI::Job> job;
|
||||||
|
if (use_surface) {
|
||||||
|
// Model to cut surface from.
|
||||||
|
SurfaceVolumeData::ModelSources sources = create_sources(object.volumes);
|
||||||
|
if (sources.empty()) {
|
||||||
|
use_surface = false;
|
||||||
|
} else {
|
||||||
|
bool is_outside = volume_type == ModelVolumeType::MODEL_PART;
|
||||||
|
// check that there is not unexpected volume type
|
||||||
|
assert(is_outside || volume_type == ModelVolumeType::NEGATIVE_VOLUME || volume_type == ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
|
SurfaceVolumeData sfvd{volume_tr, is_outside, std::move(sources)};
|
||||||
|
CreateSurfaceVolumeData surface_data{std::move(sfvd), std::move(data), volume_type, object.id()};
|
||||||
|
job = std::make_unique<CreateSurfaceVolumeJob>(std::move(surface_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!use_surface) {
|
||||||
|
// create volume
|
||||||
|
DataCreateVolume create_volume_data{std::move(data), volume_type, object.id(), volume_tr};
|
||||||
|
job = std::make_unique<CreateVolumeJob>(std::move(create_volume_data));
|
||||||
|
}
|
||||||
|
return queue_job(worker, std::move(job));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Transform3d> create_volume_transformation_on_surface(const Vec2d &screen_coor,
|
||||||
|
const Camera &camera,
|
||||||
|
const ModelVolume &volume,
|
||||||
|
const ModelInstance &instance,
|
||||||
|
RaycastManager &raycaster,
|
||||||
|
GLCanvas3D &canvas,
|
||||||
|
const std::optional<float> &distance,
|
||||||
|
const std::optional<float> &angle)
|
||||||
|
{
|
||||||
|
auto cond = RaycastManager::AllowVolumes({volume.id().id});
|
||||||
|
RaycastManager::Meshes meshes = create_meshes(canvas, cond);
|
||||||
|
raycaster.actualize(instance, &cond, &meshes);
|
||||||
|
|
||||||
|
std::optional<RaycastManager::Hit> hit = ray_from_camera(raycaster, screen_coor, camera, &cond);
|
||||||
|
|
||||||
|
// 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 options to add text by object list
|
||||||
|
if (!hit.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Create result volume transformation
|
||||||
|
Transform3d surface_trmat = create_transformation_onto_surface(hit->position, hit->normal, Slic3r::GUI::up_limit);
|
||||||
|
|
||||||
|
apply_transformation(angle, distance, surface_trmat);
|
||||||
|
|
||||||
|
return instance.get_matrix().inverse() * surface_trmat;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform3d create_volume_transformation(const GLVolume &gl_volume, const ModelObjectPtrs &objects, float volume_height, float volume_depth)
|
||||||
|
{
|
||||||
|
// Transformation is inspired add generic volumes in ObjectList::load_generic_subobject
|
||||||
|
const ModelObject *obj = objects[gl_volume.object_idx()];
|
||||||
|
BoundingBoxf3 instance_bb = obj->instance_bounding_box(gl_volume.instance_idx());
|
||||||
|
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
|
||||||
|
Transform3d tr = gl_volume.get_instance_transformation().get_matrix_no_offset().inverse();
|
||||||
|
Vec3d offset_tr(0, // center of instance - Can't suggest width of text before it will be created
|
||||||
|
- instance_bb.size().y() / 2 - volume_height / 2, // under
|
||||||
|
volume_depth / 2 - instance_bb.size().z() / 2 // lay on bed
|
||||||
|
);
|
||||||
|
return tr * Eigen::Translation3d(offset_tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLVolume *find_closest(
|
||||||
|
const Selection &selection, const Vec2d &screen_center, const Camera &camera, const ModelObjectPtrs &objects, Vec2d *closest_center)
|
||||||
|
{
|
||||||
|
assert(closest_center != nullptr);
|
||||||
|
const GLVolume * closest = nullptr;
|
||||||
|
const Selection::IndicesList &indices = selection.get_volume_idxs();
|
||||||
|
assert(!indices.empty()); // no selected volume
|
||||||
|
if (indices.empty())
|
||||||
|
return closest;
|
||||||
|
|
||||||
|
double center_sq_distance = std::numeric_limits<double>::max();
|
||||||
|
for (unsigned int id : indices) {
|
||||||
|
const GLVolume *gl_volume = selection.get_volume(id);
|
||||||
|
const ModelVolume *volume = get_model_volume(*gl_volume, objects);
|
||||||
|
if (!volume->is_model_part())
|
||||||
|
continue;
|
||||||
|
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *gl_volume);
|
||||||
|
Vec2d c = hull.centroid().cast<double>();
|
||||||
|
Vec2d d = c - screen_center;
|
||||||
|
bool is_bigger_x = std::fabs(d.x()) > std::fabs(d.y());
|
||||||
|
if ((is_bigger_x && d.x() * d.x() > center_sq_distance) || (!is_bigger_x && d.y() * d.y() > center_sq_distance))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
double distance = d.squaredNorm();
|
||||||
|
if (center_sq_distance < distance)
|
||||||
|
continue;
|
||||||
|
center_sq_distance = distance;
|
||||||
|
|
||||||
|
*closest_center = c;
|
||||||
|
closest = gl_volume;
|
||||||
|
}
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r::GUI::Emboss
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
/// private namespace implementation
|
/// private namespace implementation
|
||||||
bool priv::check(const DataBase &input, bool check_fontfile, bool use_surface)
|
bool priv::check(const DataBase &input, bool check_fontfile, bool use_surface)
|
||||||
|
@ -6,14 +6,28 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "libslic3r/Emboss.hpp"
|
#include "libslic3r/Emboss.hpp"
|
||||||
#include "libslic3r/EmbossShape.hpp"
|
#include "libslic3r/EmbossShape.hpp"
|
||||||
|
#include "libslic3r/Point.hpp" // Transform3d
|
||||||
|
|
||||||
#include "slic3r/Utils/RaycastManager.hpp"
|
#include "slic3r/Utils/RaycastManager.hpp"
|
||||||
|
|
||||||
|
#include "slic3r/GUI/Jobs/EmbossJob.hpp" // Emboss::DataBase
|
||||||
#include "slic3r/GUI/Camera.hpp"
|
#include "slic3r/GUI/Camera.hpp"
|
||||||
|
|
||||||
#include "Job.hpp"
|
#include "Job.hpp"
|
||||||
|
|
||||||
|
// forward declarations
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
class GLVolume;
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
|
class ModelObject;
|
||||||
class TriangleMesh;
|
class TriangleMesh;
|
||||||
}
|
typedef std::vector<ModelObject *> ModelObjectPtrs;
|
||||||
|
typedef std::vector<ModelVolume *> ModelVolumePtrs;
|
||||||
|
namespace GUI {
|
||||||
|
class Selection;
|
||||||
|
class RaycastManager;
|
||||||
|
class Worker;
|
||||||
|
}}
|
||||||
|
|
||||||
namespace Slic3r::GUI::Emboss {
|
namespace Slic3r::GUI::Emboss {
|
||||||
|
|
||||||
@ -232,6 +246,21 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
struct UpdateSurfaceVolumeData : public DataUpdate, public SurfaceVolumeData{};
|
struct UpdateSurfaceVolumeData : public DataUpdate, public SurfaceVolumeData{};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update text volume to use surface from object
|
||||||
|
/// </summary>
|
||||||
|
class UpdateSurfaceVolumeJob : public Job
|
||||||
|
{
|
||||||
|
UpdateSurfaceVolumeData m_input;
|
||||||
|
TriangleMesh m_result;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// move params to private variable
|
||||||
|
UpdateSurfaceVolumeJob(UpdateSurfaceVolumeData &&input);
|
||||||
|
void process(Ctl &ctl) override;
|
||||||
|
void finalize(bool canceled, std::exception_ptr &eptr) override;
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copied triangles from object to be able create mesh for cut surface from
|
/// Copied triangles from object to be able create mesh for cut surface from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -247,21 +276,59 @@ SurfaceVolumeData::ModelSources create_sources(const ModelVolumePtrs &volumes, s
|
|||||||
/// <returns>Source data for cut surface from</returns>
|
/// <returns>Source data for cut surface from</returns>
|
||||||
SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume *text_volume);
|
SurfaceVolumeData::ModelSources create_volume_sources(const ModelVolume *text_volume);
|
||||||
|
|
||||||
|
using DataBasePtr = std::unique_ptr<DataBase>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update text volume to use surface from object
|
/// Start job for add new volume to object with given transformation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class UpdateSurfaceVolumeJob : public Job
|
/// <param name="worker">Define where to queue the job. e.g. wxGetApp().plater()->get_ui_job_worker()</param>
|
||||||
{
|
/// <param name="object">Define where to add</param>
|
||||||
UpdateSurfaceVolumeData m_input;
|
/// <param name="volume_tr">Wanted volume transformation</param>
|
||||||
TriangleMesh m_result;
|
/// <param name="data">Define what to emboss - shape</param>
|
||||||
|
/// <param name="volume_type">Type of volume: Part, negative, modifier</param>
|
||||||
|
/// <return>True on success otherwise false</return>
|
||||||
|
bool start_create_volume_job(Worker &worker, const ModelObject &object, const Transform3d volume_tr, DataBasePtr data, ModelVolumeType volume_type);
|
||||||
|
|
||||||
public:
|
/// <summary>
|
||||||
// move params to private variable
|
/// Start job for add new volume on surface of object defined by screen coor
|
||||||
UpdateSurfaceVolumeJob(UpdateSurfaceVolumeData &&input);
|
/// </summary>
|
||||||
void process(Ctl &ctl) override;
|
/// <param name="screen_coor">Mouse position which define position</param>
|
||||||
void finalize(bool canceled, std::exception_ptr &eptr) override;
|
/// <param name="volume">Volume to find surface for create</param>
|
||||||
};
|
/// <param name="instance">Instance to find surface for create</param>
|
||||||
|
/// <param name="raycaster">Ability to ray cast to model</param>
|
||||||
|
/// <param name="canvas">Contain already used scene RayCasters</param>
|
||||||
|
/// <param name="angle">Initial z move</param>
|
||||||
|
/// <param name="angle">Initial z rotation</param>
|
||||||
|
/// <returns>Volume transformation otherwise there is no hit surface by screen coor</returns>
|
||||||
|
std::optional<Transform3d> create_volume_transformation_on_surface(const Vec2d &screen_coor,
|
||||||
|
const Camera &camera,
|
||||||
|
const ModelVolume &volume,
|
||||||
|
const ModelInstance &instance,
|
||||||
|
RaycastManager &raycaster,
|
||||||
|
GLCanvas3D &canvas,
|
||||||
|
const std::optional<float> &distance = {},
|
||||||
|
const std::optional<float> &angle = {});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create transformation for volume near from object(defined by glVolume)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gl_volume">Define object</param>
|
||||||
|
/// <param name="objects">All objects</param>
|
||||||
|
/// <param name="volume_height">Y Size of embossed volume [mm in instance]</param>
|
||||||
|
/// <param name="volume_depth">Z size of embossed volume - emboss depth[mm in instance]</param>
|
||||||
|
/// <returns>Transformation for new created volume</returns>
|
||||||
|
Transform3d create_volume_transformation(const GLVolume& gl_volume, const ModelObjectPtrs &objects, float volume_height, float volume_depth);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find volume in selected objects with closest convex hull to screen center.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="selection">Define where to search for closest</param>
|
||||||
|
/// <param name="screen_center">Canvas center(dependent on camera settings)</param>
|
||||||
|
/// <param name="objects">Actual objects</param>
|
||||||
|
/// <param name="closest_center">OUT: coordinate of controid of closest volume</param>
|
||||||
|
/// <returns>closest volume when exists otherwise nullptr</returns>
|
||||||
|
const GLVolume *find_closest(
|
||||||
|
const Selection &selection, const Vec2d &screen_center, const Camera &camera, const ModelObjectPtrs &objects, Vec2d *closest_center);
|
||||||
|
|
||||||
} // namespace Slic3r::GUI
|
} // namespace Slic3r::GUI
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user