9#include <polysolve/LinearSolver.hpp>
16 CubicHermiteSplineParametrization(
const std::map<int, Eigen::MatrixXd> &control_point,
const std::map<int, Eigen::MatrixXd> &tangent,
const std::map<
int, std::vector<int>> &boundary_id_to_node_id,
const Eigen::MatrixXd &
V,
const int sampling) :
boundary_id_to_node_id_(boundary_id_to_node_id)
23 std::vector<int> unused;
25 for (
const auto &b : kv.second)
27 Eigen::MatrixXd point =
V.block(b, 0, 1,
dim);
28 point.transposeInPlace();
31 double t_optimal, distance, distance_to_start, distance_to_end;
32 find_nearest_spline(point, control_point.at(kv.first), tangent.at(kv.first), nearest, t_optimal, distance, distance_to_start, distance_to_end);
34 if (nearest == -1 || distance > tol)
36 logger().error(
"Could not find a valid t for deducing spline parametrization. Distance: {}, spline: {}, point: {}, {}", distance, nearest, point(0), point(1));
46 for (
const auto &i : unused)
50 logger().error(
"Error removing unused node.");
57 void reparametrize(
const std::map<int, Eigen::MatrixXd> &control_point,
const std::map<int, Eigen::MatrixXd> &tangent,
const Eigen::MatrixXd &
V, Eigen::MatrixXd &newV)
const
60 newV =
V.block(0, 0,
V.rows(), 2);
63 for (
const auto &b : kv.second)
65 Eigen::MatrixXd new_val;
67 newV.block(b, 0, 1,
dim) = new_val;
73 void get_parameters(
const Eigen::MatrixXd &
V, std::map<int, Eigen::MatrixXd> &control_point, std::map<int, Eigen::MatrixXd> &tangent)
const
81 A.setZero(kv.second.size(), 3 * spline_count + 1);
82 b.setZero(kv.second.size(), 2);
84 for (
const int id : kv.second)
87 double t_2 = pow(t, 2);
88 double t_3 = pow(t, 3);
90 A(i, spline) = 2 * t_3 - 3 * t_2 + 1;
91 A(i, spline + 1) = -2 * t_3 + 3 * t_2;
92 A(i, spline_count + 1 + 2 * spline) = t_3 - 2 * t_2 + t;
93 A(i, spline_count + 1 + 2 * spline + 1) = t_3 - t_2;
99 Eigen::VectorXd
x = (A.transpose() * A).ldlt().solve(A.transpose() * b.col(0));
100 Eigen::VectorXd
y = (A.transpose() * A).ldlt().solve(A.transpose() * b.col(1));
101 double error_x = (A *
x - b.col(0)).norm();
102 double error_y = (A *
y - b.col(1)).norm();
103 Eigen::MatrixXd control_points(spline_count + 1,
dim), tangents(2 * spline_count,
dim);
104 control_points.col(0) =
x.segment(0, spline_count + 1);
105 control_points.col(1) =
y.segment(0, spline_count + 1);
106 tangents.col(0) =
x.segment(spline_count + 1, 2 * spline_count);
107 tangents.col(1) =
y.segment(spline_count + 1, 2 * spline_count);
108 control_point[kv.first] = control_points;
109 tangent[kv.first] = tangents;
113 void derivative_wrt_params(
const Eigen::VectorXd &grad_boundary,
const int boundary_id,
const int couple_tangents, Eigen::VectorXd &grad_control_point, Eigen::VectorXd &grad_tangent)
const
116 grad_control_point.setZero(spline_count *
dim +
dim);
117 grad_tangent.setZero(spline_count * 2 *
dim);
121 double t_2 = pow(t, 2);
122 double t_3 = pow(t, 3);
124 grad_control_point.segment(spline *
dim,
dim) += (2 * t_3 - 3 * t_2 + 1) * grad_boundary.segment(b *
dim,
dim);
125 grad_control_point.segment(spline *
dim +
dim,
dim) += (-2 * t_3 + 3 * t_2) * grad_boundary.segment(b *
dim,
dim);
126 grad_tangent.segment(spline * 2 *
dim,
dim) += (t_3 - 2 * t_2 + t) * grad_boundary.segment(b *
dim,
dim);
127 grad_tangent.segment(spline * 2 *
dim +
dim,
dim) += (t_3 - t_2) * grad_boundary.segment(b *
dim,
dim);
130 int prev_spline = spline - 1;
132 grad_tangent.segment(prev_spline * 2 *
dim +
dim,
dim) += (t_3 - 2 * t_2 + t) * grad_boundary.segment(b *
dim,
dim);
136 grad_tangent.segment(prev_spline * 2 *
dim +
dim,
dim) += (t_3 - 2 * t_2 + t) * grad_boundary.segment(b *
dim,
dim);
139 if (spline != spline_count - 1)
141 int next_spline = spline + 1;
143 grad_tangent.segment(next_spline * 2 *
dim,
dim) += (t_3 - t_2) * grad_boundary.segment(b *
dim,
dim);
147 grad_tangent.segment(next_spline * 2 *
dim,
dim) += (t_3 - t_2) * grad_boundary.segment(b *
dim,
dim);
153 static void find_nearest_spline(
const Eigen::MatrixXd &point,
const Eigen::MatrixXd &control_point,
const Eigen::MatrixXd &tangent,
int &nearest,
double &t_optimal,
double &distance,
double &distance_to_start,
double &distance_to_end,
const double tol = 1e-4)
155 int dim = point.size();
156 int num_splines = control_point.rows() - 1;
158 auto dot = [](
const Eigen::MatrixXd &a,
const Eigen::MatrixXd &b) {
159 assert(a.cols() == 1);
160 assert(b.cols() == 1);
161 return (a.transpose() * b)(0);
164 auto f = [&](
const double t,
const int segment) {
166 eval(control_point.block(segment, 0, 2,
dim), tangent.block(2 * segment, 0, 2,
dim), t,
val);
167 val.transposeInPlace();
171 auto f_ = [&](
const double t,
const int segment) {
173 deriv(control_point.block(segment, 0, 2,
dim), tangent.block(2 * segment, 0, 2,
dim), t,
val);
174 val.transposeInPlace();
178 auto f__ = [&](
const double t,
const int segment) {
180 second_deriv(control_point.block(segment, 0, 2,
dim), tangent.block(2 * segment, 0, 2,
dim), t,
val);
181 val.transposeInPlace();
185 auto g = [&](
const double t,
const int segment) {
186 auto val = f(t, segment);
187 return dot(
val,
val) - 2 * dot(point,
val) + dot(point, point);
190 auto g_ = [&](
const double t,
const int segment) {
191 auto val = f(t, segment);
192 auto deriv = f_(t, segment);
196 auto g__ = [&](
const double t,
const int segment) {
197 auto val = f(t, segment);
198 auto deriv = f_(t, segment);
199 auto sec_deriv = f__(t, segment);
200 return 2 * dot(sec_deriv,
val - point) + 2 * dot(
deriv,
deriv);
203 Eigen::MatrixXd t = Eigen::MatrixXd::Ones(num_splines, 1) / 2.;
205 for (
int i = 0; i < t.rows(); ++i)
207 for (
int iter = 0; iter < 50; ++iter)
209 t(i) -= g_(t(i), i) / g__(t(i), i);
216 for (
int i = 0; i < t.rows(); ++i)
218 if ((t(i) < -tol) || (t(i) > 1 + tol))
220 double func = g(t(i), i);
221 if ((nearest == -1) || (func < distance))
229 distance_to_start = g(0, 0);
230 distance_to_end = g(1, t.rows() - 1);
233 static void gradient(
const Eigen::MatrixXd &point,
const Eigen::MatrixXd &control_point,
const Eigen::MatrixXd &tangent,
const int spline,
const double t_parameter,
const double distance, Eigen::MatrixXd &grad)
235 int dim = point.size();
237 auto f = [&](
const double t,
const int segment) {
239 eval(control_point.block(segment, 0, 2,
dim), tangent.block(2 * segment, 0, 2,
dim), t,
val);
240 val.transposeInPlace();
244 grad.col(0).segment(0,
dim) = (point - f(t_parameter, spline)) / distance;
247 static void eval(
const Eigen::MatrixXd &control_point,
const Eigen::MatrixXd &tangent,
const double t, Eigen::MatrixXd &
val)
249 double t_2 = pow(t, 2);
250 double t_3 = pow(t, 3);
251 val = (2 * t_3 - 3 * t_2 + 1) * control_point.row(0);
252 val += (t_3 - 2 * t_2 + t) * tangent.row(0);
253 val += (-2 * t_3 + 3 * t_2) * control_point.row(1);
254 val += (t_3 - t_2) * tangent.row(1);
257 static void deriv(
const Eigen::MatrixXd &control_point,
const Eigen::MatrixXd &tangent,
const double t, Eigen::MatrixXd &
val)
259 double t_2 = pow(t, 2);
260 val = (6 * t_2 - 6 * t) * control_point.row(0);
261 val += (3 * t_2 - 4 * t + 1) * tangent.row(0);
262 val += (-6 * t_2 + 6 * t) * control_point.row(1);
263 val += (3 * t_2 - 2 * t) * tangent.row(1);
266 static void second_deriv(
const Eigen::MatrixXd &control_point,
const Eigen::MatrixXd &tangent,
const double t, Eigen::MatrixXd &
val)
268 val = (12 * t - 6) * control_point.row(0);
269 val += (6 * t - 4) * tangent.row(0);
270 val += (-12 * t + 6) * control_point.row(1);
271 val += (6 * t - 2) * tangent.row(1);
void get_parameters(const Eigen::MatrixXd &V, std::map< int, Eigen::MatrixXd > &control_point, std::map< int, Eigen::MatrixXd > &tangent) const
std::map< int, int > node_id_to_spline_
static void eval(const Eigen::MatrixXd &control_point, const Eigen::MatrixXd &tangent, const double t, Eigen::MatrixXd &val)
static void second_deriv(const Eigen::MatrixXd &control_point, const Eigen::MatrixXd &tangent, const double t, Eigen::MatrixXd &val)
std::map< int, int > boundary_id_to_spline_count_
std::map< int, double > node_id_to_t_
CubicHermiteSplineParametrization(const std::map< int, Eigen::MatrixXd > &control_point, const std::map< int, Eigen::MatrixXd > &tangent, const std::map< int, std::vector< int > > &boundary_id_to_node_id, const Eigen::MatrixXd &V, const int sampling)
static void gradient(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_point, const Eigen::MatrixXd &tangent, const int spline, const double t_parameter, const double distance, Eigen::MatrixXd &grad)
void derivative_wrt_params(const Eigen::VectorXd &grad_boundary, const int boundary_id, const int couple_tangents, Eigen::VectorXd &grad_control_point, Eigen::VectorXd &grad_tangent) const
void reparametrize(const std::map< int, Eigen::MatrixXd > &control_point, const std::map< int, Eigen::MatrixXd > &tangent, const Eigen::MatrixXd &V, Eigen::MatrixXd &newV) const
static void deriv(const Eigen::MatrixXd &control_point, const Eigen::MatrixXd &tangent, const double t, Eigen::MatrixXd &val)
static void find_nearest_spline(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_point, const Eigen::MatrixXd &tangent, int &nearest, double &t_optimal, double &distance, double &distance_to_start, double &distance_to_end, const double tol=1e-4)
std::map< int, std::vector< int > > boundary_id_to_node_id_
spdlog::logger & logger()
Retrieves the current logger.