Added vector Dirichlet and curved Hessian functionality (#1560)
* Added vector Dirichlet and curved Hessian functionality, as well as tutorials. * Applied jdumas changes * added github actions for this branch * more jdumas changes * Changed int to appropriate scalar * moved around Int definition * forgot braces somewhere * forgot braces * Applied changes suggested by jdumas * forgot braces * remove custom github workflow
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "average_from_edges_onto_vertices.h"
|
||||
|
||||
template<typename DerivedF,typename DerivedE,typename DerivedoE,
|
||||
typename DeriveduE,typename DeriveduV>
|
||||
IGL_INLINE void
|
||||
igl::average_from_edges_onto_vertices(
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
const Eigen::MatrixBase<DeriveduE> &uE,
|
||||
Eigen::PlainObjectBase<DeriveduV> &uV)
|
||||
{
|
||||
using Scalar = typename DeriveduE::Scalar;
|
||||
using VecX = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
|
||||
using Int = typename DerivedF::Scalar;
|
||||
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
|
||||
const Int n = F.maxCoeff()+1;
|
||||
|
||||
VecX edgesPerVertex(n);
|
||||
edgesPerVertex.setZero();
|
||||
uV.resize(n,1);
|
||||
uV.setZero();
|
||||
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const Int e = E(i,j);
|
||||
const Int vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
|
||||
//Count vertex valence
|
||||
++edgesPerVertex(vi);
|
||||
++edgesPerVertex(vj);
|
||||
|
||||
//Average uE value onto vertices
|
||||
uV(vi) += uE(e);
|
||||
uV(vj) += uE(e);
|
||||
}
|
||||
}
|
||||
|
||||
//Divide by valence
|
||||
for(Int i=0; i<n; ++i) {
|
||||
const Scalar valence = edgesPerVertex(i);
|
||||
if(valence>0) {
|
||||
uV(i) /= valence;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::PartialReduxExpr<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::internal::member_norm<double>, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::average_from_edges_onto_vertices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
|
||||
#define IGL_AVERAGE_FROM_EDGES_ONTO_VERTICES_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Move a scalar field defined on edges to vertices by averaging
|
||||
//
|
||||
// Input:
|
||||
// F: triangle mesh connectivity
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
// uE: scalar field defined on edges, one per edge
|
||||
//
|
||||
// Output:
|
||||
// uV: scalar field defined on vertices
|
||||
template<typename DerivedF,typename DerivedE,typename DerivedoE,
|
||||
typename DeriveduE,typename DeriveduV>
|
||||
IGL_INLINE void average_from_edges_onto_vertices(
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
const Eigen::MatrixBase<DeriveduE> &uE,
|
||||
Eigen::PlainObjectBase<DeriveduV> &uV);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "average_from_edges_onto_vertices.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "cr_vector_curvature_correction.h"
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
#include "gaussian_curvature.h"
|
||||
|
||||
#include "squared_edge_lengths.h"
|
||||
#include "doublearea.h"
|
||||
#include "boundary_loop.h"
|
||||
#include "internal_angles.h"
|
||||
|
||||
#include "PI.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_curvature_correction(V, F, cE, coE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,Eigen::Dynamic>
|
||||
theta;
|
||||
internal_angles_using_squared_edge_lengths(l_sq, theta);
|
||||
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
// Compute the angle defect kappa, set it to 0 at the boundary
|
||||
const typename DerivedF::Scalar n = F.maxCoeff() + 1;
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar,Eigen::Dynamic,1> kappa(n);
|
||||
kappa.setZero();
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
kappa(F(i,j)) -= theta(i,j);
|
||||
}
|
||||
}
|
||||
kappa.array() += 2 * PI;
|
||||
std::vector<std::vector<typename DerivedF::Scalar> > b;
|
||||
boundary_loop(F, b);
|
||||
for(const auto& loop : b) {
|
||||
for(auto v : loop) {
|
||||
kappa(v) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, theta, kappa, E, oE, K);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename Derivedkappa, typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<Derivedkappa>& kappa,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
theta.rows()==F.rows() && theta.cols()==F.cols() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
assert(kappa.rows()==F.maxCoeff()+1 &&
|
||||
"Wrong dimension in theta or kappa");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
//Divide kappa by the actual angle sum to weigh consistently.
|
||||
Derivedtheta angleSum = Derivedtheta::Zero(kappa.rows(), 1);
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
angleSum(F(i,j)) += theta(i,j);
|
||||
}
|
||||
}
|
||||
const Eigen::Matrix<typename Derivedkappa::Scalar, Eigen::Dynamic, 1>
|
||||
scaledKappa = kappa.array() / angleSum.array();
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarK> > tripletList;
|
||||
tripletList.reserve(10*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const ScalarK eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
|
||||
eki=l_sq(f,(e+2)%3); //These are squared quantities.
|
||||
const ScalarK lens = sqrt(eij*eki);
|
||||
const ScalarK o = oE(f,e)*oE(f,(e+2)%3);
|
||||
const typename DerivedF::Scalar i=F(f,(e+1)%3), j=F(f,(e+2)%3), k=F(f,e);
|
||||
const ScalarK ki=scaledKappa(i)*theta(f,(e+1)%3),
|
||||
kj=scaledKappa(j)*theta(f,(e+2)%3), kk=scaledKappa(k)*theta(f,e);
|
||||
|
||||
const ScalarK costhetaidiv = (eij-ejk+eki)/(2.*lens);
|
||||
const ScalarK sinthetaidiv = sqrt( (1.-pow(eij-ejk+eki,2)/
|
||||
(4.*eij*eki)) );
|
||||
|
||||
const ScalarK Corrijij = (ki+kj+kk);
|
||||
tripletList.emplace_back(E(f,e), E(f,e), Corrijij);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, Corrijij);
|
||||
|
||||
const ScalarK Corrijki = -o*(ki-kj-kk)*costhetaidiv;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Corrijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Corrijki);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Corrijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Corrijki);
|
||||
|
||||
const ScalarK Corrijkiperp = o*(ki-kj-kk)*sinthetaidiv;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Corrijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Corrijkiperp);
|
||||
}
|
||||
}
|
||||
|
||||
K.resize(2*nE, 2*nE);
|
||||
K.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_curvature_correction_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_curvature_correction<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_CR_VECTOR_CURVATURE_CORRECTION_H
|
||||
#define IGL_CR_VECTOR_CURVATURE_CORRECTION_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the vector Crouzeix-Raviart curvature correction
|
||||
// term of Oded Stein, Alec Jacobson, Max Wardetzky, Eitan
|
||||
// Grinspun, 2020. "A Smoothness Energy without Boundary Distortion for
|
||||
// Curved Surfaces", but using the basis functions by Oded Stein,
|
||||
// Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// K: computed curvature correction matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// theta: the tip angles at each halfedge
|
||||
// kappa: the Gaussian curvature at each vertex
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// K: computed curvature correction matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename Derivedtheta,
|
||||
typename Derivedkappa, typename DerivedE, typename DerivedOE,
|
||||
typename ScalarK>
|
||||
IGL_INLINE void
|
||||
cr_vector_curvature_correction_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<Derivedtheta>& theta,
|
||||
const Eigen::MatrixBase<Derivedkappa>& kappa,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarK>& K);
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_curvature_correction.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "cr_vector_laplacian.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, E, oE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_laplacian(V, F, cE, coE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
assert(l_sq.rows()==F.rows() && l_sq.cols()==3 && "l_sq dimensions wrong");
|
||||
assert(dA.size()==F.rows() && "dA dimensions wrong");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarL> > tripletList;
|
||||
tripletList.reserve(10*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const ScalarL eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3),
|
||||
eki=l_sq(f,(e+2)%3); //These are squared quantities.
|
||||
const ScalarL lens = sqrt(eij*eki);
|
||||
const ScalarL o = oE(f,e)*oE(f,(e+2)%3);
|
||||
|
||||
tripletList.emplace_back(E(f,e), E(f,e), 2./dA(f) * eij);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, 2./dA(f) * eij);
|
||||
|
||||
const ScalarL Dijki = o * pow(eij-ejk+eki,2)/(2.*lens*dA(f));
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3), Dijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e), Dijki);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3)+nE, Dijki);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e)+nE, Dijki);
|
||||
|
||||
const ScalarL Dijkiperp = -o * (eij-ejk+eki)/lens;
|
||||
tripletList.emplace_back(E(f,e), E(f,(e+2)%3)+nE, Dijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3)+nE, E(f,e), Dijkiperp);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,(e+2)%3), -Dijkiperp);
|
||||
tripletList.emplace_back(E(f,(e+2)%3), E(f,e)+nE, -Dijkiperp);
|
||||
}
|
||||
}
|
||||
L.resize(2*nE, 2*nE);
|
||||
L.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_laplacian<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_laplacian_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_CR_VECTOR_LAPLACIAN_H
|
||||
#define IGL_CR_VECTOR_LAPLACIAN_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the CR vector Laplacian matrix.
|
||||
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// L: computed Laplacian matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// L: computed Laplacian matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarL>
|
||||
IGL_INLINE void
|
||||
cr_vector_laplacian_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarL>& L);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_laplacian.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "cr_vector_mass.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
cr_vector_mass_intrinsic(F, l_sq, E, oE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
cr_vector_mass(V, F, cE, coE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
igl::cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarM> > tripletList;
|
||||
tripletList.reserve(2*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const typename DerivedF::Scalar v1=F(f,(e+1)%3), v2=F(f,(e+2)%3);
|
||||
//Scaled
|
||||
const ScalarM entry = dA(f) / 6;
|
||||
tripletList.emplace_back(E(f,e), E(f,e), entry);
|
||||
tripletList.emplace_back(E(f,e)+nE, E(f,e)+nE, entry);
|
||||
}
|
||||
}
|
||||
M.resize(2*nE, 2*nE);
|
||||
M.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::cr_vector_mass<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::cr_vector_mass_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_CR_VECTOR_MASS
|
||||
#define IGL_CR_VECTOR_MASS
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the CR vector mass matrix, using an arrangement of all parallel
|
||||
// degrees of freedom first, and all perpendicular degrees of freedom next.
|
||||
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// M: computed mass matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// M: computed mass matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarM>
|
||||
IGL_INLINE void
|
||||
cr_vector_mass_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarM>& M);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "cr_vector_mass.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -97,4 +97,5 @@ void igl::crouzeix_raviart_cotmatrix(
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::crouzeix_raviart_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::crouzeix_raviart_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
|
||||
@@ -82,4 +82,5 @@ void igl::crouzeix_raviart_massmatrix(
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
template void igl::crouzeix_raviart_massmatrix<float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<float, 0, int>&);
|
||||
template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "curved_hessian_energy.h"
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
#include "cr_vector_laplacian.h"
|
||||
#include "cr_vector_mass.h"
|
||||
#include "cr_vector_curvature_correction.h"
|
||||
#include "scalar_to_cr_vector_gradient.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::MatrixXi E, oE;
|
||||
curved_hessian_energy(V, F, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
curved_hessian_energy_intrinsic(F, l_sq, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
curved_hessian_energy(V, F, cE, coE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
curved_hessian_energy_intrinsic(F, l_sq, dA, E, oE, Q);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
igl::curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q)
|
||||
{
|
||||
//Matrices that need to be combined
|
||||
Eigen::SparseMatrix<ScalarQ> M, D, L, K;
|
||||
cr_vector_mass_intrinsic(F, l_sq, dA, E, oE, M);
|
||||
scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, D);
|
||||
cr_vector_laplacian_intrinsic(F, l_sq, dA, E, oE, L);
|
||||
cr_vector_curvature_correction_intrinsic(F, l_sq, E, oE, K);
|
||||
|
||||
//Invert M
|
||||
std::vector<Eigen::Triplet<ScalarQ> > tripletListMi;
|
||||
for(Eigen::Index k=0; k<M.outerSize(); ++k) {
|
||||
for(typename Eigen::SparseMatrix<ScalarQ>::InnerIterator it(M,k);
|
||||
it; ++it) {
|
||||
if(it.value() > 0) {
|
||||
tripletListMi.emplace_back(it.row(), it.col(), 1./it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
Eigen::SparseMatrix<ScalarQ> Mi(M.rows(), M.cols());
|
||||
Mi.setFromTriplets(tripletListMi.begin(), tripletListMi.end());
|
||||
|
||||
//Hessian energy matrix
|
||||
Q = D.transpose()*Mi*(L + K)*Mi*D;
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::curved_hessian_energy<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_CURVED_HESSIAN_ENERGY_H
|
||||
#define IGL_CURVED_HESSIAN_ENERGY_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the curved Hessian energy using the Crouzeix-Raviart
|
||||
// discretization.
|
||||
// See Oded Stein, Alec Jacobson, Max Wardetzky, Eitan Grinspun, 2020.
|
||||
// "A Smoothness Energy without Boundary Distortion for Curved Surfaces"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
// Version that exposes the edge orientation used.
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// Q: computed Hessian energy matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarQ>
|
||||
IGL_INLINE void
|
||||
curved_hessian_energy_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarQ>& Q);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "curved_hessian_energy.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "edge_midpoints.h"
|
||||
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedmps>
|
||||
IGL_INLINE void
|
||||
igl::edge_midpoints(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedmps> &mps)
|
||||
{
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
|
||||
|
||||
using ScalarE = typename DerivedE::Scalar;
|
||||
using ScalarF = typename DerivedF::Scalar;
|
||||
|
||||
const ScalarE m = E.maxCoeff()+1;
|
||||
|
||||
mps.resize(m, V.cols());
|
||||
for(Eigen::Index i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const ScalarE e = E(i,j);
|
||||
const ScalarF vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
|
||||
mps.row(e) = 0.5*(V.row(vi) + V.row(vj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::edge_midpoints<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_EDGE_MIDPOINTS_H
|
||||
#define IGL_EDGE_MIDPOINTS_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Computes the midpoints of edges in a triangle mesh.
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
//
|
||||
// Output:
|
||||
// mps: edge midpoints, one per edge in E
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedmps>
|
||||
IGL_INLINE void edge_midpoints(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedmps> &mps);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "edge_midpoints.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "edge_vectors.h"
|
||||
|
||||
#include <Eigen/Geometry>
|
||||
#include "per_face_normals.h"
|
||||
|
||||
#include "PI.h"
|
||||
|
||||
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedvec>
|
||||
IGL_INLINE void
|
||||
igl::edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedvec> &vec)
|
||||
{
|
||||
Eigen::Matrix<typename Derivedvec::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dummy;
|
||||
edge_vectors<false>(V, F, E, oE, vec, dummy);
|
||||
}
|
||||
|
||||
|
||||
template<bool computePerpendicular,
|
||||
typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename DerivedvecParallel,
|
||||
typename DerivedvecPerpendicular>
|
||||
IGL_INLINE void
|
||||
igl::edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
|
||||
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular)
|
||||
{
|
||||
using Scalar = typename DerivedvecParallel::Scalar;
|
||||
using MatX = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
||||
|
||||
assert(E.rows()==F.rows() && "E does not match dimensions of F.");
|
||||
assert(oE.rows()==F.rows() && "oE does not match dimensions of F.");
|
||||
assert(E.cols()==3 && F.cols()==3 && oE.cols()==3 &&
|
||||
"This method is for triangle meshes.");
|
||||
assert(F.maxCoeff()<V.rows() && "V does not seem to belong to F.");
|
||||
|
||||
const typename DerivedE::Scalar m = E.maxCoeff()+1;
|
||||
|
||||
//Compute edge-based normal
|
||||
MatX N, edgeN(m, 3);
|
||||
edgeN.setZero();
|
||||
per_face_normals(V, F, N);
|
||||
for(Eigen::Index i=0; i<E.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
edgeN.row(E(i,j)) += N.row(i);
|
||||
}
|
||||
}
|
||||
edgeN.rowwise().normalize();
|
||||
|
||||
//Compute edge vectors
|
||||
vecParallel.resize(m, 3);
|
||||
if(computePerpendicular) { //This should ideally be an if constexpr
|
||||
vecPerpendicular.resize(m, 3);
|
||||
}
|
||||
for(Eigen::Index i=0; i<E.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)<0) {
|
||||
continue;
|
||||
}
|
||||
const typename DerivedE::Scalar e=E(i,j);
|
||||
const typename DerivedF::Scalar vi=F(i,(j+1)%3), vj=F(i,(j+2)%3);
|
||||
vecParallel.row(e) = (V.row(vj)-V.row(vi)).normalized();
|
||||
if(computePerpendicular) { //This should ideally be an if constexpr
|
||||
vecPerpendicular.row(e) =
|
||||
Eigen::AngleAxis<Scalar>(0.5*PI, edgeN.row(e)) *
|
||||
vecParallel.row(e).transpose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::edge_vectors<true, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_EDGE_VECTORS_H
|
||||
#define IGL_EDGE_VECTORS_H
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
namespace igl
|
||||
{
|
||||
// Computes the normalized edge vectors for edges in a triangle mesh
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
//
|
||||
// Output:
|
||||
// vec: normalized edge vectors for each unique edge in E, according to order
|
||||
// of E.
|
||||
template<typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename Derivedvec>
|
||||
IGL_INLINE void edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<Derivedvec> &vec);
|
||||
|
||||
|
||||
// Computes the normalized edge vectors for edges in a triangle mesh
|
||||
//
|
||||
// Input:
|
||||
// V, F: triangle mesh
|
||||
// E, oE: mapping from halfedges to edges and orientation as generated by
|
||||
// orient_halfedges
|
||||
// template parameter computePerpendicular: whether to compute
|
||||
// vecPerpendicular or not.
|
||||
//
|
||||
// Output:
|
||||
// vecParallel: normalized edge vectors for each unique edge in E, according
|
||||
// to order of E.
|
||||
// vecPerpendicular: tangent unit perpendicular vector to each edge, according
|
||||
// to orientation in oE, corresponds to each vector in
|
||||
// vecParallel rotated by pi/2 around an edge-based normal.
|
||||
//
|
||||
template<bool computePerpendicular=true,
|
||||
typename DerivedV,typename DerivedF,typename DerivedE,
|
||||
typename DerivedoE, typename DerivedvecParallel,
|
||||
typename DerivedvecPerpendicular>
|
||||
IGL_INLINE void edge_vectors(
|
||||
const Eigen::MatrixBase<DerivedV> &V,
|
||||
const Eigen::MatrixBase<DerivedF> &F,
|
||||
const Eigen::MatrixBase<DerivedE> &E,
|
||||
const Eigen::MatrixBase<DerivedoE> &oE,
|
||||
Eigen::PlainObjectBase<DerivedvecParallel> &vecParallel,
|
||||
Eigen::PlainObjectBase<DerivedvecPerpendicular> &vecPerpendicular);
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "edge_vectors.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -101,4 +101,5 @@ template void igl::internal_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eig
|
||||
template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
|
||||
template void igl::internal_angles_using_squared_edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template void igl::internal_angles_using_squared_edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
||||
@@ -600,4 +600,5 @@ template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, 1
|
||||
template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::min_quad_with_fixed<double, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
|
||||
template bool igl::min_quad_with_fixed<double, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "oriented_facets.h"
|
||||
#include "unique_simplices.h"
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedE, typename DerivedOE>
|
||||
IGL_INLINE void
|
||||
igl::orient_halfedges(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE)
|
||||
{
|
||||
assert(F.cols()==3 && "This only works for triangle meshes.");
|
||||
|
||||
using Int = typename DerivedF::Scalar;
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
|
||||
DerivedE allE, EE;
|
||||
oriented_facets(F, allE);
|
||||
Eigen::Matrix<Int, Eigen::Dynamic, 1> IA, IC;
|
||||
unique_simplices(allE, EE, IA, IC);
|
||||
|
||||
E.resize(m, 3);
|
||||
oE.resize(m, 3);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const Int ind = f + m*e;
|
||||
E(f,e) = IC(ind);
|
||||
assert((EE(E(f,e),0)==allE(ind,0) || EE(E(f,e),0)==allE(ind,1)) &&
|
||||
"Something is wrong in the edge matrix.");
|
||||
oE(f,e) = EE(E(f,e),0)==allE(ind,0) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::orient_halfedges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_ORIENT_HALFEDGES_H
|
||||
#define IGL_ORIENT_HALFEDGES_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Orients halfedges for a triangle mesh, assigning them to a unique edge.
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
//
|
||||
// Outputs:
|
||||
// E: a mapping from each halfedge to each edge
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge. Every edge appears positively oriented exactly once.
|
||||
|
||||
template <typename DerivedF, typename DerivedE, typename DerivedOE>
|
||||
IGL_INLINE void
|
||||
orient_halfedges(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "orient_halfedges.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "scalar_to_cr_vector_gradient.h"
|
||||
|
||||
#include "orient_halfedges.h"
|
||||
|
||||
#include "doublearea.h"
|
||||
#include "squared_edge_lengths.h"
|
||||
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
igl::scalar_to_cr_vector_gradient(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
l_sq;
|
||||
squared_edge_lengths(V, F, l_sq);
|
||||
scalar_to_cr_vector_gradient_intrinsic(F, l_sq, E, oE, G);
|
||||
}
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
igl::scalar_to_cr_vector_gradient(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G)
|
||||
{
|
||||
if(E.rows()!=F.rows() || E.cols()!=F.cols() || oE.rows()!=F.rows() ||
|
||||
oE.cols()!=F.cols()) {
|
||||
orient_halfedges(F, E, oE);
|
||||
}
|
||||
|
||||
const Eigen::PlainObjectBase<DerivedE>& cE = E;
|
||||
const Eigen::PlainObjectBase<DerivedOE>& coE = oE;
|
||||
|
||||
scalar_to_cr_vector_gradient(V, F, cE, coE, G);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
igl::scalar_to_cr_vector_gradient_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G)
|
||||
{
|
||||
Eigen::Matrix<typename DerivedL_sq::Scalar, Eigen::Dynamic, Eigen::Dynamic>
|
||||
dA;
|
||||
DerivedL_sq l_sqrt = l_sq.array().sqrt().matrix();
|
||||
doublearea(l_sqrt, dA);
|
||||
scalar_to_cr_vector_gradient_intrinsic(F, l_sq, dA, E, oE, G);
|
||||
}
|
||||
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
igl::scalar_to_cr_vector_gradient_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G)
|
||||
{
|
||||
assert(F.cols()==3 && "Faces have three vertices");
|
||||
assert(E.rows()==F.rows() && E.cols()==F.cols() && oE.rows()==F.rows() &&
|
||||
oE.cols()==F.cols() && "Wrong dimension in edge vectors");
|
||||
|
||||
const Eigen::Index m = F.rows();
|
||||
const typename DerivedF::Scalar n = F.maxCoeff() + 1;
|
||||
const typename DerivedE::Scalar nE = E.maxCoeff() + 1;
|
||||
|
||||
std::vector<Eigen::Triplet<ScalarG> > tripletList;
|
||||
tripletList.reserve(5*3*m);
|
||||
for(Eigen::Index f=0; f<m; ++f) {
|
||||
for(int e=0; e<3; ++e) {
|
||||
const typename DerivedF::Scalar i=F(f,(e+1)%3), j=F(f,(e+2)%3), k=F(f,e);
|
||||
const ScalarG o=oE(f,e),
|
||||
eij=l_sq(f,e), ejk=l_sq(f,(e+1)%3), eki=l_sq(f,(e+2)%3); //These are squared quantities.
|
||||
const ScalarG s_eij = sqrt(eij);
|
||||
|
||||
tripletList.emplace_back(E(f,e), i, -o*dA(f)/(6.*s_eij));
|
||||
tripletList.emplace_back(E(f,e)+nE, i, -o*(eij+ejk-eki)/(12.*s_eij));
|
||||
tripletList.emplace_back(E(f,e), j, o*dA(f)/(6.*s_eij));
|
||||
tripletList.emplace_back(E(f,e)+nE, j, -o*(eij-ejk+eki)/(12.*s_eij));
|
||||
tripletList.emplace_back(E(f,e)+nE, k, o*s_eij/6.);
|
||||
}
|
||||
}
|
||||
G.resize(2*nE, n);
|
||||
G.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
template void igl::scalar_to_cr_vector_gradient_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2020 Oded Stein <oded.stein@columbia.edu>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_SCALAR_TO_CR_VECTOT_GRADIENT_H
|
||||
#define IGL_SCALAR_TO_CR_VECTOT_GRADIENT_H
|
||||
|
||||
#include "igl_inline.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Computes the gradient matrix with hat functions on the right, and
|
||||
// vector CR functions on the left.
|
||||
// See Oded Stein, Max Wardetzky, Alec Jacobson, Eitan Grinspun, 2020.
|
||||
// "A Simple Discretization of the Vector Dirichlet Energy"
|
||||
//
|
||||
// Inputs:
|
||||
// V, F: input mesh
|
||||
// E: a mapping from each halfedge to each edge, as computed with
|
||||
// orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge, as computed with orient_halfedges.
|
||||
// will be computed if not provided.
|
||||
//
|
||||
// Outputs:
|
||||
// G: computed gradient matrix
|
||||
// E, oE: these are computed if they are not present, as described above
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
scalar_to_cr_vector_gradient(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G);
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
scalar_to_cr_vector_gradient(
|
||||
const Eigen::MatrixBase<DerivedV>& V,
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
Eigen::PlainObjectBase<DerivedE>& E,
|
||||
Eigen::PlainObjectBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G);
|
||||
|
||||
|
||||
// Version that uses intrinsic quantities as input
|
||||
//
|
||||
// Inputs:
|
||||
// F: input mesh connectivity
|
||||
// l_sq: squared edge lengths of each halfedge
|
||||
// dA: double area of each face
|
||||
// E: a mapping from each halfedge to each edge.
|
||||
// oE: the orientation of each halfedge compared to the orientation of the
|
||||
// actual edge.
|
||||
//
|
||||
// Outputs:
|
||||
// G: computed gradient matrix
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DerivedE,
|
||||
typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
scalar_to_cr_vector_gradient_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G);
|
||||
|
||||
template <typename DerivedF, typename DerivedL_sq, typename DeriveddA,
|
||||
typename DerivedE, typename DerivedOE, typename ScalarG>
|
||||
IGL_INLINE void
|
||||
scalar_to_cr_vector_gradient_intrinsic(
|
||||
const Eigen::MatrixBase<DerivedF>& F,
|
||||
const Eigen::MatrixBase<DerivedL_sq>& l_sq,
|
||||
const Eigen::MatrixBase<DeriveddA>& dA,
|
||||
const Eigen::MatrixBase<DerivedE>& E,
|
||||
const Eigen::MatrixBase<DerivedOE>& oE,
|
||||
Eigen::SparseMatrix<ScalarG>& G);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "scalar_to_cr_vector_gradient.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,102 @@
|
||||
#include <test_common.h>
|
||||
#include <igl/orient_halfedges.h>
|
||||
#include <igl/is_border_vertex.h>
|
||||
#include <igl/edges.h>
|
||||
#include <igl/remove_unreferenced.h>
|
||||
#include <igl/triangle_triangle_adjacency.h>
|
||||
#include <igl/EPS.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
TEST_CASE("orient_halfedges: sanity checks", "[igl]")
|
||||
{
|
||||
const auto meshes = test_common::manifold_meshes();
|
||||
|
||||
for(const auto& mesh : meshes) {
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
igl::read_triangle_mesh(test_common::data_path(mesh), V, F);
|
||||
Eigen::MatrixXi I;
|
||||
igl::remove_unreferenced(Eigen::MatrixXd(V), Eigen::MatrixXi(F), V, F,
|
||||
I);
|
||||
|
||||
Eigen::MatrixXi TT, TTi;
|
||||
igl::triangle_triangle_adjacency(F, TT, TTi);
|
||||
// Fix mis-match convention
|
||||
{
|
||||
Eigen::PermutationMatrix<3,3> perm(3);
|
||||
perm.indices() = Eigen::Vector3i(1,2,0);
|
||||
TT = (TT*perm).eval();
|
||||
TTi = (TTi*perm).eval();
|
||||
for(int i=0;i<TTi.rows();i++) {
|
||||
for(int j=0;j<TTi.cols();j++) {
|
||||
TTi(i,j)=TTi(i,j)==-1?-1:(TTi(i,j)+3-1)%3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::MatrixXi E, oE;
|
||||
igl::orient_halfedges(F, E, oE);
|
||||
|
||||
const int m = E.maxCoeff()+1;
|
||||
std::vector<bool> b(m);
|
||||
for(int i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
b[E(i,j)] = TT(i,j)<0;
|
||||
}
|
||||
}
|
||||
int nb = 0;
|
||||
for(int i=0; i<b.size(); ++i) {
|
||||
if(b[i]) {
|
||||
++nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Perform a variety of sanity checks.
|
||||
|
||||
//Correct number of edges
|
||||
Eigen::MatrixXi sanityEdges;
|
||||
igl::edges(F, sanityEdges);
|
||||
REQUIRE(m == sanityEdges.rows());
|
||||
|
||||
//All border halfedges edges have orientation 1 only, all others
|
||||
// orientations 1 and -1, so oE must sum to the number of border
|
||||
// edges.
|
||||
REQUIRE(nb == oE.array().sum());
|
||||
|
||||
//Every border halfedge has orientation 1. Every other edge appeats
|
||||
// with orientation 1 and -1.
|
||||
std::vector<int> appeared1(m,0), appearedm1(m,0);
|
||||
for(int i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(oE(i,j)==1) {
|
||||
++appeared1[E(i,j)];
|
||||
} else if(oE(i,j)==-1) {
|
||||
++appearedm1[E(i,j)];
|
||||
} else {
|
||||
REQUIRE(false); //Only 1 and -1 should occur.
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i=0; i<m; ++i) {
|
||||
REQUIRE(appeared1[i]==1);
|
||||
if(b[i]) {
|
||||
REQUIRE(appearedm1[i]==0);
|
||||
} else {
|
||||
REQUIRE(appearedm1[i]==1);
|
||||
}
|
||||
}
|
||||
|
||||
//Two opposite halfedges always map to the same edge
|
||||
for(int i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
if(TT(i,j)>=0) {
|
||||
REQUIRE(E(i,j) == E(TT(i,j),TTi(i,j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <igl/read_triangle_mesh.h>
|
||||
#include <igl/hessian_energy.h>
|
||||
#include <igl/curved_hessian_energy.h>
|
||||
#include <igl/massmatrix.h>
|
||||
#include <igl/cotmatrix.h>
|
||||
#include <igl/isolines_map.h>
|
||||
@@ -7,6 +8,7 @@
|
||||
#include <igl/vertex_components.h>
|
||||
#include <igl/remove_unreferenced.h>
|
||||
#include <igl/opengl/glfw/Viewer.h>
|
||||
#include <igl/heat_geodesics.h>
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/SparseCholesky>
|
||||
@@ -22,86 +24,160 @@
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
typedef Eigen::SparseMatrix<double> SparseMat;
|
||||
|
||||
//Read our mesh
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
if(!igl::read_triangle_mesh(
|
||||
argc>1?argv[1]: TUTORIAL_SHARED_PATH "/beetle.off",V,F)) {
|
||||
std::cout << "Failed to load mesh." << std::endl;
|
||||
typedef Eigen::SparseMatrix<double> SparseMat;
|
||||
srand(57);
|
||||
|
||||
//Read our mesh
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
if(!igl::read_triangle_mesh(
|
||||
argc>1?argv[1]: TUTORIAL_SHARED_PATH "/beetle.off",V,F)) {
|
||||
std::cout << "Failed to load mesh." << std::endl;
|
||||
}
|
||||
|
||||
//Constructing an exact function to smooth
|
||||
igl::HeatGeodesicsData<double> hgData;
|
||||
igl::heat_geodesics_precompute(V, F, hgData);
|
||||
Eigen::VectorXd heatDist;
|
||||
Eigen::VectorXi gamma(1); gamma << 1947; //1631;
|
||||
igl::heat_geodesics_solve(hgData, gamma, heatDist);
|
||||
Eigen::VectorXd zexact =
|
||||
0.1*(heatDist.array() + (-heatDist.maxCoeff())).pow(2)
|
||||
+ 3*V.block(0,1,V.rows(),1).array().cos();
|
||||
|
||||
//Make the exact function noisy
|
||||
const double s = 0.1*(zexact.maxCoeff() - zexact.minCoeff());
|
||||
Eigen::VectorXd znoisy = zexact + s*Eigen::VectorXd::Random(zexact.size());
|
||||
|
||||
//Constructing the squared Laplacian and squared Hessian energy
|
||||
SparseMat L, M;
|
||||
igl::cotmatrix(V, F, L);
|
||||
igl::massmatrix(V, F, igl::MASSMATRIX_TYPE_BARYCENTRIC, M);
|
||||
Eigen::SimplicialLDLT<SparseMat> solver(M);
|
||||
SparseMat MinvL = solver.solve(L);
|
||||
SparseMat QL = L.transpose()*MinvL;
|
||||
SparseMat QH;
|
||||
igl::hessian_energy(V, F, QH);
|
||||
SparseMat QcH;
|
||||
igl::curved_hessian_energy(V, F, QcH);
|
||||
|
||||
//Solve to find Laplacian-smoothed Hessian-smoothed, and
|
||||
// curved-Hessian-smoothed solutions
|
||||
const double al = 3e-7;
|
||||
Eigen::SimplicialLDLT<SparseMat> lapSolver(al*QL + (1.-al)*M);
|
||||
Eigen::VectorXd zl = lapSolver.solve(al*M*znoisy);
|
||||
const double ah = 2e-7;
|
||||
Eigen::SimplicialLDLT<SparseMat> hessSolver(ah*QH + (1.-ah)*M);
|
||||
Eigen::VectorXd zh = hessSolver.solve(ah*M*znoisy);
|
||||
const double ach = 3e-7;
|
||||
Eigen::SimplicialLDLT<SparseMat> curvedHessSolver(al*QcH + (1.-ach)*M);
|
||||
Eigen::VectorXd zch = curvedHessSolver.solve(ach*M*znoisy);
|
||||
|
||||
//Viewer that shows all functions: zexact, znoisy, zl, zh
|
||||
igl::opengl::glfw::Viewer viewer;
|
||||
viewer.data().set_mesh(V,F);
|
||||
viewer.data().show_lines = false;
|
||||
viewer.callback_key_down =
|
||||
[&](igl::opengl::glfw::Viewer & viewer, unsigned char key, int mod)->bool
|
||||
{
|
||||
//Graduate result to show isolines, then compute color matrix
|
||||
const Eigen::VectorXd* z;
|
||||
switch(key) {
|
||||
case '1':
|
||||
z = &zexact;
|
||||
break;
|
||||
case '2':
|
||||
z = &znoisy;
|
||||
break;
|
||||
case '3':
|
||||
z = &zl;
|
||||
break;
|
||||
case '4':
|
||||
z = &zh;
|
||||
break;
|
||||
case '5':
|
||||
z = &zch;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
//Constructing an exact function to smooth
|
||||
Eigen::VectorXd zexact = V.block(0,2,V.rows(),1).array()
|
||||
+ 0.5*V.block(0,1,V.rows(),1).array()
|
||||
+ V.block(0,1,V.rows(),1).array().pow(2)
|
||||
+ V.block(0,2,V.rows(),1).array().pow(3);
|
||||
|
||||
//Make the exact function noisy
|
||||
srand(5);
|
||||
const double s = 0.2*(zexact.maxCoeff() - zexact.minCoeff());
|
||||
Eigen::VectorXd znoisy = zexact + s*Eigen::VectorXd::Random(zexact.size());
|
||||
|
||||
//Constructing the squared Laplacian and squared Hessian energy
|
||||
SparseMat L, M;
|
||||
igl::cotmatrix(V, F, L);
|
||||
igl::massmatrix(V, F, igl::MASSMATRIX_TYPE_BARYCENTRIC, M);
|
||||
Eigen::SimplicialLDLT<SparseMat> solver(M);
|
||||
SparseMat MinvL = solver.solve(L);
|
||||
SparseMat QL = L.transpose()*MinvL;
|
||||
SparseMat QH;
|
||||
igl::hessian_energy(V, F, QH);
|
||||
|
||||
//Solve to find Laplacian-smoothed and Hessian-smoothed solutions
|
||||
const double al = 8e-4;
|
||||
Eigen::SimplicialLDLT<SparseMat> lapSolver(al*QL + (1.-al)*M);
|
||||
Eigen::VectorXd zl = lapSolver.solve(al*M*znoisy);
|
||||
const double ah = 5e-6;
|
||||
Eigen::SimplicialLDLT<SparseMat> hessSolver(ah*QH + (1.-ah)*M);
|
||||
Eigen::VectorXd zh = hessSolver.solve(ah*M*znoisy);
|
||||
|
||||
//Viewer that shows all functions: zexact, znoisy, zl, zh
|
||||
igl::opengl::glfw::Viewer viewer;
|
||||
viewer.data().set_mesh(V,F);
|
||||
viewer.data().show_lines = false;
|
||||
viewer.callback_key_down =
|
||||
[&](igl::opengl::glfw::Viewer & viewer, unsigned char key, int mod)->bool
|
||||
{
|
||||
//Graduate result to show isolines, then compute color matrix
|
||||
const Eigen::VectorXd* z;
|
||||
switch(key) {
|
||||
case '1':
|
||||
z = &zexact;
|
||||
break;
|
||||
case '2':
|
||||
z = &znoisy;
|
||||
break;
|
||||
case '3':
|
||||
z = &zl;
|
||||
break;
|
||||
case '4':
|
||||
z = &zh;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
viewer.data().set_data(*z);
|
||||
return true;
|
||||
};
|
||||
std::cout << R"(Usage:
|
||||
viewer.data().set_data(*z);
|
||||
return true;
|
||||
};
|
||||
std::cout << R"(Smoothing a noisy function.
|
||||
Usage:
|
||||
1 Show original function
|
||||
2 Show noisy function
|
||||
3 Biharmonic smoothing (zero Neumann boundary)
|
||||
4 Biharmonic smoothing (natural Hessian boundary)
|
||||
4 Biharmonic smoothing (natural planar Hessian boundary)
|
||||
5 Biharmonic smoothing (natural curved Hessian boundary)
|
||||
|
||||
)";
|
||||
Eigen::MatrixXd CM;
|
||||
igl::parula(Eigen::VectorXd::LinSpaced(21,0,1).eval(),false,CM);
|
||||
igl::isolines_map(Eigen::MatrixXd(CM),CM);
|
||||
viewer.data().set_colormap(CM);
|
||||
viewer.data().set_data(znoisy);
|
||||
viewer.launch();
|
||||
Eigen::MatrixXd CM;
|
||||
igl::parula(Eigen::VectorXd::LinSpaced(21,0,1).eval(),false,CM);
|
||||
igl::isolines_map(Eigen::MatrixXd(CM),CM);
|
||||
viewer.data().set_colormap(CM);
|
||||
viewer.data().set_data(znoisy);
|
||||
viewer.launch();
|
||||
|
||||
|
||||
//Constructing a step function to smooth
|
||||
Eigen::VectorXd zstep = Eigen::VectorXd::Zero(V.rows());
|
||||
for(int i=0; i<V.rows(); ++i) {
|
||||
zstep(i) = V(i,2)<-0.25 ? 1. : (V(i,2)>0.31 ? 2. : 0);
|
||||
}
|
||||
|
||||
//Smooth that function
|
||||
const double sl = 2e-5;
|
||||
Eigen::SimplicialLDLT<SparseMat> stepLapSolver(sl*QL + (1.-sl)*M);
|
||||
Eigen::VectorXd stepzl = stepLapSolver.solve(al*M*zstep);
|
||||
const double sh = 6e-6;
|
||||
Eigen::SimplicialLDLT<SparseMat> stepHessSolver(sh*QH + (1.-sh)*M);
|
||||
Eigen::VectorXd stepzh = stepHessSolver.solve(ah*M*zstep);
|
||||
const double sch = 2e-5;
|
||||
Eigen::SimplicialLDLT<SparseMat> stepCurvedHessSolver(sl*QcH + (1.-sch)*M);
|
||||
Eigen::VectorXd stepzch = stepCurvedHessSolver.solve(ach*M*zstep);
|
||||
|
||||
//Display functions
|
||||
igl::opengl::glfw::Viewer viewer2;
|
||||
viewer2.data().set_mesh(V,F);
|
||||
viewer2.data().show_lines = false;
|
||||
viewer2.callback_key_down =
|
||||
[&](igl::opengl::glfw::Viewer & viewer, unsigned char key, int mod)->bool
|
||||
{
|
||||
//Graduate result to show isolines, then compute color matrix
|
||||
const Eigen::VectorXd* z;
|
||||
switch(key) {
|
||||
case '1':
|
||||
z = &zstep;
|
||||
break;
|
||||
case '2':
|
||||
z = &stepzl;
|
||||
break;
|
||||
case '3':
|
||||
z = &stepzh;
|
||||
break;
|
||||
case '4':
|
||||
z = &stepzch;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
viewer.data().set_data(*z);
|
||||
return true;
|
||||
};
|
||||
std::cout << R"(Smoothing a step function.
|
||||
Usage:
|
||||
1 Show step function
|
||||
2 Biharmonic smoothing (zero Neumann boundary)
|
||||
3 Biharmonic smoothing (natural planar Hessian boundary)
|
||||
4 Biharmonic smoothing (natural curved Hessian boundary)
|
||||
|
||||
return 0;
|
||||
)";
|
||||
|
||||
viewer2.data().set_colormap(CM);
|
||||
viewer2.data().set_data(zstep);
|
||||
viewer2.launch();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
add_executable(${PROJECT_NAME}_bin main.cpp)
|
||||
target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)
|
||||
Executable
+147
@@ -0,0 +1,147 @@
|
||||
#include <igl/read_triangle_mesh.h>
|
||||
#include <igl/parula.h>
|
||||
#include <igl/remove_unreferenced.h>
|
||||
#include <igl/opengl/glfw/Viewer.h>
|
||||
#include <igl/per_face_normals.h>
|
||||
#include <igl/orient_halfedges.h>
|
||||
#include <igl/cr_vector_laplacian.h>
|
||||
#include <igl/cr_vector_mass.h>
|
||||
#include <igl/edge_midpoints.h>
|
||||
#include <igl/edge_vectors.h>
|
||||
#include <igl/average_from_edges_onto_vertices.h>
|
||||
#include <igl/PI.h>
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/SparseCholesky>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tutorial_shared_path.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
typedef Eigen::SparseMatrix<double> SparseMat;
|
||||
|
||||
//Constants used for smoothing
|
||||
const double howMuchToSmoothBy = 1e-1;
|
||||
const int howManySmoothingInterations = 50;
|
||||
|
||||
//Read our mesh
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
if(!igl::read_triangle_mesh
|
||||
(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/elephant.obj",V,F)) {
|
||||
std::cout << "Failed to load mesh." << std::endl;
|
||||
}
|
||||
|
||||
//Orient edges for plotting
|
||||
Eigen::MatrixXi E, oE;
|
||||
igl::orient_halfedges(F, E, oE);
|
||||
|
||||
//Compute edge midpoints & edge vectors
|
||||
Eigen::MatrixXd edgeMps, parVec, perpVec;
|
||||
igl::edge_midpoints(V, F, E, oE, edgeMps);
|
||||
igl::edge_vectors(V, F, E, oE, parVec, perpVec);
|
||||
|
||||
//Constructing a function to add noise to
|
||||
const auto zraw_function = [] (const Eigen::Vector3d& x) {
|
||||
return Eigen::Vector3d(0.2*x(1) + cos(2*x(1)+0.2),
|
||||
0.5*x(0) + 0.15,
|
||||
0.3*cos(0.2+igl::PI*x(2)));
|
||||
};
|
||||
|
||||
Eigen::VectorXd zraw(2*edgeMps.rows());
|
||||
for(int i=0; i<edgeMps.rows(); ++i) {
|
||||
const Eigen::Vector3d f = zraw_function(edgeMps.row(i));
|
||||
zraw(i) = f.dot(parVec.row(i));
|
||||
zraw(i+edgeMps.rows()) = f.dot(perpVec.row(i));
|
||||
}
|
||||
|
||||
//Add noise
|
||||
srand(71);
|
||||
const double l = 15;
|
||||
Eigen::VectorXd znoisy = zraw + l*Eigen::VectorXd::Random(zraw.size());
|
||||
|
||||
//Denoise function using the vector Dirichlet energy
|
||||
Eigen::VectorXd zsmoothed = znoisy;
|
||||
for(int i=0; i<howManySmoothingInterations; ++i) {
|
||||
//Compute Laplacian and mass matrix
|
||||
SparseMat L, M;
|
||||
igl::cr_vector_mass(V, F, E, oE, M);
|
||||
igl::cr_vector_laplacian(V, F, E, oE, L);
|
||||
|
||||
//Implicit step
|
||||
Eigen::SimplicialLDLT<SparseMat> rhsSolver(M + howMuchToSmoothBy*L);
|
||||
zsmoothed = rhsSolver.solve(M*zsmoothed);
|
||||
}
|
||||
|
||||
//Convert vector fields for plotting
|
||||
const auto cr_result_to_vecs_and_colors = [&]
|
||||
(const Eigen::VectorXd& z, Eigen::MatrixXd& vecs, Eigen::MatrixXd& colors) {
|
||||
vecs.resize(edgeMps.rows(), 3);
|
||||
for(int i=0; i<edgeMps.rows(); ++i) {
|
||||
vecs.row(i) = z(i)*parVec.row(i)
|
||||
+ z(i+edgeMps.rows())*perpVec.row(i);
|
||||
}
|
||||
igl::average_from_edges_onto_vertices
|
||||
(F, E, oE, vecs.rowwise().norm(), colors);
|
||||
};
|
||||
Eigen::MatrixXd noisyvecs, noisycolors, smoothedvecs, smoothedcolors,
|
||||
rawvecs, rawcolors;
|
||||
cr_result_to_vecs_and_colors(znoisy, noisyvecs, noisycolors);
|
||||
cr_result_to_vecs_and_colors(zsmoothed, smoothedvecs, smoothedcolors);
|
||||
cr_result_to_vecs_and_colors(zraw, rawvecs, rawcolors);
|
||||
|
||||
|
||||
//Viewer that shows noisy and denoised functions
|
||||
igl::opengl::glfw::Viewer viewer;
|
||||
viewer.data().set_mesh(V,F);
|
||||
viewer.data().show_lines = false;
|
||||
viewer.callback_key_down =
|
||||
[&](igl::opengl::glfw::Viewer & viewer, unsigned char key, int mod)->bool
|
||||
{
|
||||
const Eigen::MatrixXd *vecs, *colors;
|
||||
switch(key) {
|
||||
case '1':
|
||||
vecs = &rawvecs;
|
||||
colors = &rawcolors;
|
||||
break;
|
||||
case '2':
|
||||
vecs = &noisyvecs;
|
||||
colors = &noisycolors;
|
||||
break;
|
||||
case '3':
|
||||
vecs = &smoothedvecs;
|
||||
colors = &smoothedcolors;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
viewer.data().set_data(*colors);
|
||||
viewer.data().clear_edges();
|
||||
const double s = 0.08; //How much to scale vectors during plotting
|
||||
viewer.data().add_edges(edgeMps, edgeMps + s*(*vecs),
|
||||
Eigen::RowVector3d(0.1, 0.1, 0.1));
|
||||
return true;
|
||||
};
|
||||
std::cout << R"(Usage:
|
||||
1 Show raw function
|
||||
2 Show noisy function
|
||||
3 Show smoothed function
|
||||
|
||||
)";
|
||||
Eigen::MatrixXd CM;
|
||||
igl::parula(Eigen::VectorXd::LinSpaced
|
||||
(500,znoisy.minCoeff(), znoisy.maxCoeff()).eval(), true, CM);
|
||||
viewer.data().set_colormap(CM);
|
||||
viewer.callback_key_down(viewer, '1', 0);
|
||||
viewer.launch();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
add_executable(${PROJECT_NAME}_bin main.cpp)
|
||||
target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
#include <igl/read_triangle_mesh.h>
|
||||
#include <igl/parula.h>
|
||||
#include <igl/remove_unreferenced.h>
|
||||
#include <igl/opengl/glfw/Viewer.h>
|
||||
#include <igl/per_face_normals.h>
|
||||
#include <igl/orient_halfedges.h>
|
||||
#include <igl/cr_vector_laplacian.h>
|
||||
#include <igl/cr_vector_mass.h>
|
||||
#include <igl/crouzeix_raviart_cotmatrix.h>
|
||||
#include <igl/crouzeix_raviart_massmatrix.h>
|
||||
#include <igl/edge_midpoints.h>
|
||||
#include <igl/edge_vectors.h>
|
||||
#include <igl/average_from_edges_onto_vertices.h>
|
||||
#include <igl/min_quad_with_fixed.h>
|
||||
#include <igl/heat_geodesics.h>
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/SparseCholesky>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "tutorial_shared_path.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
typedef Eigen::SparseMatrix<double> SparseMat;
|
||||
typedef Eigen::Matrix<double, 1, 1> Vector1d;
|
||||
typedef Eigen::Matrix<int, 1, 1> Vector1i;
|
||||
|
||||
//Constants used for smoothing
|
||||
const double howMuchToSmoothBy = 1e-1;
|
||||
const int howManySmoothingInterations = 50;
|
||||
|
||||
//Read our mesh
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
if(!igl::read_triangle_mesh
|
||||
(argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cheburashka.off",V,F)) {
|
||||
std::cout << "Failed to load mesh." << std::endl;
|
||||
}
|
||||
|
||||
//Compute vector Laplacian and mass matrix
|
||||
Eigen::MatrixXi E, oE;//Compute Laplacian and mass matrix
|
||||
SparseMat vecL, vecM;
|
||||
igl::cr_vector_mass(V, F, E, oE, vecM);
|
||||
igl::cr_vector_laplacian(V, F, E, oE, vecL);
|
||||
const int m = vecL.rows()/2; //The number of edges in the mesh
|
||||
|
||||
//Convert the E / oE matrix format to list of edges / EMAP format required
|
||||
// by the functions constructing scalar Crouzeix-Raviart functions
|
||||
Eigen::MatrixXi Elist(m,2), EMAP(3*F.rows(),1);
|
||||
for(int i=0; i<F.rows(); ++i) {
|
||||
for(int j=0; j<3; ++j) {
|
||||
const int e = E(i,j);
|
||||
EMAP(i+j*F.rows()) = e;
|
||||
if(oE(i,j)>0) {
|
||||
Elist.row(e) << F(i, (j+1)%3), F(i, (j+2)%3);
|
||||
}
|
||||
}
|
||||
}
|
||||
SparseMat scalarL, scalarM;
|
||||
igl::crouzeix_raviart_massmatrix(V, F, Elist, EMAP, scalarM);
|
||||
igl::crouzeix_raviart_cotmatrix(V, F, Elist, EMAP, scalarL);
|
||||
|
||||
//Compute edge midpoints & edge vectors
|
||||
Eigen::MatrixXd edgeMps, parVec, perpVec;
|
||||
igl::edge_midpoints(V, F, E, oE, edgeMps);
|
||||
igl::edge_vectors(V, F, E, oE, parVec, perpVec);
|
||||
|
||||
//Perform the vector heat method
|
||||
const int initialIndex = 14319;
|
||||
const double initialPara=0.95, initialPerp=0.08;
|
||||
const double t = 0.01;
|
||||
|
||||
SparseMat Aeq;
|
||||
Eigen::VectorXd Beq;
|
||||
Eigen::VectorXi known = Eigen::Vector2i(initialIndex, initialIndex+m);
|
||||
Eigen::VectorXd knownVals = Eigen::Vector2d(initialPara, initialPerp);
|
||||
Eigen::VectorXd Y0 = Eigen::VectorXd::Zero(2*m), Yt;
|
||||
Y0(initialIndex) = initialPara; Y0(initialIndex+m) = initialPerp;
|
||||
igl::min_quad_with_fixed
|
||||
(SparseMat(vecM+t*vecL), Eigen::VectorXd(-vecM*Y0), known, knownVals,
|
||||
Aeq, Beq, false, Yt);
|
||||
|
||||
Eigen::VectorXd u0 = Eigen::VectorXd::Zero(m), ut;
|
||||
u0(initialIndex) = sqrt(initialPara*initialPara + initialPerp*initialPerp);
|
||||
Eigen::VectorXi knownScal = Vector1i(initialIndex);
|
||||
Eigen::VectorXd knownScalVals = Vector1d(u0(initialIndex));
|
||||
igl::min_quad_with_fixed
|
||||
(SparseMat(scalarM+t*scalarL), Eigen::VectorXd(-scalarM*u0), knownScal,
|
||||
knownScalVals, Aeq, Beq, false, ut);
|
||||
|
||||
Eigen::VectorXd phi0 = Eigen::VectorXd::Zero(m), phit;
|
||||
phi0(initialIndex) = 1;
|
||||
Eigen::VectorXd knownScalValsPhi = Vector1d(1);
|
||||
igl::min_quad_with_fixed
|
||||
(SparseMat(scalarM+t*scalarL), Eigen::VectorXd(-scalarM*phi0), knownScal,
|
||||
knownScalValsPhi, Aeq, Beq, false, phit);
|
||||
|
||||
Eigen::ArrayXd Xtfactor = ut.array() /
|
||||
(phit.array() * (Yt.array().segment(0,m)*Yt.array().segment(0,m)
|
||||
+ Yt.array().segment(m,m)*Yt.array().segment(m,m)).sqrt());
|
||||
Eigen::VectorXd Xt(2*m);
|
||||
Xt.segment(0,m) = Xtfactor * Yt.segment(0,m).array();
|
||||
Xt.segment(m,m) = Xtfactor * Yt.segment(m,m).array();
|
||||
|
||||
|
||||
//Compute scalar heat colors
|
||||
igl::HeatGeodesicsData<double> hgData;
|
||||
igl::heat_geodesics_precompute(V, F, hgData);
|
||||
Eigen::VectorXd heatColor;
|
||||
Eigen::VectorXi gamma = Elist.row(initialIndex);
|
||||
igl::heat_geodesics_solve(hgData, gamma, heatColor);
|
||||
|
||||
|
||||
//Convert vector field for plotting
|
||||
Eigen::MatrixXd vecs(m, 3);
|
||||
for(int i=0; i<edgeMps.rows(); ++i) {
|
||||
vecs.row(i) = Xt(i)*parVec.row(i) + Xt(i+edgeMps.rows())*perpVec.row(i);
|
||||
}
|
||||
|
||||
|
||||
//Viewer that shows parallel transported vector
|
||||
igl::opengl::glfw::Viewer viewer;
|
||||
viewer.data().set_mesh(V,F);
|
||||
viewer.data().show_lines = false;
|
||||
viewer.data().set_data(heatColor.maxCoeff()-heatColor.array(), //invert colormap
|
||||
igl::COLOR_MAP_TYPE_VIRIDIS);
|
||||
const double s = 0.012; //How much to scale vectors during plotting
|
||||
Eigen::MatrixXd vecColors(m, 3);
|
||||
for(int i=0; i<m; ++i) {
|
||||
vecColors.row(i) << 0.1, 0.1, 0.1;
|
||||
}
|
||||
vecColors.row(initialIndex) << 0.9, 0.1, 0.1;
|
||||
viewer.data().add_edges(edgeMps, edgeMps + s*vecs, vecColors);
|
||||
|
||||
std::cout << R"(The red vector is parallel transported to every point on the surface.
|
||||
The surface is shaded by geodesic distance from the red vector.
|
||||
)"
|
||||
<< std::endl;
|
||||
viewer.launch();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -166,4 +166,6 @@ if(TUTORIALS_CHAPTER7)
|
||||
add_subdirectory("718_IterativeClosestPoint")
|
||||
add_subdirectory("719_ExplodedView")
|
||||
add_subdirectory("720_BlueNoise")
|
||||
add_subdirectory("721_VectorFieldSmoothing")
|
||||
add_subdirectory("722_VectorParallelTransport")
|
||||
endif()
|
||||
|
||||
Reference in New Issue
Block a user