Lagrange
Loading...
Searching...
No Matches
sqrt_subdivision.h
1/*
2 * Copyright 2020 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 <lagrange/Mesh.h>
15#include <lagrange/MeshTrait.h>
16#include <lagrange/create_mesh.h>
17#include <lagrange/internal/constants.h>
18#include <lagrange/legacy/inline.h>
19
20// clang-format off
21#include <lagrange/utils/warnoff.h>
22#include <igl/adjacency_list.h>
23#include <igl/barycenter.h>
24#include <igl/triangle_triangle_adjacency.h>
25#include <lagrange/utils/warnon.h>
26// clang-format on
27
28namespace lagrange {
29namespace subdivision {
30LAGRANGE_LEGACY_INLINE
31namespace legacy {
32
45template <typename DerivedVI, typename DerivedFI, typename DerivedVO, typename DerivedFO>
46void sqrt_subdivision(
47 const Eigen::MatrixBase<DerivedVI>& VI,
48 const Eigen::MatrixBase<DerivedFI>& FI,
49 Eigen::PlainObjectBase<DerivedVO>& VO,
50 Eigen::PlainObjectBase<DerivedFO>& FO)
51{
52 using Scalar = typename DerivedVI::Scalar;
53 using Index = typename DerivedFI::Scalar;
54 using MatrixXs = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
55 using MatrixXi = Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
56 using RowVector3s = Eigen::Matrix<Scalar, 1, 3>;
57
58 // Step 1: new vertices at barycenter of every face
59 MatrixXs BC;
60 igl::barycenter(VI, FI, BC);
61
62 // Step 2: move old vertices to new positions
63 VO.resize(VI.rows() + FI.rows(), VI.cols());
64 VO.topRows(VI.rows()) = VI;
65 VO.bottomRows(BC.rows()) = BC;
66 std::vector<std::vector<Index>> VV;
67 igl::adjacency_list(FI, VV);
68 for (Index i = 0; i < (Index)VI.rows(); ++i) {
69 Scalar n = static_cast<Scalar>(VV[i].size());
70 Scalar an =
71 static_cast<Scalar>((4.0 - 2.0 * std::cos(2.0 * lagrange::internal::pi / n)) / 9.0);
72 RowVector3s sum_vi = RowVector3s::Zero();
73 for (auto j : VV[i]) {
74 sum_vi += VI.row(j);
75 }
76 VO.row(i) = (1 - an) * VI.row(i) + an / n * sum_vi;
77 }
78
79 // Step 3: compute a new set of faces, and flip edges as required
80 FO.resize(3 * FI.rows(), FI.cols());
81 for (Index f = 0; f < (Index)FI.rows(); ++f) {
82 FO.row(3 * f + 0) << VI.rows() + f, FI(f, 0), FI(f, 1);
83 FO.row(3 * f + 1) << VI.rows() + f, FI(f, 1), FI(f, 2);
84 FO.row(3 * f + 2) << VI.rows() + f, FI(f, 2), FI(f, 0);
85 }
86 MatrixXi TT, TTi;
87 igl::triangle_triangle_adjacency(FI, TT, TTi);
88 for (Index f = 0; f < (Index)FI.rows(); ++f) {
89 for (Index i = 0; i < (Index)FI.cols(); ++i) {
90 if (TT(f, i) != static_cast<Index>(-1) && TT(f, i) > f) {
91 Index g = TT(f, i);
92 Index j = TTi(f, i);
93 FO(3 * f + i, 2) = VI.rows() + g;
94 FO(3 * g + j, 2) = VI.rows() + f;
95 }
96 }
97 }
98}
99
115template <
116 typename MeshType,
117 std::enable_if_t<lagrange::MeshTraitHelper::is_mesh<MeshType>::value>* = nullptr>
118std::unique_ptr<MeshType> sqrt_subdivision(const MeshType& mesh)
119{
120 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
121
122 using VertexArray = typename MeshType::VertexArray;
123 using FacetArray = typename MeshType::FacetArray;
124
125 VertexArray V;
126 FacetArray F;
127 sqrt_subdivision(mesh.get_vertices(), mesh.get_facets(), V, F);
128 return lagrange::create_mesh(V, F);
129}
130
131} // namespace legacy
132} // namespace subdivision
133} // namespace lagrange
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
Subdivision surfaces.
Definition mesh_subdivision.h:32
Main namespace for Lagrange.
auto create_mesh(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets)
This function create a new mesh given the vertex and facet arrays by copying data into the Mesh objec...
Definition create_mesh.h:39