Lagrange
compute_uv_distortion.h
1/*
2 * Copyright 2017 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <cassert>
15#include <iostream>
16
17#include <lagrange/Mesh.h>
18#include <lagrange/MeshTrait.h>
19#include <lagrange/attributes/attribute_utils.h>
20#include <lagrange/common.h>
21#include <lagrange/legacy/inline.h>
22#include <lagrange/utils/safe_cast.h>
23
24namespace lagrange {
25LAGRANGE_LEGACY_INLINE
26namespace legacy {
27
38template <typename MeshType>
40{
41 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
42 if (mesh.get_vertex_per_facet() != 3) {
43 throw std::runtime_error("Input mesh must be a triangle mesh.");
44 }
45
46 using Scalar = typename MeshType::Scalar;
47 using Index = typename MeshType::Index;
48 using AttributeArray = typename MeshType::AttributeArray;
49
50 if (mesh.has_vertex_attribute("uv") && !mesh.has_corner_attribute("uv")) {
51 map_vertex_attribute_to_corner_attribute(mesh, "uv");
52 }
53 if (!mesh.has_corner_attribute("uv")) {
54 throw std::runtime_error("UV vertex attribute is missing.");
55 }
56
57 // const Index num_vertices = mesh->get_num_vertices();
58 const Index num_facets = mesh.get_num_facets();
59 const Index vertex_per_facet = mesh.get_vertex_per_facet();
60 const auto& vertices = mesh.get_vertices();
61 const auto& facets = mesh.get_facets();
62
63 const auto& uv = mesh.get_corner_attribute("uv");
64 la_runtime_assert(safe_cast<Index>(uv.rows()) == num_facets * vertex_per_facet);
65
66 const Scalar INVALID = std::numeric_limits<Scalar>::max();
67
68 AttributeArray distortion(num_facets, 1);
69 distortion.setConstant(INVALID);
70
71 for (Index i = 0; i < num_facets; i++) {
72 Eigen::Matrix<Index, 1, 3> f = facets.row(i);
73 Eigen::Matrix<Scalar, 1, 3> v0, v1, v2;
74 Eigen::Matrix<Scalar, 1, 2> V0, V1, V2;
75 v0 << vertices.row(f[0]);
76 v1 << vertices.row(f[1]);
77 v2 << vertices.row(f[2]);
78 V0 << uv.row(i * 3 + 0);
79 V1 << uv.row(i * 3 + 1);
80 V2 << uv.row(i * 3 + 2);
81
82 if (V0.minCoeff() < 0.0 || V0.maxCoeff() > 1.0) continue;
83 if (V1.minCoeff() < 0.0 || V1.maxCoeff() > 1.0) continue;
84 if (V2.minCoeff() < 0.0 || V2.maxCoeff() > 1.0) continue;
85
86 // AMIPS energy can be computed geometrically.
87 // Area ratio == det(F)
88 // Dirichlet energy == |F|^2
89 const Eigen::Matrix<Scalar, 1, 3> e0 = v1 - v2;
90 const Eigen::Matrix<Scalar, 1, 3> e1 = v2 - v0;
91 const Eigen::Matrix<Scalar, 1, 3> e2 = v0 - v1;
92 const Scalar l0 = e0.norm();
93 const Scalar l1 = e1.norm();
94 const Scalar l2 = e2.norm();
95 const Scalar s = 0.5f * (l0 + l1 + l2);
96 const Scalar a = sqrt(s * (s - l0) * (s - l1) * (s - l2));
97
98 const Eigen::Matrix<Scalar, 1, 2> E0 = V1 - V2;
99 const Eigen::Matrix<Scalar, 1, 2> E1 = V2 - V0;
100 const Eigen::Matrix<Scalar, 1, 2> E2 = V0 - V1;
101 const Scalar L0 = E0.norm();
102 const Scalar L1 = E1.norm();
103 const Scalar L2 = E2.norm();
104 const Scalar S = 0.5f * (L0 + L1 + L2);
105 const Scalar A = sqrt(S * (S - L0) * (S - L1) * (S - L2));
106
107 const Scalar area_ratio = A / a;
108
109 const Scalar cot_0 = e1.dot(-e2) / e1.cross(-e2).norm();
110 const Scalar cot_1 = e2.dot(-e0) / e2.cross(-e0).norm();
111 const Scalar cot_2 = e0.dot(-e1) / e0.cross(-e1).norm();
112
113 // Need to divid by the area since we want energy density.
114 const Scalar dirichlet = 0.5f * (cot_0 * L0 * L0 + cot_1 * L1 * L1 + cot_2 * L2 * L2) / a;
115
116 // Distortion measure is bounded from below by 2. It is achieved if
117 // and only if the mapping f is isometric.
118 distortion(i, 0) = dirichlet / area_ratio;
119 }
120
121 mesh.add_facet_attribute("distortion");
122 mesh.set_facet_attribute("distortion", distortion);
123}
124} // namespace legacy
125} // namespace lagrange
Definition: Mesh.h:48
AttributeId compute_uv_distortion(SurfaceMesh< Scalar, Index > &mesh, const UVDistortionOptions &options={})
Compute uv distortion using the selected distortion measure.
Definition: compute_uv_distortion.cpp:30
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
Main namespace for Lagrange.
Definition: AABBIGL.h:30