6#include <igl/boundary_conditions.h>
8#include <igl/boundary_loop.h>
9#include <igl/exact_geodesic.h>
10#include <igl/bounding_box.h>
11#include <igl/writeOBJ.h>
15#include <unsupported/Eigen/SparseExtra>
17#include <unordered_map>
24 Eigen::Matrix<double, 3, 1> affine_transformation(
const Eigen::Matrix<double, 3, 1> &control_pt,
const Eigen::Matrix<double, 3, 1> &point,
const Eigen::Matrix<double, 6, 1> ¶m)
26 Eigen::Matrix<double, 3, 1> transformed_point(3);
28 const double helper_0 = cos(param(2));
29 const double helper_1 = control_pt(0) - point(0);
30 const double helper_2 = cos(param(1));
31 const double helper_3 = helper_1 * helper_2;
32 const double helper_4 = control_pt(2) - point(2);
33 const double helper_5 = sin(param(0));
34 const double helper_6 = sin(param(2));
35 const double helper_7 = helper_5 * helper_6;
36 const double helper_8 = sin(param(1));
37 const double helper_9 = cos(param(0));
38 const double helper_10 = helper_0 * helper_9;
39 const double helper_11 = control_pt(1) - point(1);
40 const double helper_12 = helper_6 * helper_9;
41 const double helper_13 = helper_0 * helper_5;
42 transformed_point(0) = control_pt(0) - helper_0 * helper_3 - helper_11 * (-helper_12 + helper_13 * helper_8) - helper_4 * (helper_10 * helper_8 + helper_7) + param(3);
43 transformed_point(1) = control_pt(1) - helper_11 * (helper_10 + helper_7 * helper_8) - helper_3 * helper_6 + helper_4 * (-helper_12 * helper_8 + helper_13) + param(4);
44 transformed_point(2) = control_pt(2) + helper_1 * helper_8 - helper_11 * helper_2 * helper_5 - helper_2 * helper_4 * helper_9 + param(5);
46 return transformed_point;
49 Eigen::MatrixXd grad_affine_transformation(
const Eigen::Matrix<double, 3, 1> &control_pt,
const Eigen::VectorXd &point,
const Eigen::VectorXd ¶m)
51 Eigen::MatrixXd
grad(6, 3);
53 const double helper_0 = control_pt(1) - point(1);
54 const double helper_1 = sin(param(0));
55 const double helper_2 = sin(param(2));
56 const double helper_3 = helper_1 * helper_2;
57 const double helper_4 = sin(param(1));
58 const double helper_5 = cos(param(0));
59 const double helper_6 = cos(param(2));
60 const double helper_7 = helper_5 * helper_6;
61 const double helper_8 = helper_3 + helper_4 * helper_7;
62 const double helper_9 = control_pt(2) - point(2);
63 const double helper_10 = helper_2 * helper_5;
64 const double helper_11 = helper_1 * helper_6;
65 const double helper_12 = -helper_10 + helper_11 * helper_4;
66 const double helper_13 = control_pt(0) - point(0);
67 const double helper_14 = cos(param(1));
68 const double helper_15 = helper_0 * helper_1;
69 const double helper_16 = helper_5 * helper_9;
70 const double helper_17 = helper_13 * helper_4 - helper_14 * helper_15 - helper_14 * helper_16;
71 const double helper_18 = helper_13 * helper_14;
72 const double helper_19 = helper_3 * helper_4 + helper_7;
73 const double helper_20 = -helper_10 * helper_4 + helper_11;
74 grad(0) = -helper_0 * helper_8 + helper_12 * helper_9;
75 grad(1) = helper_17 * helper_6;
76 grad(2) = helper_0 * helper_19 + helper_18 * helper_2 - helper_20 * helper_9;
80 grad(6) = helper_0 * helper_20 + helper_19 * helper_9;
81 grad(7) = helper_17 * helper_2;
82 grad(8) = -helper_0 * helper_12 - helper_18 * helper_6 - helper_8 * helper_9;
86 grad(12) = helper_14 * (-helper_0 * helper_5 + helper_1 * helper_9);
87 grad(13) = helper_15 * helper_4 + helper_16 * helper_4 + helper_18;
93 return grad.transpose();
111 Eigen::MatrixXd new_control_points;
115 for (
int i = 1; i < new_control_points.rows() - 1; ++i)
116 new_control_points.row(i) =
x.segment(2 * i - 2, 2);
122 Eigen::MatrixXd new_vertices;
123 spline_->reparametrize(new_control_points, new_vertices);
130 Eigen::VectorXd grad;
131 spline_->derivative_wrt_params(grad_full, grad);
142 return Eigen::VectorXd();
149 return Eigen::VectorXd();
154 return Eigen::VectorXd();
158 : num_control_vertices_(num_control_vertices), num_vertices_(num_vertices), allow_rotations_(allow_rotations)
166 const auto &mesh = state.
mesh;
167 const auto &bases = state.
bases;
171 const int e = lb.element_id();
172 for (
int i = 0; i < lb.size(); ++i)
174 const int primitive_global_id = lb.global_primitive_id(i);
175 const int boundary_id = mesh->get_boundary_id(primitive_global_id);
176 const auto nodes = gbases[e].local_nodes_for_primitive(primitive_global_id, *mesh);
178 for (
int f = 0; f < nodes.size(); ++f)
180 F_surface_(f_size - 1, f) = map[gbases[e].bases[nodes(f)].global()[0].index];
185 for (
int e = 0; e < gbases.size(); e++)
187 for (
const auto &gbs : gbases[e].bases)
188 V_surface_.row(map[gbs.global()[0].index]) = gbs.global()[0].node;
194 std::set<int> fixed_vertices;
196 for (
int i = 0; i < boundary_loop.size(); ++i)
197 fixed_vertices.insert(boundary_loop(i));
198 for (
const auto &i : existing_points)
199 fixed_vertices.insert(i);
202 Eigen::VectorXi free_vertices(
V.rows() - fixed_vertices.size());
204 for (
int i = 0; i <
V.rows(); ++i)
205 if (fixed_vertices.find(i) == fixed_vertices.end())
206 free_vertices(s++) = i;
208 Eigen::VectorXi VS, FS, FT;
209 VS.resize(fixed_vertices.size());
211 for (
const auto &j : fixed_vertices)
215 igl::exact_geodesic(
V,
F, VS, FS, free_vertices, FT, d);
217 double max_min_dist = -1;
218 for (
int i = 0; i < d.size(); ++i)
223 opt_idx = free_vertices(i);
226 else if (d(i) > max_min_dist)
229 opt_idx = free_vertices(i);
244 Eigen::VectorXi outer_loop;
245 std::vector<std::vector<int>> loops;
246 igl::boundary_loop(
F, loops);
247 if (loops.size() == 1)
249 outer_loop.resize(loops[0].
size());
250 for (
int i = 0; i < loops[0].size(); ++i)
251 outer_loop(i) = loops[0][i];
255 logger().error(
"More than 1 boundary loop! Concatenating and continuing as normal.");
256 for (
const auto &l : loops)
258 int size = outer_loop.size();
259 outer_loop.conservativeResize(outer_loop.size() + l.size());
260 for (
int i = 0; i < l.size(); ++i)
261 outer_loop(
size + i) = l[i];
264 Eigen::MatrixXd V_outer_loop =
V(outer_loop, Eigen::all);
268 std::vector<int> control_indices;
270 std::set<int> possible_control_vertices;
271 for (
int i = 0; i <
F.rows(); ++i)
272 for (
int j = 0; j <
F.cols(); ++j)
273 possible_control_vertices.insert(
F(i, j));
274 for (
int i = 0; i < outer_loop.size(); ++i)
275 possible_control_vertices.erase(outer_loop(i));
279 const int recompute_loops = 5;
280 for (
int r = 0; r < recompute_loops; ++r)
284 std::vector<int> indices = control_indices;
285 indices.erase(indices.begin() + i);
287 control_indices[i] = new_idx;
296 igl::writeOBJ(
"bbw_control_points_" + std::to_string(
V.rows()) +
".obj",
control_points_, Eigen::MatrixXi::Zero(0, 3));
297 igl::writeOBJ(
"bbw_outer_loop_" + std::to_string(
V.rows()) +
".obj", V_outer_loop, Eigen::MatrixXi::Zero(0, 3));
301 Eigen::VectorXi point_handles_idx(point_handles.rows());
302 for (
int i = 0; i < point_handles_idx.size(); ++i)
303 point_handles_idx(i) = i;
304 igl::boundary_conditions(
V,
F, point_handles, point_handles_idx, Eigen::VectorXi(), Eigen::VectorXi(), Eigen::VectorXi(), b, bc);
306 igl::BBWData bbw_data;
307 bbw_data.active_set_params.max_iter = 500;
308 bbw_data.verbosity = 1;
309 bbw_data.partition_unity =
false;
310 Eigen::MatrixXd complete_bbw_weights;
311 bool computation = igl::bbw(
V,
F, b, bc, bbw_data, complete_bbw_weights);
315 complete_bbw_weights = (complete_bbw_weights.array().colwise() / complete_bbw_weights.array().rowwise().sum()).
eval();
319 igl::writeOBJ(
"surface_mesh.obj",
V,
F);
320 Eigen::saveMarket(
bbw_weights_.sparseView(0, 1e-8).eval(),
"bbw_control_weights.mat");
332 Eigen::VectorXd
y = Eigen::VectorXd::Zero(
y_start.size());
337 Eigen::Matrix<double, 6, 1> affine_params =
x.segment(j * 6, 6);
358 Eigen::VectorXd grad = Eigen::VectorXd::Zero(
x.size());
363 grad.segment(j * 6, 6) +=
bbw_weights_(i, j) * grad_affine_transformation(
control_points_.row(j),
y_start.segment(i * 3, 3),
x.segment(j * 6, 6)).transpose() * grad_full.segment(i * 3, 3);
369 grad.segment(j * 3, 3) +=
bbw_weights_(i, j) * grad_full.segment(i * 3, 3);
377 std::unordered_map<int, int> full_to_reduced_indices;
381 for (
int i = 0; i <
V.rows(); ++i)
385 BV.col(0) =
V.row(i);
386 BV.col(1) =
V.row(i);
390 for (
int j = 0; j < 3; ++j)
392 BV(j, 0) = std::min(BV(j, 0),
V(i, j));
393 BV(j, 1) = std::max(BV(j, 1),
V(i, j));
398 Eigen::VectorXd bbox_width = (BV.col(1) - BV.col(0));
399 for (
int j = 0; j < 3; ++j)
400 if (bbox_width(j) < 1e-12)
401 bbox_width(j) = 1e-3;
404 BV.col(0) -= 0.05 * (BV.col(1) - BV.col(0));
405 BV.col(1) += 0.05 * (BV.col(1) - BV.col(0));
407 auto in_bbox = [&BV](
const Eigen::VectorXd &
x) {
409 in &= (
x(0) >= BV(0, 0)) && (
x(0) <= BV(0, 1));
410 in &= (
x(1) >= BV(1, 0)) && (
x(1) <= BV(1, 1));
411 in &= (
x(2) >= BV(2, 0)) && (
x(0) <= BV(2, 1));
416 for (
int j = 0; j <
V.rows(); ++j)
420 full_to_reduced_indices[i] = j;
426 bool contains_face =
true;
427 for (
int j = 0; j < 3; ++j)
428 contains_face &= (full_to_reduced_indices.count(
F_surface_(i, j)) == 1);
432 F.conservativeResize(
F.rows() + 1, 3);
433 for (
int j = 0; j < 3; ++j)
434 F(
F.rows() - 1, j) = full_to_reduced_indices.at(
F_surface_(i, j));
main class that contains the polyfem solver and all its state
void get_vertices(Eigen::MatrixXd &vertices) const
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
std::vector< int > node_to_primitive() const
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
std::vector< mesh::LocalBoundary > total_local_boundary
mapping from elements to nodes for all mesh
bool invoked_inverse_eval_
const Eigen::VectorXd knots_
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
std::shared_ptr< BSplineParametrization2D > spline_
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
const Eigen::MatrixXd initial_control_points_
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
const Eigen::VectorXd knots_u_
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
const Eigen::MatrixXd initial_control_point_grid_
std::shared_ptr< BSplineParametrization3D > spline_
const Eigen::VectorXd knots_v_
bool invoked_inverse_eval_
Eigen::MatrixXi F_surface_
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eigen::MatrixXd boundary_bbw_weights_
const int num_control_vertices_
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
Eigen::MatrixXd control_points_
Eigen::MatrixXd V_surface_
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
void compute_faces_for_partial_vertices(const Eigen::MatrixXd &V, Eigen::MatrixXi &F) const
const bool allow_rotations_
Eigen::MatrixXd bbw_weights_
bool invoked_inverse_eval_
int size(const int x_size) const override
BoundedBiharmonicWeights2Dto3D(const int num_control_vertices, const int num_vertices, const Eigen::MatrixXd &V_surface, const Eigen::MatrixXi &F_surface)
int optimal_new_control_point_idx(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::VectorXi &boundary_loop, const std::vector< int > &existing_points) const
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
spdlog::logger & logger()
Retrieves the current logger.
void log_and_throw_error(const std::string &msg)