Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
content badge Iframe embedding
swh:1:cnt:76561c0563f1e48fa71d613c8a272311d3be3963

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
#include "LocalGlobalSolver.h"

#include <geometrycentral/utilities/vector2.h>
#include <igl/cat.h>
#include <igl/columnize.h>
#include <igl/cotmatrix.h>
#include <igl/cotmatrix_entries.h>
#include <igl/project_isometrically_to_plane.h>
#include <igl/repdiag.h>

LocalGlobalSolver::LocalGlobalSolver(const Eigen::Ref<Eigen::MatrixX3d> V, const Eigen::Ref<Eigen::MatrixX3i> F) : _F(F)
{
  using namespace Eigen;

  // number of vertices
  nV = V.rows();
  nF = F.rows();

  s1.resize(nF);
  s2.resize(nF);
  stressX.resize(nF, 2);
  stressY.resize(nF, 2);

  MatrixX2d plane_V;
  MatrixX3i plane_F;
  SparseMatrix<double> ref_map, ref_map_dim;

  igl::project_isometrically_to_plane(V, F, plane_V, plane_F, ref_map);
  igl::repdiag(ref_map, 2, ref_map_dim);

  int nF = F.rows();
  _Ainv.resize(2, 2 * nF);
  for(int i = 0; i < nF; ++i)
  {
    Matrix2d A;
    A.col(0) = plane_V.row(nF + i) - plane_V.row(i);
    A.col(1) = plane_V.row(2 * nF + i) - plane_V.row(i);
    _Ainv.block<2, 2>(0, 2 * i) = A.inverse();
  }

  buildRHS(plane_V, plane_F);
  _K = (ref_map_dim * _K).eval();
  _K.prune([&](const int row, const int col, const double val) { return row != 0 && row != nV; });

  assert(_K.rows() == nV * 2);

  SparseMatrix<double> L; // cotan Laplacian
  igl::cotmatrix(V, F, L);
  SparseMatrix<double> Q = (-L).eval();
  Q.prune([](const int row, const int col, const double val) { return row > 0 && col > 0; });
  Q.reserve(1);
  Q.insert(0, 0) = 1;

  _solver = std::make_unique<geometrycentral::PositiveDefiniteSolver<double>>(Q);
}

void LocalGlobalSolver::solveOneStep(Eigen::Ref<Eigen::MatrixX2d> U, double sMin, double sMax)
{
  using namespace Eigen;

  Matrix<double, 2, -1> R(2, 2 * nF);
#pragma omp parallel for schedule(static) num_threads(omp_get_max_threads() - 1)
  for(int i = 0; i < _F.rows(); ++i)
  {
    Matrix2d B;
    B.col(0) = U.row(_F(i, 1)) - U.row(_F(i, 0));
    B.col(1) = U.row(_F(i, 2)) - U.row(_F(i, 0));

    R.block<2, 2>(0, 2 * i) = project(B * _Ainv.block<2, 2>(0, 2 * i), sMin, sMax, i);
  }

  VectorXd Rcol;
  igl::columnize(R, nF, 2, Rcol);
  VectorXd Bcol = -_K * Rcol;

  U.col(0) = _solver->solve(-Bcol.segment(0, nV));
  U.col(1) = _solver->solve(-Bcol.segment(nV, nV));
}

void LocalGlobalSolver::solve(Eigen::Ref<Eigen::MatrixX2d> U, double sMin, double sMax, int nbIter)
{
  using namespace Eigen;

  if(nbIter > 0)
    for(int i = 0; i < nbIter; ++i)
      solveOneStep(U, sMin, sMax);
  else
  {
    VectorXd s1_prev = VectorXd::Constant(s1.size(), sMin);
    VectorXd s2_prev = VectorXd::Constant(s2.size(), sMax);
    solveOneStep(U, sMin, sMax);
    while(std::max((s1 - s1_prev).norm() / s1.size(), (s2 - s2_prev).norm() / s2.size()) > 1e-8)
    {
      s1_prev = s1;
      s2_prev = s2;
      solveOneStep(U, sMin, sMax);
    }
  }
}

Eigen::Matrix2d LocalGlobalSolver::project(const Eigen::Matrix2d& M, double sMin, double sMax, int i)
{
  using namespace Eigen;
  JacobiSVD<Matrix2d> svd;
  svd.compute(M, ComputeFullU | ComputeFullV);
  Matrix2d S = svd.singularValues().asDiagonal();

  // save data
  s1(i) = S(0, 0);
  s2(i) = S(1, 1);
  stressX.row(i) = svd.matrixU().col(0);
  stressY.row(i) = svd.matrixU().col(1);

  S(1, 1) = sMin;
  S(0, 0) = sMax;
  return svd.matrixU() * S * svd.matrixV().transpose();
}

void LocalGlobalSolver::buildRHS(const Eigen::Ref<Eigen::MatrixX2d> V, const Eigen::Ref<Eigen::MatrixX3i> F)
{
  using namespace Eigen;

  SparseMatrix<double> KX, KY;
  buildLinearBlock(V, F, 0, KX);
  buildLinearBlock(V, F, 1, KY);
  _K = igl::cat(2, igl::repdiag(KX, 2), igl::repdiag(KY, 2));
}

void LocalGlobalSolver::buildLinearBlock(const Eigen::Ref<Eigen::MatrixXd> V,
                                         const Eigen::Ref<Eigen::MatrixXi> F,
                                         const int d,
                                         Eigen::SparseMatrix<double>& Kd)
{
  using namespace Eigen;

  // Temporary output
  std::vector<Triplet<double>> Kd_IJV;
  Kd_IJV.reserve(3 * 2 * F.rows());

  // gather cotangent weights
  MatrixXd C;
  igl::cotmatrix_entries(V, F, C);
  // should have weights for each edge
  assert(C.cols() == 3);
  // loop over elements
  for(int i = 0; i < F.rows(); ++i)
  {
    // loop over edges of element
    for(int j = 0; j < 3; ++j)
    {
      int source = F(i, (j + 1) % 3);
      int dest = F(i, (j + 2) % 3);
      double v = C(i, j) * (V(source, d) - V(dest, d));
      Kd_IJV.emplace_back(source, i, v);
      Kd_IJV.emplace_back(dest, i, -v);
    }
  }
  Kd.resize(V.rows(), F.rows());
  Kd.setFromTriplets(Kd_IJV.begin(), Kd_IJV.end());
}

Eigen::VectorXd LocalGlobalSolver::stretchAngles()
{
  using namespace geometrycentral;

  Eigen::VectorXd angles(nF);
  for(int i = 0; i < nF; ++i)
  {
    Vector2 dir{stressX(i, 0), stressX(i, 1)};
    angles(i) = dir.pow(2).arg() / 2;
  }
  return angles;
}

back to top

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API