PolyFEM
Loading...
Searching...
No Matches
BSplineParametrization.cpp
Go to the documentation of this file.
3
4namespace polyfem
5{
6 // void BSplineParametrization::get_parameters(const Eigen::MatrixXd &V, Eigen::MatrixXd &control_points)
7 // {
8 // bool mesh_changed = V.rows() != num_vertices;
9 // get_parameters(V, control_points, mesh_changed);
10 // }
11
12 BSplineParametrization2D::BSplineParametrization2D(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &knots, const Eigen::MatrixXd &V) : BSplineParametrization(V), dim(control_points.cols())
13 {
14 assert(dim == 2);
15 // Deduce the t parameter of all of the points in the spline sections
16 double tol = 1e-4;
17 curve.set_control_points(control_points);
18 curve.set_knots(knots);
19 std::vector<int> unused;
20 for (int i = 0; i < V.rows(); ++i)
21 node_ids_.push_back(i);
22 for (const auto &b : node_ids_)
23 {
24 Eigen::MatrixXd point = V.block(b, 0, 1, dim);
25 auto t = curve.approximate_inverse_evaluate(point);
26 double distance = (point - curve.evaluate(t)).norm();
27
28 if (distance > tol)
29 {
30 logger().error("Could not find a valid t for deducing spline parametrization. Distance: {}, point: {}, {}", distance, point(0), point(1));
31 unused.push_back(b);
32 continue;
33 }
34
35 node_id_to_t_[b] = t;
36 }
37
38 if (unused.size() > 0)
39 log_and_throw_error("Some nodes do not take part in the spline parametrization!");
40
41 // Remove nodes that do not have a parametrization.
42 // for (const auto &i : unused)
43 // {
44 // auto loc = std::find(node_ids_.begin(), node_ids_.end(), i);
45 // if (loc == node_ids_.end())
46 // logger().error("Error removing unused node.");
47 // node_ids_.erase(loc);
48 // }
49 logger().info("Number of useful boundary nodes in spline parametrization: {}", node_ids_.size());
50 }
51
52 void BSplineParametrization2D::reparametrize(const Eigen::MatrixXd &control_points, Eigen::MatrixXd &newV)
53 {
54 // Given new control parameters and the t parameter precomputed, compute new V
55 curve.set_control_points(control_points);
56 newV.setZero(node_ids_.size(), 2);
57 for (const auto &b : node_ids_)
58 {
59 auto new_val = curve.evaluate(node_id_to_t_.at(b));
60 newV.block(b, 0, 1, dim) = new_val;
61 }
62 }
63
64 void BSplineParametrization2D::get_parameters(const Eigen::MatrixXd &V, Eigen::MatrixXd &control_points, const bool mesh_changed)
65 {
66 assert(!mesh_changed);
67 Eigen::MatrixXd boundary_points(node_ids_.size(), dim), t_params(node_ids_.size(), 1);
68 bool boundary_changed = false;
69 for (int i = 0; i < node_ids_.size(); ++i)
70 {
71 auto old_point = curve.evaluate(node_id_to_t_.at(node_ids_[i]));
72 auto new_point = V.block(node_ids_[i], 0, 1, dim);
73 boundary_points.block(i, 0, 1, dim) = new_point;
74 t_params(i) = node_id_to_t_.at(node_ids_[i]);
75 double difference = (old_point - new_point).norm();
76 if (difference > 1e-4)
77 {
78 boundary_changed = true;
79 }
80 }
81 if (boundary_changed)
82 {
83 // Deduce parameter values from vertex positions. This will involve fitting on an overdetermined system
84 auto new_curve = curve.fit(t_params, boundary_points, curve.get_control_points().rows(), curve.get_knots());
85 control_points = new_curve.get_control_points();
86 }
87 else
88 {
89 control_points = curve.get_control_points();
90 }
91 }
92
93 void BSplineParametrization2D::derivative_wrt_params(const Eigen::VectorXd &grad_boundary, Eigen::VectorXd &grad_control_points)
94 {
95 grad_control_points.setZero(curve.get_control_points().size());
96 nanospline::BSpline<double, 1, 3> curve_;
97 curve_.set_knots(curve.get_knots());
98
99 for (int i = 0; i < curve.get_control_points().rows(); ++i)
100 {
101 Eigen::MatrixXd indicator = Eigen::MatrixXd::Zero(curve.get_control_points().rows(), 1);
102 indicator(i) = 1;
103 curve_.set_control_points(indicator);
104 for (const auto &b : node_ids_)
105 {
106 auto basis_val = curve_.evaluate(node_id_to_t_.at(b))(0);
107 for (int k = 0; k < dim; ++k)
108 grad_control_points(i * dim + k) += grad_boundary(b * dim + k) * basis_val;
109 }
110 }
111 }
112
113 void BSplineParametrization2D::gradient(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_points, const double t_parameter, const double distance, Eigen::MatrixXd &grad)
114 {
115 nanospline::BSpline<double, 2, 3> curve;
116 curve.set_control_points(control_points);
117 auto val = curve.evaluate(t_parameter);
118
119 grad = (point - val) / distance;
120 }
121
122 void BSplineParametrization2D::eval(const Eigen::MatrixXd &control_points, const double t, Eigen::MatrixXd &val)
123 {
124 nanospline::BSpline<double, 2, 3> curve;
125 curve.set_control_points(control_points);
126 val = curve.evaluate(t);
127 }
128
129 void BSplineParametrization2D::deriv(const Eigen::MatrixXd &control_points, const double t, Eigen::MatrixXd &val)
130 {
131 nanospline::BSpline<double, 2, 3> curve;
132 curve.set_control_points(control_points);
133 val = curve.evaluate_derivative(t);
134 }
135
136 BSplineParametrization3D::BSplineParametrization3D(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &knots_u, const Eigen::MatrixXd &knots_v, const Eigen::MatrixXd &V) : BSplineParametrization(V), dim(control_points.cols())
137 {
138 assert(dim == 3);
139 // Deduce the t parameter of all of the points in the spline sections
140 double tol = 1e-4;
141 patch.set_control_grid(control_points);
142 patch.set_knots_u(knots_u);
143 patch.set_knots_v(knots_v);
144 patch.initialize();
145 std::vector<int> unused;
146 for (int i = 0; i < V.rows(); ++i)
147 node_ids_.push_back(i);
148 for (const auto &b : node_ids_)
149 {
150 Eigen::MatrixXd point = V.block(b, 0, 1, dim);
151 auto uv = patch.approximate_inverse_evaluate(point, 5, 5, 0, 1, 0, 1, 30);
152 assert(uv.size() == 2);
153 double distance = (point - patch.evaluate(uv(0), uv(1))).norm();
154
155 if (distance > tol)
156 {
157 logger().error("Could not find a valid uv for deducing spline parametrization. Distance: {}", distance);
158 unused.push_back(b);
159 continue;
160 }
161
162 node_id_to_param_[b] = uv;
163 }
164
165 if (unused.size() > 0)
166 log_and_throw_error("Some nodes do not take part in the spline parametrization!");
167
168 // Remove nodes that do not have a parametrization.
169 // for (const auto &i : unused)
170 // {
171 // auto loc = std::find(node_ids_.begin(), node_ids_.end(), i);
172 // if (loc == node_ids_.end())
173 // logger().error("Error removing unused node.");
174 // node_ids_.erase(loc);
175 // }
176 logger().info("Number of useful boundary nodes in spline parametrization: {}", node_ids_.size());
177 }
178
179 void BSplineParametrization3D::get_parameters(const Eigen::MatrixXd &V, Eigen::MatrixXd &control_points, const bool mesh_changed)
180 {
181 assert(!mesh_changed);
182 Eigen::MatrixXd boundary_points(node_ids_.size(), dim), uv_params(node_ids_.size(), 2);
183 bool boundary_changed = false;
184 for (int i = 0; i < node_ids_.size(); ++i)
185 // for (const auto &b : node_ids_)
186 {
187 auto uv = node_id_to_param_.at(node_ids_[i]);
188 assert(uv.size() == 2);
189 auto old_point = patch.evaluate(uv(0), uv(1));
190 auto new_point = V.block(node_ids_[i], 0, 1, dim);
191 boundary_points.block(i, 0, 1, dim) = new_point;
192 uv_params.row(i) = uv;
193 double difference = (old_point - new_point).norm();
194 if (difference > 1e-4)
195 {
196 boundary_changed = true;
197 }
198 }
199 if (boundary_changed)
200 {
201 // Deduce parameter values from vertex positions. This will involve fitting on an overdetermined system
202 auto new_patch = patch.fit(uv_params, boundary_points, patch.get_knots_u().size() - 1 - 3, patch.get_knots_v().size() - 1 - 3, patch.get_knots_u(), patch.get_knots_v());
203 control_points = new_patch.get_control_grid();
204 }
205 else
206 {
207 control_points = patch.get_control_grid();
208 }
209 }
210
211 void BSplineParametrization3D::reparametrize(const Eigen::MatrixXd &control_points, Eigen::MatrixXd &newV)
212 {
213 // Given new control parameters and the t parameter precomputed, compute new V
214 newV.setZero(node_ids_.size(), 3);
215 patch.set_control_grid(control_points);
216 patch.initialize();
217 for (const auto &b : node_ids_)
218 {
219 auto uv = node_id_to_param_.at(b);
220 assert(uv.size() == 2);
221 auto new_val = patch.evaluate(uv(0), uv(1));
222 newV.block(b, 0, 1, dim) = new_val;
223 }
224 }
225
226 void BSplineParametrization3D::derivative_wrt_params(const Eigen::VectorXd &grad_boundary, Eigen::VectorXd &grad_control_points)
227 {
228
229 grad_control_points.setZero(patch.get_control_grid().size());
230
231 for (int i = 0; i < patch.get_control_grid().rows(); ++i)
232 {
233 nanospline::BSplinePatch<double, 3, 3, 3> patch_;
234 patch_.set_knots_u(patch.get_knots_u());
235 patch_.set_knots_v(patch.get_knots_v());
236 Eigen::MatrixXd indicator = Eigen::MatrixXd::Zero(patch.get_control_grid().rows(), 3);
237 indicator.row(i) = Eigen::VectorXd::Ones(3);
238 patch_.set_control_grid(indicator);
239 patch_.initialize();
240 for (const auto &b : node_ids_)
241 {
242 auto uv = node_id_to_param_.at(b);
243 assert(uv.size() == 2);
244 auto basis_val = patch_.evaluate(uv(0), uv(1))(0);
245 for (int k = 0; k < dim; ++k)
246 grad_control_points(i * dim + k) += grad_boundary(b * dim + k) * basis_val;
247 }
248 }
249 }
250
251 void BSplineParametrization3D::gradient(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, const double distance, Eigen::MatrixXd &grad)
252 {
253 assert(uv_parameter.size() == 2);
254 nanospline::BSplinePatch<double, 3, 3, 3> patch;
255 patch.set_control_grid(control_points);
256 auto val = patch.evaluate(uv_parameter(0), uv_parameter(1));
257
258 grad = (point - val) / distance;
259 }
260
261 void BSplineParametrization3D::eval(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, Eigen::MatrixXd &val)
262 {
263 assert(uv_parameter.size() == 2);
264 nanospline::BSplinePatch<double, 3, 3, 3> patch;
265 patch.set_control_grid(control_points);
266 val = patch.evaluate(uv_parameter(0), uv_parameter(1));
267 }
268
269 void BSplineParametrization3D::deriv(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, Eigen::MatrixXd &deriv_u, Eigen::MatrixXd &deriv_v)
270 {
271 assert(uv_parameter.size() == 2);
272 nanospline::BSplinePatch<double, 3, 3, 3> patch;
273 patch.set_control_grid(control_points);
274 deriv_u = patch.evaluate_derivative_u(uv_parameter(0), uv_parameter(1));
275 deriv_v = patch.evaluate_derivative_v(uv_parameter(0), uv_parameter(1));
276 }
277} // namespace polyfem
int V
double val
Definition Assembler.cpp:86
void derivative_wrt_params(const Eigen::VectorXd &grad_boundary, Eigen::VectorXd &grad_control_points) override
BSplineParametrization2D(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &knots, const Eigen::MatrixXd &V)
void reparametrize(const Eigen::MatrixXd &control_points, Eigen::MatrixXd &newV) override
static void eval(const Eigen::MatrixXd &control_points, const double t, Eigen::MatrixXd &val)
static void deriv(const Eigen::MatrixXd &control_points, const double t, Eigen::MatrixXd &val)
nanospline::BSpline< double, 2, 3 > curve
static void gradient(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_points, const double t_parameter, const double distance, Eigen::MatrixXd &grad)
void get_parameters(const Eigen::MatrixXd &V, Eigen::MatrixXd &control_points, const bool mesh_changed) override
static void gradient(const Eigen::MatrixXd &point, const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, const double distance, Eigen::MatrixXd &grad)
static void deriv(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, Eigen::MatrixXd &deriv_u, Eigen::MatrixXd &deriv_v)
std::map< int, Eigen::MatrixXd > node_id_to_param_
void get_parameters(const Eigen::MatrixXd &V, Eigen::MatrixXd &control_points, const bool mesh_changed) override
static void eval(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &uv_parameter, Eigen::MatrixXd &val)
BSplineParametrization3D(const Eigen::MatrixXd &control_points, const Eigen::MatrixXd &knots_u, const Eigen::MatrixXd &knots_v, const Eigen::MatrixXd &V)
nanospline::BSplinePatch< double, 3, 3, 3 > patch
void derivative_wrt_params(const Eigen::VectorXd &grad_boundary, Eigen::VectorXd &grad_control_points) override
void reparametrize(const Eigen::MatrixXd &control_points, Eigen::MatrixXd &newV) override
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71