mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 03:01:48 +08:00
extend functionality of surface drag
This commit is contained in:
parent
a1a57eb61c
commit
b7f4159d57
@ -345,16 +345,6 @@ bool GLGizmoEmboss::on_mouse_for_rotation(const wxMouseEvent &mouse_event)
|
||||
}
|
||||
|
||||
namespace priv {
|
||||
/// <summary>
|
||||
/// Get transformation to world
|
||||
/// - use fix after store to 3mf when exists
|
||||
/// </summary>
|
||||
/// <param name="gl_volume">Scene volume</param>
|
||||
/// <param name="model">To identify MovelVolume with fix transformation</param>
|
||||
/// <returns></returns>
|
||||
static Transform3d world_matrix(const GLVolume *gl_volume, const Model *model);
|
||||
static Transform3d world_matrix(const Selection &selection);
|
||||
|
||||
/// <summary>
|
||||
/// Change position of emboss window
|
||||
/// </summary>
|
||||
@ -363,36 +353,6 @@ static Transform3d world_matrix(const Selection &selection);
|
||||
static void change_window_position(std::optional<ImVec2> &output_window_offset, bool try_to_fix);
|
||||
} // namespace priv
|
||||
|
||||
Transform3d priv::world_matrix(const GLVolume *gl_volume, const Model *model)
|
||||
{
|
||||
if (!gl_volume)
|
||||
return Transform3d::Identity();
|
||||
Transform3d res = gl_volume->world_matrix();
|
||||
|
||||
if (!model)
|
||||
return res;
|
||||
|
||||
const ModelVolume* mv = get_model_volume(*gl_volume, model->objects);
|
||||
if (!mv)
|
||||
return res;
|
||||
|
||||
const std::optional<TextConfiguration> &tc = mv->text_configuration;
|
||||
if (!tc.has_value())
|
||||
return res;
|
||||
|
||||
const std::optional<Transform3d> &fix = tc->fix_3mf_tr;
|
||||
if (!fix.has_value())
|
||||
return res;
|
||||
|
||||
return res * fix->inverse();
|
||||
}
|
||||
|
||||
Transform3d priv::world_matrix(const Selection &selection)
|
||||
{
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(selection);
|
||||
return world_matrix(gl_volume, selection.get_model());
|
||||
}
|
||||
|
||||
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
// exist selected volume?
|
||||
@ -1115,17 +1075,6 @@ static inline void execute_job(std::shared_ptr<Job> j)
|
||||
});
|
||||
}
|
||||
|
||||
namespace priv {
|
||||
/// <summary>
|
||||
/// Calculate translation of text volume onto surface of model
|
||||
/// </summary>
|
||||
/// <param name="volume">Text</param>
|
||||
/// <param name="raycast_manager">AABB trees of object. Actualize object containing text</param>
|
||||
/// <param name="selection">Transformation of actual instance</param>
|
||||
/// <returns>Offset of volume in volume coordinate</returns>
|
||||
std::optional<Vec3d> calc_surface_offset(const ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection);
|
||||
} // namespace priv
|
||||
|
||||
bool GLGizmoEmboss::process()
|
||||
{
|
||||
// no volume is selected -> selection from right panel
|
||||
@ -1160,7 +1109,7 @@ bool GLGizmoEmboss::process()
|
||||
|
||||
// when it is new applying of use surface than move origin onto surfaca
|
||||
if (!m_volume->text_configuration->style.prop.use_surface) {
|
||||
auto offset = priv::calc_surface_offset(*m_volume, m_raycast_manager, m_parent.get_selection());
|
||||
auto offset = calc_surface_offset(m_parent.get_selection(), m_raycast_manager);
|
||||
if (offset.has_value())
|
||||
text_tr *= Eigen::Translation<double, 3>(*offset);
|
||||
}
|
||||
@ -1231,7 +1180,7 @@ bool priv::apply_camera_dir(const Camera &camera, GLCanvas3D &canvas) {
|
||||
if (sel.is_empty()) return false;
|
||||
|
||||
// camera direction transformed into volume coordinate system
|
||||
Transform3d to_world = priv::world_matrix(sel);
|
||||
Transform3d to_world = world_matrix_fixed(sel);
|
||||
Vec3d cam_dir_tr = to_world.inverse().linear() * cam_dir;
|
||||
cam_dir_tr.normalize();
|
||||
|
||||
@ -2949,53 +2898,6 @@ void GLGizmoEmboss::do_rotate(float relative_z_angle)
|
||||
m_parent.do_rotate(snapshot_name);
|
||||
}
|
||||
|
||||
std::optional<Vec3d> priv::calc_surface_offset(const ModelVolume &volume, RaycastManager &raycast_manager, const Selection &selection) {
|
||||
// Move object on surface
|
||||
auto cond = RaycastManager::SkipVolume(volume.id().id);
|
||||
raycast_manager.actualize(volume.get_object(), &cond);
|
||||
|
||||
//const Selection &selection = m_parent.get_selection();
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(selection);
|
||||
Transform3d to_world = priv::world_matrix(gl_volume, selection.get_model());
|
||||
Vec3d point = to_world * Vec3d::Zero();
|
||||
Vec3d direction = to_world.linear() * (-Vec3d::UnitZ());
|
||||
|
||||
// ray in direction of text projection(from volume zero to z-dir)
|
||||
std::optional<RaycastManager::Hit> hit_opt = raycast_manager.closest_hit(point, direction, &cond);
|
||||
|
||||
// Try to find closest point when no hit object in emboss direction
|
||||
if (!hit_opt.has_value()) {
|
||||
std::optional<RaycastManager::ClosePoint> close_point_opt = raycast_manager.closest(point);
|
||||
|
||||
// It should NOT appear. Closest point always exists.
|
||||
assert(close_point_opt.has_value());
|
||||
if (!close_point_opt.has_value())
|
||||
return {};
|
||||
|
||||
// It is no neccesary to move with origin by very small value
|
||||
if (close_point_opt->squared_distance < EPSILON)
|
||||
return {};
|
||||
|
||||
const RaycastManager::ClosePoint &close_point = *close_point_opt;
|
||||
Transform3d hit_tr = raycast_manager.get_transformation(close_point.tr_key);
|
||||
Vec3d hit_world = hit_tr * close_point.point;
|
||||
Vec3d offset_world = hit_world - point; // vector in world
|
||||
Vec3d offset_volume = to_world.inverse().linear() * offset_world;
|
||||
return offset_volume;
|
||||
}
|
||||
|
||||
// It is no neccesary to move with origin by very small value
|
||||
const RaycastManager::Hit &hit = *hit_opt;
|
||||
if (hit.squared_distance < EPSILON)
|
||||
return {};
|
||||
Transform3d hit_tr = raycast_manager.get_transformation(hit.tr_key);
|
||||
Vec3d hit_world = hit_tr * hit.position;
|
||||
Vec3d offset_world = hit_world - point; // vector in world
|
||||
// TIP: It should be close to only z move
|
||||
Vec3d offset_volume = to_world.inverse().linear() * offset_world;
|
||||
return offset_volume;
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::draw_advanced()
|
||||
{
|
||||
const auto &ff = m_style_manager.get_font_file_with_cache();
|
||||
@ -3610,7 +3512,7 @@ bool priv::start_create_volume_on_surface_job(
|
||||
auto cond = RaycastManager::AllowVolumes({vol_id});
|
||||
|
||||
RaycastManager::Meshes meshes = create_meshes(canvas, cond);
|
||||
raycaster.actualize(obj, &cond, &meshes);
|
||||
raycaster.actualize(*obj, &cond, &meshes);
|
||||
|
||||
const Camera &camera = plater->get_camera();
|
||||
std::optional<RaycastManager::Hit> hit = ray_from_camera(raycaster, screen_coor, camera, &cond);
|
||||
|
@ -105,10 +105,13 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
||||
return false;
|
||||
|
||||
const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects);
|
||||
assert(object != nullptr);
|
||||
if (object == nullptr)
|
||||
return false;
|
||||
|
||||
const ModelInstance *instance = get_model_instance(*gl_volume, *object);
|
||||
const ModelVolume *volume = get_model_volume(*gl_volume, *object);
|
||||
|
||||
assert(object != nullptr && instance != nullptr && volume != nullptr);
|
||||
assert(instance != nullptr && volume != nullptr);
|
||||
if (object == nullptr || instance == nullptr || volume == nullptr)
|
||||
return false;
|
||||
|
||||
@ -131,7 +134,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
||||
// initialize raycasters
|
||||
// INFO: It could slows down for big objects
|
||||
// (may be move to thread and do not show drag until it finish)
|
||||
raycast_manager.actualize(instance, &condition, &meshes);
|
||||
raycast_manager.actualize(*instance, &condition, &meshes);
|
||||
|
||||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
@ -242,4 +245,92 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Vec3d> calc_surface_offset(const Selection &selection, RaycastManager &raycast_manager) {
|
||||
const GLVolume *gl_volume_ptr = get_selected_gl_volume(selection);
|
||||
if (gl_volume_ptr == nullptr)
|
||||
return {};
|
||||
const GLVolume& gl_volume = *gl_volume_ptr;
|
||||
|
||||
const ModelObjectPtrs &objects = selection.get_model()->objects;
|
||||
const ModelVolume* volume = get_model_volume(gl_volume, objects);
|
||||
if (volume == nullptr)
|
||||
return {};
|
||||
|
||||
const ModelInstance* instance = get_model_instance(gl_volume, objects);
|
||||
if (instance == nullptr)
|
||||
return {};
|
||||
|
||||
// Move object on surface
|
||||
auto cond = RaycastManager::SkipVolume(volume->id().id);
|
||||
raycast_manager.actualize(*instance, &cond);
|
||||
|
||||
Transform3d to_world = world_matrix_fixed(gl_volume, selection.get_model()->objects);
|
||||
Vec3d point = to_world * Vec3d::Zero();
|
||||
Vec3d direction = to_world.linear() * (-Vec3d::UnitZ());
|
||||
|
||||
// ray in direction of text projection(from volume zero to z-dir)
|
||||
std::optional<RaycastManager::Hit> hit_opt = raycast_manager.closest_hit(point, direction, &cond);
|
||||
|
||||
// Try to find closest point when no hit object in emboss direction
|
||||
if (!hit_opt.has_value()) {
|
||||
std::optional<RaycastManager::ClosePoint> close_point_opt = raycast_manager.closest(point);
|
||||
|
||||
// It should NOT appear. Closest point always exists.
|
||||
assert(close_point_opt.has_value());
|
||||
if (!close_point_opt.has_value())
|
||||
return {};
|
||||
|
||||
// It is no neccesary to move with origin by very small value
|
||||
if (close_point_opt->squared_distance < EPSILON)
|
||||
return {};
|
||||
|
||||
const RaycastManager::ClosePoint &close_point = *close_point_opt;
|
||||
Transform3d hit_tr = raycast_manager.get_transformation(close_point.tr_key);
|
||||
Vec3d hit_world = hit_tr * close_point.point;
|
||||
Vec3d offset_world = hit_world - point; // vector in world
|
||||
Vec3d offset_volume = to_world.inverse().linear() * offset_world;
|
||||
return offset_volume;
|
||||
}
|
||||
|
||||
// It is no neccesary to move with origin by very small value
|
||||
const RaycastManager::Hit &hit = *hit_opt;
|
||||
if (hit.squared_distance < EPSILON)
|
||||
return {};
|
||||
Transform3d hit_tr = raycast_manager.get_transformation(hit.tr_key);
|
||||
Vec3d hit_world = hit_tr * hit.position;
|
||||
Vec3d offset_world = hit_world - point; // vector in world
|
||||
// TIP: It should be close to only z move
|
||||
Vec3d offset_volume = to_world.inverse().linear() * offset_world;
|
||||
return offset_volume;
|
||||
}
|
||||
|
||||
Transform3d world_matrix_fixed(const GLVolume &gl_volume, const ModelObjectPtrs &objects)
|
||||
{
|
||||
Transform3d res = gl_volume.world_matrix();
|
||||
|
||||
const ModelVolume *mv = get_model_volume(gl_volume, objects);
|
||||
if (!mv)
|
||||
return res;
|
||||
|
||||
const std::optional<TextConfiguration> &tc = mv->text_configuration;
|
||||
if (!tc.has_value())
|
||||
return res;
|
||||
|
||||
const std::optional<Transform3d> &fix = tc->fix_3mf_tr;
|
||||
if (!fix.has_value())
|
||||
return res;
|
||||
|
||||
return res * fix->inverse();
|
||||
}
|
||||
|
||||
Transform3d world_matrix_fixed(const Selection &selection)
|
||||
{
|
||||
const GLVolume *gl_volume = get_selected_gl_volume(selection);
|
||||
assert(gl_volume != nullptr);
|
||||
if (gl_volume == nullptr)
|
||||
return Transform3d::Identity();
|
||||
|
||||
return world_matrix_fixed(*gl_volume, selection.get_model()->objects);
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
@ -12,6 +12,7 @@ class GLVolume;
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
class GLCanvas3D;
|
||||
class Selection;
|
||||
struct Camera;
|
||||
|
||||
// Data for drag&drop over surface with mouse
|
||||
@ -37,11 +38,48 @@ struct SurfaceDrag
|
||||
bool exist_hit = true;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Mouse event handler, when move(drag&drop) volume over model surface
|
||||
/// NOTE: Dragged volume has to be selected. And also has to be hovered on start of dragging.
|
||||
/// </summary>
|
||||
/// <param name="mouse_event">Contain type of event and mouse position</param>
|
||||
/// <param name="camera">Actual viewport of camera</param>
|
||||
/// <param name="surface_drag">Structure which keep information about dragging</param>
|
||||
/// <param name="canvas">Contain gl_volumes and selection</param>
|
||||
/// <param name="raycast_manager">AABB trees for raycast in object
|
||||
/// Refresh state inside of function </param>
|
||||
/// <returns>True when event is processed otherwise false</returns>
|
||||
bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
||||
const Camera &camera,
|
||||
std::optional<SurfaceDrag> &surface_drag,
|
||||
GLCanvas3D &canvas,
|
||||
RaycastManager &raycast_manager);
|
||||
|
||||
/// <summary>
|
||||
/// Calculate translation of volume onto surface of model
|
||||
/// </summary>
|
||||
/// <param name="selection">Must contain only one selected volume, Transformation of current instance</param>
|
||||
/// <param name="raycast_manager">AABB trees of object. Actualize object</param>
|
||||
/// <returns>Offset of volume in volume coordinate</returns>
|
||||
std::optional<Vec3d> calc_surface_offset(const Selection &selection, RaycastManager &raycast_manager);
|
||||
|
||||
/// <summary>
|
||||
/// Get transformation to world
|
||||
/// - use fix after store to 3mf when exists
|
||||
/// </summary>
|
||||
/// <param name="gl_volume">Scene volume</param>
|
||||
/// <param name="objects">To identify Model volume with fix transformation</param>
|
||||
/// <returns>Fixed Transformation of gl_volume</returns>
|
||||
Transform3d world_matrix_fixed(const GLVolume &gl_volume, const ModelObjectPtrs& objects);
|
||||
|
||||
/// <summary>
|
||||
/// Get transformation to world
|
||||
/// - use fix after store to 3mf when exists
|
||||
/// NOTE: when not one volume selected return identity
|
||||
/// </summary>
|
||||
/// <param name="selection">Selected volume</param>
|
||||
/// <returns>Fixed Transformation of selected volume in selection</returns>
|
||||
Transform3d world_matrix_fixed(const Selection &selection);
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
#endif // slic3r_SurfaceDrag_hpp_
|
@ -7,8 +7,8 @@ namespace priv {
|
||||
using namespace Slic3r;
|
||||
static void actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip, RaycastManager::Meshes *input = nullptr);
|
||||
static const AABBMesh * get_mesh(const RaycastManager::Meshes &meshes, size_t volume_id);
|
||||
static RaycastManager::TrKey create_key(const ModelVolume* volume, const ModelInstance* instance){
|
||||
return std::make_pair(instance->id().id, volume->id().id); }
|
||||
static RaycastManager::TrKey create_key(const ModelVolume& volume, const ModelInstance& instance){
|
||||
return std::make_pair(instance.id().id, volume.id().id); }
|
||||
static RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key);
|
||||
static bool is_lower_key(const RaycastManager::TrKey &k1, const RaycastManager::TrKey &k2) {
|
||||
return k1.first < k2.first || k1.first == k2.first && k1.second < k2.second; }
|
||||
@ -16,23 +16,23 @@ static bool is_lower(const RaycastManager::TrItem &i1, const RaycastManager::TrI
|
||||
return is_lower_key(i1.first, i2.first); };
|
||||
}
|
||||
|
||||
void RaycastManager::actualize(const ModelObject *object, const ISkip *skip, Meshes *meshes)
|
||||
void RaycastManager::actualize(const ModelObject &object, const ISkip *skip, Meshes *meshes)
|
||||
{
|
||||
// actualize MeshRaycaster
|
||||
priv::actualize(m_meshes, object->volumes, skip, meshes);
|
||||
priv::actualize(m_meshes, object.volumes, skip, meshes);
|
||||
|
||||
// check if inscance was removed
|
||||
std::vector<bool> removed_transf(m_transformations.size(), {true});
|
||||
|
||||
bool need_sort = false;
|
||||
// actualize transformation matrices
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
for (const ModelVolume *volume : object.volumes) {
|
||||
if (skip != nullptr && skip->skip(volume->id().id)) continue;
|
||||
const Transform3d &volume_tr = volume->get_matrix();
|
||||
for (const ModelInstance *instance : object->instances) {
|
||||
for (const ModelInstance *instance : object.instances) {
|
||||
const Transform3d &instrance_tr = instance->get_matrix();
|
||||
Transform3d transformation = instrance_tr * volume_tr;
|
||||
TrKey key = priv::create_key(volume, instance);
|
||||
TrKey key = priv::create_key(*volume, *instance);
|
||||
auto item = priv::find(m_transformations, key);
|
||||
if (item != m_transformations.end()) {
|
||||
// actualize transformation all the time
|
||||
@ -56,9 +56,9 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip, Mes
|
||||
std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower);
|
||||
}
|
||||
|
||||
void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip, Meshes *meshes)
|
||||
void RaycastManager::actualize(const ModelInstance &instance, const ISkip *skip, Meshes *meshes)
|
||||
{
|
||||
const ModelVolumePtrs &volumes = instance->get_object()->volumes;
|
||||
const ModelVolumePtrs &volumes = instance.get_object()->volumes;
|
||||
|
||||
// actualize MeshRaycaster
|
||||
priv::actualize(m_meshes, volumes, skip, meshes);
|
||||
@ -72,9 +72,9 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip,
|
||||
if (skip != nullptr && skip->skip(volume->id().id))
|
||||
continue;
|
||||
const Transform3d &volume_tr = volume->get_matrix();
|
||||
const Transform3d &instrance_tr = instance->get_matrix();
|
||||
const Transform3d &instrance_tr = instance.get_matrix();
|
||||
Transform3d transformation = instrance_tr * volume_tr;
|
||||
TrKey key = priv::create_key(volume, instance);
|
||||
TrKey key = priv::create_key(*volume, instance);
|
||||
auto item = priv::find(m_transformations, key);
|
||||
if (item != m_transformations.end()) {
|
||||
// actualize transformation all the time
|
||||
|
@ -86,8 +86,8 @@ public:
|
||||
/// <param name="object">Model representation</param>
|
||||
/// <param name="skip">Condifiton for skip actualization</param>
|
||||
/// <param name="meshes">Speed up for already created AABBtrees</param>
|
||||
void actualize(const ModelObject *object, const ISkip *skip = nullptr, Meshes *meshes = nullptr);
|
||||
void actualize(const ModelInstance *instance, const ISkip *skip = nullptr, Meshes* meshes = nullptr);
|
||||
void actualize(const ModelObject &object, const ISkip *skip = nullptr, Meshes *meshes = nullptr);
|
||||
void actualize(const ModelInstance &instance, const ISkip *skip = nullptr, Meshes* meshes = nullptr);
|
||||
|
||||
class SkipVolume: public ISkip
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user