Blender V4.3
uv_initializer.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "uv_initializer.h"
10#include "cotmatrix.h"
11
12#include <Eigen/SparseLU>
13
14namespace slim {
15
16static double compute_angle(const Eigen::Vector3d &a, const Eigen::Vector3d &b)
17{
18 return acos(a.dot(b) / (a.norm() * b.norm()));
19}
20
22 const Eigen::MatrixXi &f,
23 const Eigen::MatrixXd &v,
24 Eigen::SparseMatrix<double> &vertex_to_face_indices)
25{
26
27 typedef Eigen::Triplet<double> t;
28 std::vector<t> coefficients;
29
30 for (int i = 0; i < f.rows(); i++) {
31
32 int vertex_index1 = f(i, 0);
33 int vertex_index2 = f(i, 1);
34 int vertex_index3 = f(i, 2);
35
36 double angle1 = compute_angle(v.row(vertex_index2) - v.row(vertex_index1),
37 v.row(vertex_index3) - v.row(vertex_index1));
38 double angle2 = compute_angle(v.row(vertex_index3) - v.row(vertex_index2),
39 v.row(vertex_index1) - v.row(vertex_index2));
40 double angle3 = compute_angle(v.row(vertex_index1) - v.row(vertex_index3),
41 v.row(vertex_index2) - v.row(vertex_index3));
42
43 coefficients.push_back(t(vertex_index1, 2 * vertex_index2, angle3));
44 coefficients.push_back(t(vertex_index1, 2 * vertex_index3 + 1, angle2));
45
46 coefficients.push_back(t(vertex_index2, 2 * vertex_index1 + 1, angle3));
47 coefficients.push_back(t(vertex_index2, 2 * vertex_index3, angle1));
48
49 coefficients.push_back(t(vertex_index3, 2 * vertex_index1, angle2));
50 coefficients.push_back(t(vertex_index3, 2 * vertex_index2 + 1, angle1));
51 }
52
53 vertex_to_face_indices.setFromTriplets(coefficients.begin(), coefficients.end());
54}
55
57 const Eigen::MatrixXi &f,
58 const Eigen::MatrixXd &v,
59 Eigen::SparseMatrix<double> &vertex_to_face_indices)
60{
61
62 typedef Eigen::Triplet<double> t;
63 std::vector<t> coefficients;
64
65 for (int i = 0; i < f.rows(); i++) {
66
67 int vertex_index1 = f(i, 0);
68 int vertex_index2 = f(i, 1);
69 int vertex_index3 = f(i, 2);
70
71 double angle1 = compute_angle(v.row(vertex_index2) - v.row(vertex_index1),
72 v.row(vertex_index3) - v.row(vertex_index1));
73 double angle2 = compute_angle(v.row(vertex_index3) - v.row(vertex_index2),
74 v.row(vertex_index1) - v.row(vertex_index2));
75 double angle3 = compute_angle(v.row(vertex_index1) - v.row(vertex_index3),
76 v.row(vertex_index2) - v.row(vertex_index3));
77
78 coefficients.push_back(t(vertex_index1, 2 * vertex_index2, angle1));
79 coefficients.push_back(t(vertex_index1, 2 * vertex_index3 + 1, angle1));
80
81 coefficients.push_back(t(vertex_index2, 2 * vertex_index1 + 1, angle2));
82 coefficients.push_back(t(vertex_index2, 2 * vertex_index3, angle2));
83
84 coefficients.push_back(t(vertex_index3, 2 * vertex_index1, angle3));
85 coefficients.push_back(t(vertex_index3, 2 * vertex_index2 + 1, angle3));
86 }
87
88 vertex_to_face_indices.setFromTriplets(coefficients.begin(), coefficients.end());
89}
90
91/* Implementation of different fixed-border parameterizations, mean value coordinates, harmonic,
92 * tutte. */
93void convex_border_parameterization(const Eigen::MatrixXi &f,
94 const Eigen::MatrixXd &v,
95 const Eigen::MatrixXi &e,
96 const Eigen::VectorXd &el,
97 const Eigen::VectorXi &bnd,
98 const Eigen::MatrixXd &bnd_uv,
99 Eigen::MatrixXd &uv,
100 Method method)
101{
102 int verts_num = uv.rows();
103 int edges_num = e.rows();
104
105 Eigen::SparseMatrix<double> vertex_to_angles(verts_num, verts_num * 2);
106
107 switch (method) {
108 case HARMONIC:
110 break;
111 case MVC:
112 find_vertex_to_its_angles_correspondence(f, v, vertex_to_angles);
113 break;
114 case TUTTE:
115 break;
116 }
117
118 int n_unknowns = verts_num - bnd.size();
119 int n_knowns = bnd.size();
120
121 Eigen::SparseMatrix<double> aint(n_unknowns, n_unknowns);
122 Eigen::SparseMatrix<double> abnd(n_unknowns, n_knowns);
123 Eigen::VectorXd z(n_knowns);
124
125 std::vector<Eigen::Triplet<double>> int_triplet_vector;
126 std::vector<Eigen::Triplet<double>> bnd_triplet_vector;
127
128 int rowindex;
129 int columnindex;
130 double edge_weight, edge_length;
131 Eigen::RowVector2i edge;
132
133 int first_vertex, second_vertex;
134
135 for (int e_idx = 0; e_idx < edges_num; e_idx++) {
136 edge = e.row(e_idx);
137 edge_length = el(e_idx);
138 first_vertex = edge(0);
139 second_vertex = edge(1);
140
141 if (first_vertex >= n_knowns) {
142 /* Into aint. */
143 rowindex = first_vertex - n_knowns;
144
145 double angle1 = vertex_to_angles.coeff(first_vertex, 2 * second_vertex);
146 double angle2 = vertex_to_angles.coeff(first_vertex, 2 * second_vertex + 1);
147
148 switch (method) {
149 case HARMONIC:
150 edge_weight = 1 / tan(angle1) + 1 / tan(angle2);
151 break;
152 case MVC:
153 edge_weight = tan(angle1 / 2) + tan(angle2 / 2);
154 edge_weight /= edge_length;
155 break;
156 case TUTTE:
157 edge_weight = 1;
158 break;
159 }
160
161 int_triplet_vector.push_back(Eigen::Triplet<double>(rowindex, rowindex, edge_weight));
162
163 if (second_vertex >= n_knowns) {
164 /* Also an unknown point in the interior. */
165 columnindex = second_vertex - n_knowns;
166
167 int_triplet_vector.push_back(Eigen::Triplet<double>(rowindex, columnindex, -edge_weight));
168 }
169 else {
170 /* Known point on the border. */
171 columnindex = second_vertex;
172 bnd_triplet_vector.push_back(Eigen::Triplet<double>(rowindex, columnindex, edge_weight));
173 }
174 }
175 }
176
177 aint.setFromTriplets(int_triplet_vector.begin(), int_triplet_vector.end());
178 aint.makeCompressed();
179
180 abnd.setFromTriplets(bnd_triplet_vector.begin(), bnd_triplet_vector.end());
181 abnd.makeCompressed();
182
183 for (int i = 0; i < n_unknowns; i++) {
184 double factor = aint.coeff(i, i);
185 aint.row(i) /= factor;
186 abnd.row(i) /= factor;
187 }
188
189 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
190 solver.compute(aint);
191
192 for (int i = 0; i < 2; i++) {
193
194 for (int zindex = 0; zindex < n_knowns; zindex++) {
195 z(zindex) = bnd_uv(bnd(zindex), i);
196 }
197
198 Eigen::VectorXd b = abnd * z;
199
200 Eigen::VectorXd uvs;
201 uvs = solver.solve(b);
202
203 Eigen::VectorXd boundary = bnd_uv.col(i);
204 Eigen::VectorXd interior = uvs;
205
206 uv.col(i) << boundary, interior;
207 }
208}
209
210void mvc(const Eigen::MatrixXi &f,
211 const Eigen::MatrixXd &v,
212 const Eigen::MatrixXi &e,
213 const Eigen::VectorXd &el,
214 const Eigen::VectorXi &bnd,
215 const Eigen::MatrixXd &bnd_uv,
216 Eigen::MatrixXd &uv)
217{
218
219 convex_border_parameterization(f, v, e, el, bnd, bnd_uv, uv, Method::MVC);
220}
221
222void harmonic(const Eigen::MatrixXi &f,
223 const Eigen::MatrixXd &v,
224 const Eigen::MatrixXi &e,
225 const Eigen::VectorXd &el,
226 const Eigen::VectorXi &bnd,
227 const Eigen::MatrixXd &bnd_uv,
228 Eigen::MatrixXd &uv)
229{
230
231 convex_border_parameterization(f, v, e, el, bnd, bnd_uv, uv, Method::HARMONIC);
232}
233
234void tutte(const Eigen::MatrixXi &f,
235 const Eigen::MatrixXd &v,
236 const Eigen::MatrixXi &e,
237 const Eigen::VectorXd &el,
238 const Eigen::VectorXi &bnd,
239 const Eigen::MatrixXd &bnd_uv,
240 Eigen::MatrixXd &uv)
241{
242
243 convex_border_parameterization(f, v, e, el, bnd, bnd_uv, uv, Method::TUTTE);
244}
245
246void map_vertices_to_convex_border(Eigen::MatrixXd &vertex_positions)
247{
248 double pi = atan(1) * 4;
249 int boundary_vertices_num = vertex_positions.rows();
250 double x, y;
251 double angle = 2 * pi / boundary_vertices_num;
252
253 for (int i = 0; i < boundary_vertices_num; i++) {
254 x = cos(angle * i);
255 y = sin(angle * i);
256 vertex_positions(i, 0) = (x * 0.5) + 0.5;
257 vertex_positions(i, 1) = (y * 0.5) + 0.5;
258 }
259}
260
261static void get_flips(const Eigen::MatrixXi &f,
262 const Eigen::MatrixXd &uv,
263 std::vector<int> &flip_idx)
264{
265 flip_idx.resize(0);
266 for (int i = 0; i < f.rows(); i++) {
267
268 Eigen::Vector2d v1_n = uv.row(f(i, 0));
269 Eigen::Vector2d v2_n = uv.row(f(i, 1));
270 Eigen::Vector2d v3_n = uv.row(f(i, 2));
271
272 Eigen::MatrixXd t2_homo(3, 3);
273 t2_homo.col(0) << v1_n(0), v1_n(1), 1;
274 t2_homo.col(1) << v2_n(0), v2_n(1), 1;
275 t2_homo.col(2) << v3_n(0), v3_n(1), 1;
276 double det = t2_homo.determinant();
277 assert(det == det);
278 if (det < 0) {
279 flip_idx.push_back(i);
280 }
281 }
282}
283
284int count_flips(const Eigen::MatrixXi &f, const Eigen::MatrixXd &uv)
285{
286
287 std::vector<int> flip_idx;
288 get_flips(f, uv, flip_idx);
289
290 return flip_idx.size();
291}
292
293} // namespace slim
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
local_group_size(16, 16) .push_constant(Type b
ccl_device_inline float3 cos(float3 v)
void map_vertices_to_convex_border(Eigen::MatrixXd &vertex_positions)
void tutte(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::VectorXd &el, const Eigen::VectorXi &bnd, const Eigen::MatrixXd &bnd_uv, Eigen::MatrixXd &uv)
static void get_flips(const Eigen::MatrixXi &f, const Eigen::MatrixXd &uv, std::vector< int > &flip_idx)
int count_flips(const Eigen::MatrixXi &f, const Eigen::MatrixXd &uv)
static double compute_angle(const Eigen::Vector3d &a, const Eigen::Vector3d &b)
static void find_vertex_to_its_angles_correspondence(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, Eigen::SparseMatrix< double > &vertex_to_face_indices)
void mvc(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::VectorXd &el, const Eigen::VectorXi &bnd, const Eigen::MatrixXd &bnd_uv, Eigen::MatrixXd &uv)
static void find_vertex_to_opposite_angles_correspondence(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, Eigen::SparseMatrix< double > &vertex_to_face_indices)
void convex_border_parameterization(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::VectorXd &el, const Eigen::VectorXi &bnd, const Eigen::MatrixXd &bnd_uv, Eigen::MatrixXd &uv, Method method)
void harmonic(const Eigen::MatrixXi &f, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::VectorXd &el, const Eigen::VectorXi &bnd, const Eigen::MatrixXd &bnd_uv, Eigen::MatrixXd &uv)
Method
@ HARMONIC
@ TUTTE
@ MVC