189 lines
7.2 KiB
C++
189 lines
7.2 KiB
C++
#ifndef slic3r_RaycastManager_hpp_
|
|
#define slic3r_RaycastManager_hpp_
|
|
|
|
#include <memory> // unique_ptr
|
|
#include <optional>
|
|
#include "libslic3r/SLA/IndexedMesh.hpp" //#include "libslic3r/AABBMesh.hpp" // Structure to cast rays
|
|
#include "libslic3r/Point.hpp" // Transform3d
|
|
#include "libslic3r/ObjectID.hpp"
|
|
#include "libslic3r/Model.hpp" // ModelObjectPtrs, ModelObject, ModelInstance, ModelVolume
|
|
|
|
namespace Slic3r::GUI{
|
|
|
|
/// <summary>
|
|
/// Cast rays from camera to scene
|
|
/// Used for find hit point on model volume under mouse cursor
|
|
/// </summary>
|
|
class RaycastManager
|
|
{
|
|
// Public structures used by RaycastManager
|
|
public:
|
|
|
|
// ModelVolume.id
|
|
using Mesh = std::pair<size_t, std::unique_ptr<sla::IndexedMesh> >;//AABBMesh
|
|
using Meshes = std::vector<Mesh>;
|
|
|
|
// Key for transformation consist of unique volume and instance id ... ObjectId()
|
|
// ModelInstance, ModelVolume
|
|
using TrKey = std::pair<size_t, size_t>;
|
|
using TrItem = std::pair<TrKey, Transform3d>;
|
|
using TrItems = std::vector<TrItem>;
|
|
|
|
/// <summary>
|
|
/// Interface for identify allowed volumes to cast rays.
|
|
/// </summary>
|
|
class ISkip{
|
|
public:
|
|
virtual ~ISkip() = default;
|
|
|
|
/// <summary>
|
|
/// Condition to not process model volume
|
|
/// </summary>
|
|
/// <param name="model_volume_id">ObjectID of model volume to not process</param>
|
|
/// <returns>True on skip otherwise false</returns>
|
|
virtual bool skip(const size_t &model_volume_id) const { return false; }
|
|
};
|
|
|
|
// TODO: it is more general object move outside of this class
|
|
template<typename T>
|
|
struct SurfacePoint {
|
|
using Vec3 = Eigen::Matrix<T, 3, 1, Eigen::DontAlign>;
|
|
Vec3 position = Vec3::Zero();
|
|
Vec3 normal = Vec3::UnitZ();
|
|
};
|
|
|
|
struct Hit : public SurfacePoint<double>
|
|
{
|
|
TrKey tr_key;
|
|
double squared_distance;
|
|
};
|
|
|
|
struct ClosePoint
|
|
{
|
|
TrKey tr_key;
|
|
Vec3d point;
|
|
double squared_distance;
|
|
};
|
|
const Meshes& get_meshes() { return m_meshes; }
|
|
// Members
|
|
private:
|
|
// Keep structure to fast cast rays
|
|
// meshes are sorted by volume_id for faster search
|
|
Meshes m_meshes;
|
|
|
|
// Keep transformation of meshes
|
|
TrItems m_transformations;
|
|
// Note: one mesh could have more transformations ... instances
|
|
|
|
public:
|
|
|
|
/// <summary>
|
|
/// Actualize raycasters + transformation
|
|
/// Detection of removed object
|
|
/// Detection of removed instance
|
|
/// Detection of removed volume
|
|
/// </summary>
|
|
/// <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);
|
|
|
|
class SkipVolume: public ISkip
|
|
{
|
|
size_t volume_id;
|
|
public:
|
|
SkipVolume(size_t volume_id) : volume_id(volume_id) {}
|
|
bool skip(const size_t &model_volume_id) const override { return model_volume_id == volume_id; }
|
|
};
|
|
|
|
class AllowVolumes: public ISkip
|
|
{
|
|
std::vector<size_t> allowed_id;
|
|
public:
|
|
AllowVolumes() = default;
|
|
AllowVolumes(std::vector<size_t> allowed_id) : allowed_id(allowed_id) {}
|
|
void clear() {
|
|
allowed_id.clear();
|
|
}
|
|
bool skip(const size_t &model_volume_id) const override {
|
|
if (allowed_id.size() == 0) {
|
|
return false;
|
|
}
|
|
auto it = std::find(allowed_id.begin(), allowed_id.end(), model_volume_id);
|
|
return it == allowed_id.end();
|
|
}
|
|
};
|
|
|
|
/// <summary>
|
|
/// Unproject on mesh and return closest hit to point in given direction
|
|
/// </summary>
|
|
/// <param name="point">Position in space</param>
|
|
/// <param name="direction">Casted ray direction</param>
|
|
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
|
/// <returns>Position on surface, normal direction in world coorinate
|
|
/// + key, to know hitted instance and volume</returns>
|
|
std::optional<Hit> first_hit(const Vec3d &point, const Vec3d &direction, const ISkip *skip = nullptr) const;
|
|
|
|
/// <summary>
|
|
/// Unproject Ray(point direction) on mesh to find closest hit of surface in given direction
|
|
/// NOTE: It inspect also oposit direction of ray !!
|
|
/// </summary>
|
|
/// <param name="point">Start point for ray</param>
|
|
/// <param name="direction">Direction of ray, orientation doesn't matter, both are used</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> closest_hit(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<ClosePoint> closest(const Vec3d &point, const ISkip *skip = nullptr) const;
|
|
|
|
/// <summary>
|
|
/// Getter on transformation from hitted volume to world
|
|
/// </summary>
|
|
/// <param name="tr_key">Define transformation</param>
|
|
/// <returns>Transformation for key</returns>
|
|
Transform3d get_transformation(const TrKey &tr_key) const;
|
|
void clear();
|
|
};
|
|
|
|
class GLCanvas3D;
|
|
/// <summary>
|
|
/// Use scene Raycasters and prepare data for actualize RaycasterManager
|
|
/// </summary>
|
|
/// <param name="canvas">contain Scene raycasters</param>
|
|
/// <param name="condition">Limit for scene casters</param>
|
|
/// <returns>Meshes</returns>
|
|
RaycastManager::Meshes create_meshes(GLCanvas3D &canvas, const RaycastManager::AllowVolumes &condition);
|
|
|
|
struct Camera;
|
|
/// <summary>
|
|
/// Unproject on mesh by Mesh raycasters
|
|
/// </summary>
|
|
/// <param name="mouse_pos">Position of mouse on screen</param>
|
|
/// <param name="camera">Projection params</param>
|
|
/// <param name="skip">Define which caster will be skipped, null mean no skip</param>
|
|
/// <returns>Position on surface, normal direction in world coorinate
|
|
/// + key, to know hitted instance and volume</returns>
|
|
std::optional<RaycastManager::Hit> ray_from_camera(const RaycastManager &raycaster,
|
|
const Vec2d &mouse_pos,
|
|
const Camera &camera,
|
|
const RaycastManager::ISkip *skip);
|
|
|
|
/// <summary>
|
|
/// Create condition to allowe only parts from volumes without one given
|
|
/// </summary>
|
|
/// <param name="volumes">List of allowed volumes included one which is dissalowed and non parts</param>
|
|
/// <param name="disallowed_volume_id">Disallowed volume</param>
|
|
/// <returns>Condition</returns>
|
|
RaycastManager::AllowVolumes create_condition(const ModelVolumePtrs &volumes, const ObjectID &disallowed_volume_id);
|
|
|
|
} // namespace Slic3r::GUI
|
|
|
|
#endif // slic3r_RaycastManager_hpp_
|