#pragma once #include "implicit_function.hpp" static constexpr double kEpsilon = 1e-6; template class ConstantFunction : public ImplicitFunction { public: explicit ConstantFunction(Scalar value) : value_(value) {} Scalar evaluate_scalar(const Eigen::Ref> &pos) const { return value_; } Eigen::Vector evaluate_gradient(const Eigen::Ref> &pos) const { return Eigen::Vector::Zero(); } Eigen::Vector evaluate_scalar_gradient(const Eigen::Ref> &pos) const { auto res = Eigen::Vector::Zero(); res[0] = value_; return res; } private: Scalar value_{}; }; template class PlaneDistanceFunction : public ImplicitFunction { public: PlaneDistanceFunction(const Eigen::Ref> &point, const Eigen::Ref> &normal) : point_(point), normal_(normal) { normal_.normalize(); } Scalar evaluate_scalar(const Eigen::Ref> &pos) const { return normal_.dot(pos - point_); } Eigen::Vector evaluate_gradient(const Eigen::Ref> &pos) const { return normal_; } Eigen::Vector evaluate_scalar_gradient(const Eigen::Ref> &pos) const { Eigen::Vector res{}; res.template head().array() = normal_.array(); res[Dim] = evaluate_scalar(pos); return res; } private: Eigen::Vector point_{}; Eigen::Vector normal_{}; }; template class SphereDistanceFunction : public ImplicitFunction { public: SphereDistanceFunction(const Eigen::Ref> ¢er, Scalar radius) : center_(center), radius_(radius) { } Scalar evaluate_scalar(const Eigen::Ref> &pos) const { return (pos - center_).norm() - radius_; } Eigen::Vector evaluate_gradient(const Eigen::Ref> &pos) const { auto vec = pos - center_; Scalar norm = vec.norm(); if (norm <= kEpsilon) return Eigen::Vector::Zero(); return vec / norm; } Eigen::Vector evaluate_scalar_gradient(const Eigen::Ref> &pos) const { Eigen::Vector res{}; auto vec = pos - center_; Scalar norm = vec.norm(); if (norm <= kEpsilon) { res[Dim] = -radius_; return res; } res.template head().array() = vec.array() / norm; res[Dim] = norm - radius_; return res; } private: Eigen::Vector center_{}; Scalar radius_{}; }; template class CylinderDistanceFunction; template class CylinderDistanceFunction : public ImplicitFunction { public: CylinderDistanceFunction(const Eigen::Ref> &axis_point, const Eigen::Ref> &axis_dir, Scalar radius) : axis_point_(axis_point), axis_dir_(axis_dir), radius_(radius) { axis_dir_.normalize(); } Scalar evaluate_scalar(const Eigen::Ref> &pos) const { auto vec = pos - axis_point_; auto dist = vec.dot(axis_dir_); return (vec - dist * axis_dir_).norm() - radius_; } Eigen::Vector evaluate_gradient(const Eigen::Ref> &pos) const { auto vec = pos - axis_point_; auto dist = vec.dot(axis_dir_); auto vec_para = dist * axis_dir_; Eigen::Vector vec_perp = vec - vec_para; Scalar norm = vec_perp.norm(); if (norm <= kEpsilon) return Eigen::Vector::Zero(); return vec_perp / norm; } Eigen::Vector evaluate_scalar_gradient(const Eigen::Ref> &pos) const { Eigen::Vector res{}; auto vec = pos - axis_point_; auto dist = vec.dot(axis_dir_); auto vec_para = dist * axis_dir_; Eigen::Vector vec_perp = vec - vec_para; Scalar norm = vec_perp.norm(); if (norm <= kEpsilon) { res[3] = -radius_; return res; } res.template head<3>().array() = vec_perp.array() / norm; res[3] = norm - radius_; return res; } private: Eigen::Vector axis_point_{}; Eigen::Vector axis_dir_{}; Scalar radius_{}; }; template class ConeDistanceFunction; template class ConeDistanceFunction : public ImplicitFunction { public: ConeDistanceFunction(const Eigen::Ref> &apex_point, const Eigen::Ref> &axis_dir, Scalar apex_angle) : apex_point_(apex_point), axis_dir_(axis_dir), apex_angle_cosine_(std::cos(apex_angle)) { axis_dir_.normalize(); } Scalar evaluate_scalar(const Eigen::Ref> &pos) const { return apex_angle_cosine_ * (pos - apex_point_).norm() - (pos - apex_point_).dot(axis_dir_); } Eigen::Vector evaluate_gradient(const Eigen::Ref> &pos) const { auto vec_apex = pos - apex_point_; auto vec_norm = vec_apex.norm(); if (vec_norm <= kEpsilon) return Eigen::Vector::Zero(); return vec_apex * apex_angle_cosine_ / vec_norm - axis_dir_; } Eigen::Vector evaluate_scalar_gradient(const Eigen::Ref> &pos) const { auto vec_apex = pos - apex_point_; auto vec_norm = vec_apex.norm(); if (vec_norm <= kEpsilon) return Eigen::Vector::Zero(); Eigen::Vector res{}; res.template head<3>().array() = vec_apex.array() * apex_angle_cosine_ / vec_norm - axis_dir_.array(); res[3] = apex_angle_cosine_ * vec_norm - vec_apex.dot(axis_dir_); return res; } private: Eigen::Vector apex_point_{}; Eigen::Vector axis_dir_{}; Scalar apex_angle_cosine_{}; }; template class TorusDistanceFunction;