Project text origin on object surface when use surface is set. When no intersection thans closest point is selected
(@vojta wants it)
This commit is contained in:
parent
043c4c5e90
commit
e8e50b50f1
@ -1,5 +1,6 @@
|
||||
#include "CameraUtils.hpp"
|
||||
#include <igl/project.h> // projecting points
|
||||
#include <igl/unproject.h>
|
||||
|
||||
#include "slic3r/GUI/3DScene.hpp" // GLVolume
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
@ -79,37 +80,48 @@ Slic3r::Polygon CameraUtils::create_hull2d(const Camera & camera,
|
||||
return Geometry::convex_hull(vertices_2d);
|
||||
}
|
||||
|
||||
#include <igl/unproject.h>
|
||||
Vec3d CameraUtils::create_ray(const Camera &camera, const Vec2d &coor) {
|
||||
if (camera.get_type() == Camera::EType::Ortho)
|
||||
return camera.get_dir_forward();
|
||||
// check that it is known camera no other tha ORTHO or Persepective
|
||||
assert(camera.get_type() == Camera::EType::Perspective);
|
||||
void CameraUtils::ray_from_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction) {
|
||||
switch (camera.get_type()) {
|
||||
case Camera::EType::Ortho: return ray_from_ortho_screen_pos(camera, position, point, direction);
|
||||
case Camera::EType::Perspective: return ray_from_persp_screen_pos(camera, position, point, direction);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
Vec3d CameraUtils::screen_point(const Camera &camera, const Vec2d &position)
|
||||
{
|
||||
double height = camera.get_viewport().data()[3];
|
||||
// Y coordinate has opposit direction
|
||||
return Vec3d(position.x(), height - position.y(), 0.);
|
||||
}
|
||||
|
||||
void CameraUtils::ray_from_ortho_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction)
|
||||
{
|
||||
assert(camera.get_type() == Camera::EType::Ortho);
|
||||
Matrix4d modelview = camera.get_view_matrix().matrix();
|
||||
Matrix4d projection = camera.get_projection_matrix().matrix();
|
||||
Vec4i viewport(camera.get_viewport().data());
|
||||
igl::unproject(screen_point(camera,position), modelview, projection, viewport, point);
|
||||
direction = camera.get_dir_forward();
|
||||
}
|
||||
void CameraUtils::ray_from_persp_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction)
|
||||
{
|
||||
assert(camera.get_type() == Camera::EType::Perspective);
|
||||
Matrix4d modelview = camera.get_view_matrix().matrix();
|
||||
Matrix4d projection = camera.get_projection_matrix().matrix();
|
||||
Vec4i viewport(camera.get_viewport().data());
|
||||
|
||||
Vec3d scene_point(coor.x(), viewport[3] - coor.y(), 0.);
|
||||
Vec3d unprojected_point;
|
||||
igl::unproject(scene_point, modelview, projection, viewport, unprojected_point);
|
||||
igl::unproject(screen_point(camera, position), modelview, projection, viewport, unprojected_point);
|
||||
|
||||
Vec3d p0 = camera.get_position();
|
||||
Vec3d dir = unprojected_point - p0;
|
||||
dir.normalize();
|
||||
return dir;
|
||||
point = camera.get_position();
|
||||
direction = unprojected_point - point;
|
||||
}
|
||||
|
||||
Vec2d CameraUtils::get_z0_position(const Camera &camera, const Vec2d & coor)
|
||||
{
|
||||
Vec3d dir = CameraUtils::create_ray(camera, coor);
|
||||
Vec3d p0 = camera.get_position();
|
||||
if (camera.get_type() == Camera::EType::Ortho) {
|
||||
Matrix4d modelview = camera.get_view_matrix().matrix();
|
||||
Matrix4d projection = camera.get_projection_matrix().matrix();
|
||||
Vec4i viewport(camera.get_viewport().data());
|
||||
igl::unproject(Vec3d(coor.x(), viewport[3] - coor.y(), 0.), modelview, projection, viewport, p0);
|
||||
}
|
||||
Vec3d p0, dir;
|
||||
ray_from_screen_pos(camera, coor, p0, dir);
|
||||
|
||||
// is approx zero
|
||||
if ((fabs(dir.z()) - 1e-4) < 0)
|
||||
@ -117,7 +129,7 @@ Vec2d CameraUtils::get_z0_position(const Camera &camera, const Vec2d & coor)
|
||||
std::numeric_limits<double>::max());
|
||||
|
||||
// find position of ray cross plane(z = 0)
|
||||
double t = p0.z() / dir.z();
|
||||
double t = p0.z() / dir.z();
|
||||
Vec3d p = p0 - t * dir;
|
||||
return Vec2d(p.x(), p.y());
|
||||
}
|
||||
|
@ -36,12 +36,15 @@ public:
|
||||
static Polygon create_hull2d(const Camera &camera, const GLVolume &volume);
|
||||
|
||||
/// <summary>
|
||||
/// Unproject screen coordinate to scene direction start from camera position
|
||||
/// Create ray(point and direction) for screen coordinate
|
||||
/// </summary>
|
||||
/// <param name="camera">Projection params</param>
|
||||
/// <param name="coor">Coordinate on screen</param>
|
||||
/// <returns>Scene direction</returns>
|
||||
static Vec3d create_ray(const Camera &camera, const Vec2d &coor);
|
||||
/// <param name="camera">Definition of camera</param>
|
||||
/// <param name="position">Position on screen(aka mouse position) </param>
|
||||
/// <param name="point">OUT start of ray</param>
|
||||
/// <param name="direction">OUT direction of ray</param>
|
||||
static void ray_from_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction);
|
||||
static void ray_from_ortho_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction);
|
||||
static void ray_from_persp_screen_pos(const Camera &camera, const Vec2d &position, Vec3d &point, Vec3d &direction);
|
||||
|
||||
/// <summary>
|
||||
/// Unproject mouse coordinate to get position in space where z coor is zero
|
||||
@ -52,6 +55,14 @@ public:
|
||||
/// <returns>Position on platter under mouse</returns>
|
||||
static Vec2d get_z0_position(const Camera &camera, const Vec2d &coor);
|
||||
|
||||
/// <summary>
|
||||
/// Create 3d screen point from 2d position
|
||||
/// </summary>
|
||||
/// <param name="camera">Define camera viewport</param>
|
||||
/// <param name="position">Position on screen(aka mouse position)</param>
|
||||
/// <returns>Point represented screen coor in 3d</returns>
|
||||
static Vec3d screen_point(const Camera &camera, const Vec2d &position);
|
||||
|
||||
};
|
||||
} // Slic3r::GUI
|
||||
|
||||
|
@ -506,7 +506,8 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||
if (!hit.has_value())
|
||||
return false;
|
||||
TextConfiguration &tc = *m_volume->text_configuration;
|
||||
// hide common dragging of object
|
||||
// INFO: GLVolume is transformed by common movement but we need move over surface
|
||||
// so hide common dragging of object
|
||||
m_parent.toggle_model_objects_visibility(false, m_volume->get_object(), gl_volume->instance_idx(), m_volume);
|
||||
|
||||
// Calculate temporary position
|
||||
@ -519,7 +520,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
|
||||
if (tc.fix_3mf_tr.has_value())
|
||||
trmat = trmat * (*tc.fix_3mf_tr);
|
||||
|
||||
// temp is in wolrld coors
|
||||
// temp is in world coors
|
||||
m_temp_transformation = object_trmat * trmat;
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
// Added because of weird case after double click into scene
|
||||
@ -2849,6 +2850,44 @@ void GLGizmoEmboss::do_rotate(float relative_z_angle)
|
||||
// snapshot_name = L("Set text rotation");
|
||||
m_parent.do_rotate(snapshot_name);
|
||||
}
|
||||
namespace priv {
|
||||
bool transform_on_surface(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 = priv::get_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());
|
||||
//direction.normalize();
|
||||
|
||||
// ray in direction of text projection(from volume zero to z-dir)
|
||||
std::optional<RaycastManager::Hit> hit_opt = raycast_manager.unproject(point, direction, &cond);
|
||||
if (!hit_opt.has_value())
|
||||
hit_opt = raycast_manager.closest(point);
|
||||
|
||||
if (!hit_opt.has_value())
|
||||
return false;
|
||||
|
||||
const RaycastManager::Hit &hit = *hit_opt;
|
||||
Transform3d hit_tr = raycast_manager.get_transformation(hit.tr_key);
|
||||
Vec3d hit_world = hit_tr * hit.position.cast<double>();
|
||||
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;
|
||||
|
||||
// when try to use surface on just loaded text from 3mf
|
||||
auto fix = volume.text_configuration->fix_3mf_tr;
|
||||
if (fix.has_value())
|
||||
offset_volume = fix->linear() * offset_volume;
|
||||
|
||||
volume.set_transformation(volume.get_matrix() * Eigen::Translation<double, 3>(offset_volume));
|
||||
return true;
|
||||
}
|
||||
} // namespace priv
|
||||
|
||||
void GLGizmoEmboss::draw_advanced()
|
||||
{
|
||||
@ -2903,7 +2942,7 @@ void GLGizmoEmboss::draw_advanced()
|
||||
if (font_prop.emboss < 0.1)
|
||||
font_prop.emboss = 1;
|
||||
|
||||
// TODO: project an origin on surface
|
||||
priv::transform_on_surface(*m_volume, m_raycast_manager, m_parent.get_selection());
|
||||
}
|
||||
process();
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "slic3r/GUI/CameraUtils.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
@ -340,36 +341,24 @@ Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
|
||||
return m_normals[facet_idx];
|
||||
}
|
||||
|
||||
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& point, Vec3d& direction)
|
||||
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, Vec3d& point, Vec3d& direction)
|
||||
{
|
||||
Matrix4d modelview = camera.get_view_matrix().matrix();
|
||||
Matrix4d projection= camera.get_projection_matrix().matrix();
|
||||
Vec4i viewport(camera.get_viewport().data());
|
||||
|
||||
Vec3d pt1;
|
||||
Vec3d pt2;
|
||||
igl::unproject(Vec3d(mouse_pos.x(), viewport[3] - mouse_pos.y(), 0.),
|
||||
modelview, projection, viewport, pt1);
|
||||
igl::unproject(Vec3d(mouse_pos.x(), viewport[3] - mouse_pos.y(), 1.),
|
||||
modelview, projection, viewport, pt2);
|
||||
|
||||
CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction);
|
||||
Transform3d inv = trafo.inverse();
|
||||
pt1 = inv * pt1;
|
||||
pt2 = inv * pt2;
|
||||
|
||||
point = pt1;
|
||||
direction = pt2-pt1;
|
||||
point = inv*point;
|
||||
direction = inv.linear()*direction;
|
||||
}
|
||||
|
||||
|
||||
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
|
||||
size_t* facet_idx) const
|
||||
{
|
||||
Vec3d point;
|
||||
Vec3d direction;
|
||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
||||
CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction);
|
||||
Transform3d inv = trafo.inverse();
|
||||
point = inv*point;
|
||||
direction = inv.linear()*direction;
|
||||
|
||||
std::vector<AABBMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||
|
||||
|
@ -145,6 +145,7 @@ public:
|
||||
assert(m_mesh != nullptr);
|
||||
}
|
||||
|
||||
// DEPRICATED - use CameraUtils::ray_from_screen_pos
|
||||
static void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& point, Vec3d& direction);
|
||||
|
||||
@ -159,6 +160,8 @@ public:
|
||||
size_t* facet_idx = nullptr // index of the facet hit
|
||||
) const;
|
||||
|
||||
const AABBMesh &get_aabb_mesh() const { return m_emesh; }
|
||||
|
||||
bool is_valid_intersection(Vec3d point, Vec3d direction, const Transform3d& trafo) const;
|
||||
|
||||
// Given a vector of points in woorld coordinates, this returns vector
|
||||
|
@ -73,20 +73,23 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
|
||||
m_transformations.erase(m_transformations.begin() + i);
|
||||
}
|
||||
|
||||
namespace priv {
|
||||
struct HitWithDistance : public RaycastManager::Hit
|
||||
{
|
||||
double squared_distance;
|
||||
HitWithDistance(double squared_distance,
|
||||
const Hit::Key &key,
|
||||
const SurfacePoint &surface_point)
|
||||
: Hit(key, surface_point.position, surface_point.normal)
|
||||
, squared_distance(squared_distance)
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
||||
const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const
|
||||
{
|
||||
struct HitWithDistance: public Hit
|
||||
{
|
||||
double squared_distance;
|
||||
HitWithDistance(double squared_distance,
|
||||
const TrKey & key,
|
||||
const SurfacePoint &surface_point)
|
||||
: Hit(key, surface_point.position, surface_point.normal)
|
||||
, squared_distance(squared_distance)
|
||||
{}
|
||||
};
|
||||
std::optional<HitWithDistance> closest;
|
||||
std::optional<priv::HitWithDistance> closest;
|
||||
for (const auto &item : m_transformations) {
|
||||
const TrKey &key = item.first;
|
||||
size_t volume_id = key.second;
|
||||
@ -109,13 +112,69 @@ std::optional<RaycastManager::Hit> RaycastManager::unproject(
|
||||
if (closest.has_value() &&
|
||||
closest->squared_distance < squared_distance)
|
||||
continue;
|
||||
closest = HitWithDistance(squared_distance, key, surface_point);
|
||||
closest = priv::HitWithDistance(squared_distance, key, surface_point);
|
||||
}
|
||||
|
||||
//if (!closest.has_value()) return {};
|
||||
return closest;
|
||||
}
|
||||
|
||||
std::optional<RaycastManager::Hit> RaycastManager::unproject(const Vec3d &point, const Vec3d &direction, const ISkip *skip) const
|
||||
{
|
||||
std::optional<priv::HitWithDistance> closest;
|
||||
for (const auto &item : m_transformations) {
|
||||
const TrKey &key = item.first;
|
||||
size_t volume_id = key.second;
|
||||
if (skip != nullptr && skip->skip(volume_id)) continue;
|
||||
const Transform3d &transformation = item.second;
|
||||
auto raycaster_it =
|
||||
std::find_if(m_raycasters.begin(), m_raycasters.end(),
|
||||
[volume_id](const RaycastManager::Raycaster &it)
|
||||
-> bool { return volume_id == it.first; });
|
||||
if (raycaster_it == m_raycasters.end()) continue;
|
||||
const MeshRaycaster &raycaster = *(raycaster_it->second);
|
||||
const AABBMesh& mesh = raycaster.get_aabb_mesh();
|
||||
const Transform3d & tr_inv = transformation.inverse();
|
||||
Vec3d mesh_point = tr_inv * point;
|
||||
Vec3d mesh_direction = tr_inv.linear() * direction;
|
||||
std::vector<AABBMesh::hit_result> hits = mesh.query_ray_hits(mesh_point, mesh_direction);
|
||||
for (const AABBMesh::hit_result &hit : hits) {
|
||||
double squared_distance = (mesh_point - hit.position()).squaredNorm();
|
||||
if (closest.has_value() &&
|
||||
closest->squared_distance < squared_distance)
|
||||
continue;
|
||||
SurfacePoint surface_point(hit.position().cast<float>(), hit.normal().cast<float>());
|
||||
closest = priv::HitWithDistance(squared_distance, key, surface_point);
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
std::optional<RaycastManager::Hit> RaycastManager::closest(const Vec3d &point, const ISkip *skip) const {
|
||||
Vec3f point_f = point.cast<float>();
|
||||
std::optional<priv::HitWithDistance> closest;
|
||||
for (const auto &item : m_transformations) {
|
||||
const TrKey &key = item.first;
|
||||
size_t volume_id = key.second;
|
||||
if (skip != nullptr && skip->skip(volume_id))
|
||||
continue;
|
||||
const Transform3d &transformation = item.second;
|
||||
auto raycaster_it = std::find_if(m_raycasters.begin(), m_raycasters.end(),
|
||||
[volume_id](const RaycastManager::Raycaster &it) -> bool { return volume_id == it.first; });
|
||||
if (raycaster_it == m_raycasters.end())
|
||||
continue;
|
||||
const MeshRaycaster &raycaster = *(raycaster_it->second);
|
||||
Vec3f n;
|
||||
Vec3f p = raycaster.get_closest_point(point_f, &n);
|
||||
double squared_distance = (point_f - p).squaredNorm();
|
||||
if (closest.has_value() && closest->squared_distance < squared_distance)
|
||||
continue;
|
||||
SurfacePoint surface_point(p,n);
|
||||
closest = priv::HitWithDistance(squared_distance, key, surface_point);
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) const {
|
||||
auto item = std::find_if(m_transformations.begin(),
|
||||
m_transformations.end(),
|
||||
|
@ -65,8 +65,9 @@ public:
|
||||
|
||||
struct Hit: public SurfacePoint
|
||||
{
|
||||
TrKey tr_key;
|
||||
Hit(TrKey tr_key, Vec3f position, Vec3f normal)
|
||||
using Key = TrKey;
|
||||
Key tr_key;
|
||||
Hit(Key tr_key, Vec3f position, Vec3f normal)
|
||||
: SurfacePoint(position, normal), tr_key(tr_key)
|
||||
{}
|
||||
};
|
||||
@ -102,6 +103,23 @@ public:
|
||||
const Camera &camera,
|
||||
const ISkip *skip = nullptr) const;
|
||||
|
||||
/// <summary>
|
||||
/// Unproject Ray(point direction) on mesh by MeshRaycasters
|
||||
/// </summary>
|
||||
/// <param name="point">Start point for ray</param>
|
||||
/// <param name="direction">Direction of ray</param>
|
||||
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
||||
/// <returns>Position on surface, normal direction and transformation key, which define hitted object instance</returns>
|
||||
std::optional<Hit> unproject(const Vec3d &point, const Vec3d &direction, const ISkip *skip = nullptr) const;
|
||||
|
||||
/// <summary>
|
||||
/// Search of closest point
|
||||
/// </summary>
|
||||
/// <param name="point">Point</param>
|
||||
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
||||
/// <returns></returns>
|
||||
std::optional<Hit> closest(const Vec3d &point, const ISkip *skip = nullptr) const;
|
||||
|
||||
/// <summary>
|
||||
/// Getter on transformation
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user