Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_misc.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tlin includes
Toshihiro Shimizu 890ddd
#include "tlin/tlin.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
#include <memory></memory>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformer.h"
Toshihiro Shimizu 890ddd
Campbell Barton 107701
#include <cstring></cstring>
Campbell Barton 107701
Toshihiro Shimizu 890ddd
/*! \file plasticdeformer.cpp
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  This file contains the implementation of a Mesh Deformer as specified in the
Toshihiro Shimizu 890ddd
  Igarashi-Moscovich-Hughes paper "As-Rigid-As-Possible Shape Manipulation",
Toshihiro Shimizu 890ddd
  with some slight modifications.
Toshihiro Shimizu 890ddd
  \n\n
Toshihiro Shimizu 890ddd
  Notably, the choice of handle points is not limited to mesh vertices, but free
Toshihiro Shimizu 890ddd
  along the mesh surface. This can be achieved by constraining the classical
Toshihiro Shimizu 890ddd
  least-squares minimization problems on a linear hyperplane, in the form:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  

\f$

Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \left{ \begin{array}{c}
Toshihiro Shimizu 890ddd
    v^t H v + v^t f + c   \rightarrow   \mbox{min} \\
Toshihiro Shimizu 890ddd
    A v + d = 0
Toshihiro Shimizu 890ddd
  \end{array} \right.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \f$ 

Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  which can be solved using the Lagrange Multipliers theorem:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  

\f$

tomosu 953a4a
Toshihiro Shimizu 890ddd
  \Rightarrow \left{ \begin{array}{c}
Toshihiro Shimizu 890ddd
    H v + f = A^t \lambda
Toshihiro Shimizu 890ddd
    A v + d = 0
Toshihiro Shimizu 890ddd
  \end{array} \right.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  \Rightarrow \left( \begin{array}{c} H \\ A \end{array} \begin{array}{c} -A^t
Shinya Kitaoka 120a6e
  \\ 0 \end{array} \right)
tomosu 953a4a
              \left( \begin{array}{c} v \\ \lambda \end{array} \right) =
Toshihiro Shimizu 890ddd
              \left( \begin{array}{c} -f \\ -d \end{array} \right)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \f$ 

Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//#define GL_DEBUG                                    // Debug using OpenGL.
Shinya Kitaoka 38fd86
// Must deform while drawing.
Shinya Kitaoka 120a6e
#ifdef GL_DEBUG   // NOTE: You should force deformations,
Shinya Kitaoka 120a6e
#include "tgl.h"  // see plasticdeformersstorage.cpp
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Local structures
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! A linear constraint of the kind   k[0] * v0 + k[1] * v1 + k[2] * v2 = b;
Shinya Kitaoka 120a6e
//! (b is not included though)
Toshihiro Shimizu 890ddd
struct LinearConstraint {
Shinya Kitaoka 120a6e
  int m_h;        //!< Original handle index corresponding to this constraint
Shinya Kitaoka 120a6e
  int m_v[3];     //!< The mesh vertex indices v0, v1, v2
Shinya Kitaoka 120a6e
  double m_k[3];  //!< Constraint coefficients
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct SuperFactors_free {
tomosu 953a4a
  void operator()(tlin::SuperFactors *f) { tlin::freeF(f); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
using SuperFactorsPtr = std::unique_ptr<tlin::superfactors, superfactors_free="">;</tlin::superfactors,>
Shinya Kitaoka 120a6e
using DoublePtr       = std::unique_ptr<double[]>;</double[]>
Shinya Kitaoka 120a6e
using TPointDPtr      = std::unique_ptr<tpointd[]>;</tpointd[]>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Local functions
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void vertices(const TTextureMesh &mesh, int faceIdx, const TPointD *&p0,
Shinya Kitaoka 120a6e
                     const TPointD *&p1, const TPointD *&p2) {
Shinya Kitaoka 120a6e
  int v0, v1, v2;
Shinya Kitaoka 120a6e
  mesh.faceVertices(faceIdx, v0, v1, v2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  p0 = &mesh.vertex(v0).P(), p1 = &mesh.vertex(v1).P(),
Shinya Kitaoka 120a6e
  p2 = &mesh.vertex(v2).P();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void buildTriangularCoordinates(const TTextureMesh &mesh, int &faceIdx,
Shinya Kitaoka 120a6e
                                       const TPointD &p, double &c0, double &c1,
Shinya Kitaoka 120a6e
                                       double &c2) {
Shinya Kitaoka 120a6e
  TPointD coords;
Shinya Kitaoka 120a6e
  const TPointD *p0, *p1, *p2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Follow the hint first
Shinya Kitaoka 120a6e
  if (faceIdx >= 0 && faceIdx < mesh.facesCount() &&
Shinya Kitaoka 120a6e
      mesh.faceContains(faceIdx, p)) {
Shinya Kitaoka 120a6e
    vertices(mesh, faceIdx, p0, p1, p2);
Shinya Kitaoka 120a6e
    coords = tcg::point_ops::triCoords(p, *p0, *p1, *p2);
Shinya Kitaoka 120a6e
    c1 = coords.x, c2 = coords.y, c0 = 1.0 - c1 - c2;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Find out the face searching on the mesh
Shinya Kitaoka 120a6e
  faceIdx = mesh.faceContaining(p);
Shinya Kitaoka 120a6e
  if (faceIdx >= 0) {
Shinya Kitaoka 120a6e
    vertices(mesh, faceIdx, p0, p1, p2);
Shinya Kitaoka 120a6e
    coords = tcg::point_ops::triCoords(p, *p0, *p1, *p2);
Shinya Kitaoka 120a6e
    c1 = coords.x, c2 = coords.y, c0 = 1.0 - c1 - c2;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void addConstraint1d(int j, const LinearConstraint &cnstr,
Shinya Kitaoka 120a6e
                            tlin::spmat &mat) {
Shinya Kitaoka 120a6e
  int i, var, nVars = 3;
Shinya Kitaoka 120a6e
  for (i = 0; i < nVars; ++i) {
Shinya Kitaoka 120a6e
    var = cnstr.m_v[i];
Shinya Kitaoka 120a6e
    mat.at(j, var) += cnstr.m_k[i];
Shinya Kitaoka 120a6e
    mat.at(var, j) = mat(j, var);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void addConstraint2d(int j, const LinearConstraint &cnstr,
Shinya Kitaoka 120a6e
                            tlin::spmat &mat) {
Shinya Kitaoka 120a6e
  int i, varX, varY, k = j + 1, nVars = 3;
Shinya Kitaoka 120a6e
  for (i = 0; i < nVars; ++i) {
Shinya Kitaoka 120a6e
    varX = 2 * cnstr.m_v[i], varY = varX + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    mat.at(j, varX) += cnstr.m_k[i];
Shinya Kitaoka 120a6e
    mat.at(k, varY) += cnstr.m_k[i];
Shinya Kitaoka 120a6e
    mat.at(varX, j) = mat(j, varX);
Shinya Kitaoka 120a6e
    mat.at(varY, k) = mat(k, varY);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void addGValues(int v0x, int v0y, int v1x, int v1y, int v2x, int v2y,
Shinya Kitaoka 120a6e
                       double px, double py, double w, tlin::spmat &G) {
Shinya Kitaoka 120a6e
  double sqPy = py * py, one_px = 1.0 - px;
Shinya Kitaoka 120a6e
  double a = w * (one_px * one_px + sqPy), b = w * (px * one_px - sqPy),
Shinya Kitaoka 120a6e
         c = w * (py * one_px + px * py), d = w * (px * px + sqPy);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  sqPy *= w;
Shinya Kitaoka 120a6e
  one_px *= w;
Shinya Kitaoka 120a6e
  px *= w;
Shinya Kitaoka 120a6e
  py *= w;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v0x, v0x) += a;
Shinya Kitaoka 120a6e
  G.at(v0x, v1x) += b;
Shinya Kitaoka 120a6e
  G.at(v0x, v1y) += c;
Shinya Kitaoka 120a6e
  G.at(v0x, v2x) -= one_px;
Shinya Kitaoka 120a6e
  G.at(v0x, v2y) -= py;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v0y, v0y) += a;
Shinya Kitaoka 120a6e
  G.at(v0y, v1x) -= py;
Shinya Kitaoka 120a6e
  G.at(v0y, v1y) += b;
Shinya Kitaoka 120a6e
  G.at(v0y, v2x) += py;
Shinya Kitaoka 120a6e
  G.at(v0y, v2y) -= one_px;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v1x, v0x) += b;
Shinya Kitaoka 120a6e
  G.at(v1x, v0y) += -py;
Shinya Kitaoka 120a6e
  G.at(v1x, v1x) += d;
Shinya Kitaoka 120a6e
  G.at(v1x, v2x) += -px;
Shinya Kitaoka 120a6e
  G.at(v1x, v2y) += py;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v1y, v0x) += c;
Shinya Kitaoka 120a6e
  G.at(v1y, v0y) += b;
Shinya Kitaoka 120a6e
  G.at(v1y, v1y) += d;
Shinya Kitaoka 120a6e
  G.at(v1y, v2x) -= py;
Shinya Kitaoka 120a6e
  G.at(v1y, v2y) -= px;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v2x, v0x) -= one_px;
Shinya Kitaoka 120a6e
  G.at(v2x, v0y) += py;
Shinya Kitaoka 120a6e
  G.at(v2x, v1x) -= px;
Shinya Kitaoka 120a6e
  G.at(v2x, v1y) -= py;
Shinya Kitaoka 120a6e
  G.at(v2x, v2x) += w;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  G.at(v2y, v0x) -= py;
Shinya Kitaoka 120a6e
  G.at(v2y, v0y) -= one_px;
Shinya Kitaoka 120a6e
  G.at(v2y, v1x) += py;
Shinya Kitaoka 120a6e
  G.at(v2y, v1y) -= px;
Shinya Kitaoka 120a6e
  G.at(v2y, v2y) += w;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void buildF(double px, double py, tlin::spmat &F) {
Shinya Kitaoka 120a6e
  double one_px = 1.0 - px, sqPy = py * py;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  F.at(0, 0) = 1.0 + one_px * one_px + sqPy;
Shinya Kitaoka 120a6e
  F.at(1, 1) = F(0, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  F.at(0, 2) = px * one_px - sqPy;
Shinya Kitaoka 120a6e
  F.at(0, 3) = py * one_px + px * py;
Shinya Kitaoka 120a6e
  F.at(1, 2) = -F(0, 3);
Shinya Kitaoka 120a6e
  F.at(1, 3) = F(0, 2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  F.at(2, 0) = F(0, 2);
Shinya Kitaoka 120a6e
  F.at(2, 1) = F(1, 2);
Shinya Kitaoka 120a6e
  F.at(3, 0) = F(0, 3);
Shinya Kitaoka 120a6e
  F.at(3, 1) = F(1, 3);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  F.at(2, 2) = 1.0 + px * px + sqPy;
Shinya Kitaoka 120a6e
  F.at(3, 3) = F(2, 2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void build_c(double v0x, double v0y, double v1x, double v1y, double v2x,
Shinya Kitaoka 120a6e
             double v2y, double px, double py, double *c) {
Shinya Kitaoka 120a6e
  c[0] = (v0x + v2x * (1.0 - px) + v2y * py);
Shinya Kitaoka 120a6e
  c[1] = (v0y - v2x * py + v2y * (1.0 - px));
Shinya Kitaoka 120a6e
  c[2] = (v1x + v2x * px - v2y * py);
Shinya Kitaoka 120a6e
  c[3] = (v1y + v2y * px + v2x * py);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void addHValues(int v0, int v1, double w, tlin::spmat &H) {
Shinya Kitaoka 120a6e
  H.at(v0, v0) += w;
Shinya Kitaoka 120a6e
  H.at(v1, v0) -= w;
Shinya Kitaoka 120a6e
  H.at(v0, v1) -= w;
Shinya Kitaoka 120a6e
  H.at(v1, v1) += w;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void add_f_values(int v0, int v1, double fit0, double fit1, double w,
Shinya Kitaoka 120a6e
                         double *f) {
Shinya Kitaoka 120a6e
  double f0_f1 = w * (fit0 - fit1);
Shinya Kitaoka 120a6e
  f[v0] += f0_f1;
Shinya Kitaoka 120a6e
  f[v1] -= f0_f1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticDeformer::Imp  definition
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class PlasticDeformer::Imp {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TTextureMeshP m_mesh;                  //!< Deformed mesh (cannot be changed)
Shinya Kitaoka 120a6e
  std::vector<plastichandle> m_handles;  //!< Compiled handles</plastichandle>
Shinya Kitaoka 120a6e
  std::vector<linearconstraint> m_constraints1,</linearconstraint>
Shinya Kitaoka 120a6e
      m_constraints3;  //!< Compiled constraints (depends on the above)
Shinya Kitaoka 120a6e
  bool m_compiled;     //!< Whether the deformer is ready to deform()
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Imp();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void initialize(const TTextureMeshP &mesh);
Shinya Kitaoka 120a6e
  void compile(const std::vector<plastichandle> &handles, int *faceHints);</plastichandle>
Shinya Kitaoka 120a6e
  void deform(const TPointD *dstHandles, double *dstVerticesCoords);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void copyOriginals(double *dstVerticesCoords);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  tlin::spmat m_G;         //!< Pre-initialized entries for the 1st
Shinya Kitaoka 120a6e
                           //!< linear system
Shinya Kitaoka 120a6e
  SuperFactorsPtr m_invC;  //!< C's factors (C is G plus linear constraints)
Shinya Kitaoka 120a6e
  DoublePtr m_q;           //!< Step 1's known term
Shinya Kitaoka 120a6e
  DoublePtr m_out;         //!< Step 1's result
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Step 1 members:
Shinya Kitaoka 120a6e
  //   The first step of a MeshDeformer instance is about building the desired
Shinya Kitaoka 120a6e
  //   vertices configuration.
Shinya Kitaoka 120a6e
  void initializeStep1();
Shinya Kitaoka 120a6e
  void compileStep1(const std::vector<plastichandle> &handles);</plastichandle>
Shinya Kitaoka 120a6e
  void deformStep1(const TPointD *dstHandles, double *dstVerticesCoords);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void releaseInitializedData();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  std::vector<superfactorsptr></superfactorsptr>
Shinya Kitaoka 120a6e
      m_invF;  //!< Each of step 2's systems factorizations
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointDPtr m_relativeCoords;  //!< Faces' p2 coordinates in (p0, p1)'s
Shinya Kitaoka 38fd86
                                //! orthogonal reference
Shinya Kitaoka 120a6e
  double m_v[4], m_c[4];        //!< Known term and output coordinates
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointDPtr m_fitTriangles;  //!< Output face coordinates
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Step 2 members:
Shinya Kitaoka 120a6e
  //   The second step of MeshDeformer rigidly maps neighbourhoods of the
Shinya Kitaoka 120a6e
  //   original mesh
Shinya Kitaoka 120a6e
  //   to fit as much as possible the neighbourhoods in the step 1 result.
Shinya Kitaoka 120a6e
  void initializeStep2();
Shinya Kitaoka 120a6e
  void compileStep2(const std::vector<plastichandle> &handles);</plastichandle>
Shinya Kitaoka 120a6e
  void deformStep2(const TPointD *dstHandles, double *dstVerticesCoords);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  // NOTE: This step accepts separation in the X and Y components
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tlin::spmat m_H;         //!< Step 3's system entries
Shinya Kitaoka 120a6e
  SuperFactorsPtr m_invK;  //!< System inverse
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DoublePtr m_fx, m_fy;  //!< Known terms
Shinya Kitaoka 120a6e
  DoublePtr m_x, m_y;    //!< Output values
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Step 3 members:
Shinya Kitaoka 120a6e
  //   The third step of MeshDeformer glues together the mapped neighbourhoods
Shinya Kitaoka 120a6e
  //   from step2.
Shinya Kitaoka 120a6e
  void initializeStep3();
Shinya Kitaoka 120a6e
  void compileStep3(const std::vector<plastichandle> &handles);</plastichandle>
Shinya Kitaoka 120a6e
  void deformStep3(const TPointD *dstHandles, double *dstVerticesCoords);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlasticDeformer::Imp::Imp() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::initialize(const TTextureMeshP &mesh) {
Shinya Kitaoka 120a6e
  assert("Input mesh must be squeezed!" &&
Shinya Kitaoka 120a6e
         mesh->verticesCount() == mesh->vertices().nodesCount() &&
Shinya Kitaoka 120a6e
         mesh->edgesCount() == mesh->edges().nodesCount() &&
Shinya Kitaoka 120a6e
         mesh->facesCount() == mesh->faces().nodesCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_mesh = mesh;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  initializeStep1();
Shinya Kitaoka 120a6e
  initializeStep2();
Shinya Kitaoka 120a6e
  initializeStep3();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_compiled = false;  // Compilation is expected after a new initialization
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticDeformer::Imp::compile(const std::vector<plastichandle> &handles,</plastichandle>
Shinya Kitaoka 120a6e
                                   int *faceHints) {
Shinya Kitaoka 120a6e
  assert(m_mesh);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_handles.clear(), m_handles.reserve(handles.size());
Shinya Kitaoka 120a6e
  m_constraints1.clear(), m_constraints3.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  LinearConstraint constr;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build the linear constraints raising from the mesh-handles pairing
Shinya Kitaoka 120a6e
  int h, hCount = handles.size();
Shinya Kitaoka 120a6e
  for (h = 0; h < hCount; ++h) {
Shinya Kitaoka 120a6e
    int localFaceIdx = -1, &faceIdx = faceHints ? faceHints[h] : localFaceIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ::buildTriangularCoordinates(*m_mesh, faceIdx, handles[h].m_pos,
Shinya Kitaoka 120a6e
                                 constr.m_k[0], constr.m_k[1], constr.m_k[2]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (faceIdx >= 0) {
Shinya Kitaoka 120a6e
      constr.m_h = h;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      m_mesh->faceVertices(faceIdx, constr.m_v[0], constr.m_v[1],
Shinya Kitaoka 120a6e
                           constr.m_v[2]);
Shinya Kitaoka 120a6e
      m_constraints1.push_back(constr);
Shinya Kitaoka 120a6e
      if (handles[h].m_interpolate) m_constraints3.push_back(constr);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Store the handles to retain precompiled data
Shinya Kitaoka 120a6e
      m_handles.push_back(handles[h]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // m_handles = handles;                              // NOT directly copied
Shinya Kitaoka 120a6e
  // like this: some handles could be
Shinya Kitaoka 120a6e
  // (geometrically) OUTSIDE the mesh!
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Now, invoke the actual compilation procedures
Shinya Kitaoka 120a6e
  m_compiled = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_handles.size() < 2) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  compileStep1(handles);  // These may set m_compiled = false. Must still be
Shinya Kitaoka 120a6e
  compileStep2(handles);  // called even when that happens - as they are
Shinya Kitaoka 120a6e
  compileStep3(handles);  // responsible for resources reclamation.
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::deform(const TPointD *dstHandles,
Shinya Kitaoka 120a6e
                                  double *dstVerticesCoords) {
Shinya Kitaoka 120a6e
  assert(m_mesh);
Shinya Kitaoka 120a6e
  assert(dstVerticesCoords);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Deal with trivial cases
Shinya Kitaoka 120a6e
  if (!m_compiled || m_handles.size() == 0) {
Shinya Kitaoka 120a6e
    // Cannot deform anything - just copy the source mesh vertices into dst ones
Shinya Kitaoka 120a6e
    copyOriginals(dstVerticesCoords);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(dstHandles);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_handles.size() == 1) {
Shinya Kitaoka 120a6e
    // 1 handle inside the mesh - pure translational case
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const PlasticHandle &srcHandle = m_handles.front();
Shinya Kitaoka 120a6e
    const TPointD &dstHandlePos    = dstHandles[m_constraints1.front().m_h];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TPointD shift(dstHandlePos - srcHandle.m_pos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int v, vCount = m_mesh->verticesCount();
Shinya Kitaoka 120a6e
    for (v = 0; v != vCount; ++v, dstVerticesCoords += 2) {
Shinya Kitaoka 120a6e
      dstVerticesCoords[0] = m_mesh->vertex(v).P().x + shift.x;
Shinya Kitaoka 120a6e
      dstVerticesCoords[1] = m_mesh->vertex(v).P().y + shift.y;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  deformStep1(dstHandles, dstVerticesCoords);
Shinya Kitaoka 120a6e
  deformStep2(dstHandles, dstVerticesCoords);
Shinya Kitaoka 120a6e
  deformStep3(dstHandles, dstVerticesCoords);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::copyOriginals(double *dstVerticesCoords) {
Shinya Kitaoka 120a6e
  int v, vCount = m_mesh->verticesCount();
Shinya Kitaoka 120a6e
  for (v = 0; v != vCount; ++v, dstVerticesCoords += 2) {
Shinya Kitaoka 120a6e
    dstVerticesCoords[0] = m_mesh->vertex(v).P().x;
Shinya Kitaoka 120a6e
    dstVerticesCoords[1] = m_mesh->vertex(v).P().y;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::releaseInitializedData() {
Shinya Kitaoka 120a6e
  // Release m_G and m_H
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    tlin::spmat temp;
Shinya Kitaoka 120a6e
    swap(m_G, temp);
Shinya Kitaoka 120a6e
  }  // Ensure resources release by swapping them
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    tlin::spmat temp;
Shinya Kitaoka 120a6e
    swap(m_H, temp);
Shinya Kitaoka 120a6e
  }  // with newly initialized instances
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Plastic Deformation Step 1
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::initializeStep1() {
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
  int vCount = mesh.verticesCount(), vCount_2 = 2 * vCount;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_G = tlin::spmat(vCount_2, vCount_2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize the linear system indices for the stored mesh
Shinya Kitaoka 120a6e
  int f, fCount = mesh.facesCount();
Shinya Kitaoka 120a6e
  for (f = 0; f < fCount; ++f) {
Shinya Kitaoka 120a6e
    int v0, v1, v2;
Shinya Kitaoka 120a6e
    mesh.faceVertices(f, v0, v1, v2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int v0x = 2 * v0;   // We'll use 2 params per vertex - with
Shinya Kitaoka 120a6e
    int v0y = v0x + 1;  // adjacent x and y parameters
Shinya Kitaoka 120a6e
    int v1x = 2 * v1;
Shinya Kitaoka 120a6e
    int v1y = v1x + 1;
Shinya Kitaoka 120a6e
    int v2x = 2 * v2;
Shinya Kitaoka 120a6e
    int v2y = v2x + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const TTextureMesh::vertex_type &vx0 = mesh.vertex(v0);
Shinya Kitaoka 120a6e
    const TTextureMesh::vertex_type &vx1 = mesh.vertex(v1);
Shinya Kitaoka 120a6e
    const TTextureMesh::vertex_type &vx2 = mesh.vertex(v2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD c0, c1, c2;
Shinya Kitaoka 120a6e
    c2 = tcg::point_ops::ortCoords(vx2.P(), vx0.P(), vx1.P());
Shinya Kitaoka 120a6e
    c0 = tcg::point_ops::ortCoords(vx0.P(), vx1.P(), vx2.P());
Shinya Kitaoka 120a6e
    c1 = tcg::point_ops::ortCoords(vx1.P(), vx2.P(), vx0.P());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    addGValues(v0x, v0y, v1x, v1y, v2x, v2y, c2.x, c2.y, vx2.P().rigidity, m_G);
Shinya Kitaoka 120a6e
    addGValues(v1x, v1y, v2x, v2y, v0x, v0y, c0.x, c0.y, vx0.P().rigidity, m_G);
Shinya Kitaoka 120a6e
    addGValues(v2x, v2y, v0x, v0y, v1x, v1y, c1.x, c1.y, vx1.P().rigidity, m_G);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::compileStep1(
Shinya Kitaoka 120a6e
    const std::vector<plastichandle> &handles) {</plastichandle>
Shinya Kitaoka 120a6e
  // First, release resources
Shinya Kitaoka 120a6e
  m_invC.reset();
Shinya Kitaoka 120a6e
  m_q.reset();
Shinya Kitaoka 120a6e
  m_out.reset();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, start compiling
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
  int vCount = mesh.verticesCount(), hCount = m_handles.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int cSize = 2 * (vCount + hCount);  // Coefficients count
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize C with G
Shinya Kitaoka 120a6e
  tlin::SuperMatrix *trC = 0;
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    tlin::spmat C(cSize, cSize);
Shinya Kitaoka 120a6e
    C.entries()                      = m_G.entries();
Shinya Kitaoka 120a6e
    C.entries().hashFunctor().m_cols = C.cols();
Shinya Kitaoka 120a6e
    C.entries().rehash(C.entries()
Shinya Kitaoka 120a6e
                           .buckets()
Shinya Kitaoka 120a6e
                           .size());  // Rehash to entries according to C's size
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Add the entries constraining handles
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    std::vector<linearconstraint>::iterator ht, hEnd(m_constraints1.end());</linearconstraint>
Shinya Kitaoka 120a6e
    for (i = 0, ht = m_constraints1.begin(); ht != hEnd; ++i, ++ht)
Shinya Kitaoka 120a6e
      addConstraint2d(2 * (vCount + i), *ht, C);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    tlin::traduceS(C, trC);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build m_invC
Shinya Kitaoka 120a6e
  tlin::SuperFactors *invC = 0;
Shinya Kitaoka 120a6e
  tlin::factorize(trC, invC);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tlin::freeS(trC);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (invC) {
Shinya Kitaoka 120a6e
    m_invC.reset(invC);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Reallocate arrays
Shinya Kitaoka 120a6e
    m_q.reset(new double[cSize]);
Shinya Kitaoka 120a6e
    m_out.reset(new double[cSize]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    memset(m_q.get(), 0,
Shinya Kitaoka 120a6e
           2 * vCount *
Shinya Kitaoka 120a6e
               sizeof(double));  // Initialize the system's known term with 0
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    m_compiled = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::deformStep1(const TPointD *dstHandles,
Shinya Kitaoka 120a6e
                                       double *dstVerticesCoords) {
Shinya Kitaoka 120a6e
  int vCount2 = 2 * m_mesh->verticesCount();
Shinya Kitaoka 120a6e
  int cSize   = vCount2 + 2 * m_handles.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Copy destination handles into the system's known term
Shinya Kitaoka 120a6e
  int i, h;
Shinya Kitaoka 120a6e
  for (i = vCount2, h = 0; i < cSize; i += 2, ++h) {
Shinya Kitaoka 120a6e
    const TPointD &dstHandlePos = dstHandles[m_constraints1[h].m_h];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_q[i] = dstHandlePos.x;  // NOTE: We could use calloc on-the-fly, sparing
Shinya Kitaoka 120a6e
    m_q[i + 1] =
Shinya Kitaoka 120a6e
        dstHandlePos.y;  // some memory. Have to benchmark the cost, though...
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Solve the linear system
Shinya Kitaoka 120a6e
  double *out = m_out.get();
Shinya Kitaoka 120a6e
  tlin::solve(m_invC.get(), m_q.get(), out);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef GL_DEBUG
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glColor3d(1.0, 0.0, 0.0);  // Red
Shinya Kitaoka 120a6e
  glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Draw deformed mesh edges
Shinya Kitaoka 120a6e
  int e, eCount = m_mesh->edgesCount();
Shinya Kitaoka 120a6e
  for (e = 0; e < eCount; ++e) {
Shinya Kitaoka 120a6e
    const TTextureMesh::edge_type &ed = m_mesh->edge(e);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double *x0 = out + 2 * ed.vertex(0), *x1 = out + 2 * ed.vertex(1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    glVertex2d(*x0, *(x0 + 1));
Shinya Kitaoka 120a6e
    glVertex2d(*x1, *(x1 + 1));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glEnd();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Plastic Deformation Step 2
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::initializeStep2() {
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
  int f, fCount = mesh.facesCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Clear and re-initialize vars
Shinya Kitaoka 120a6e
  tlin::spmat F(4, 4);
Shinya Kitaoka 120a6e
  tlin::SuperMatrix *trF;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<superfactorsptr>(fCount).swap(m_invF);</superfactorsptr>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_relativeCoords.reset(new TPointD[fCount]);
Shinya Kitaoka 120a6e
  m_fitTriangles.reset(new TPointD[3 * fCount]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Build step 2's system factorizations (yep, can be done at this point)
Shinya Kitaoka 120a6e
  const TPointD *p0, *p1, *p2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (f = 0; f < fCount; ++f) {
Shinya Kitaoka 120a6e
    ::vertices(mesh, f, p0, p1, p2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TPointD c(tcg::point_ops::ortCoords(*p2, *p0, *p1));
Shinya Kitaoka 120a6e
    m_relativeCoords[f] = c;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    F.clear();
Shinya Kitaoka 120a6e
    buildF(c.x, c.y, F);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    trF = 0;
Shinya Kitaoka 120a6e
    tlin::traduceS(F, trF);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    tlin::SuperFactors *invF = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    tlin::factorize(trF, invF);
Shinya Kitaoka 120a6e
    m_invF[f].reset(invF);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    tlin::freeS(trF);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::compileStep2(
Shinya Kitaoka 120a6e
    const std::vector<plastichandle> &handles) {</plastichandle>
Shinya Kitaoka 120a6e
  // Nothing to do :)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::deformStep2(const TPointD *dstHandles,
Shinya Kitaoka 120a6e
                                       double *dstVerticesCoords) {
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
  int vCount               = mesh.verticesCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  memset(m_fx.get(), 0,
Shinya Kitaoka 120a6e
         vCount * sizeof(double));  // These should be part of step 3...
Shinya Kitaoka 120a6e
  memset(m_fy.get(), 0,
Shinya Kitaoka 120a6e
         vCount * sizeof(double));  // They are filled here just for convenience
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build fit triangles
Shinya Kitaoka 120a6e
  TPointD *fitTri = m_fitTriangles.get(), *relCoord = m_relativeCoords.get();
Shinya Kitaoka 120a6e
  double *out1 = m_out.get();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int f, fCount = mesh.facesCount();
Shinya Kitaoka 120a6e
  for (f = 0; f < fCount; ++f, fitTri += 3, ++relCoord) {
Shinya Kitaoka 120a6e
    int v0, v1, v2;
Shinya Kitaoka 120a6e
    m_mesh->faceVertices(f, v0, v1, v2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const RigidPoint &p0 = mesh.vertex(v0).P(), &p1 = mesh.vertex(v1).P(),
Shinya Kitaoka 120a6e
                     &p2 = mesh.vertex(v2).P();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double *v0x = out1 + (v0 << 1), *v0y = v0x + 1, *v1x = out1 + (v1 << 1),
Shinya Kitaoka 120a6e
           *v1y = v1x + 1, *v2x = out1 + (v2 << 1), *v2y = v2x + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    build_c(*v0x, *v0y, *v1x, *v1y, *v2x, *v2y, relCoord->x, relCoord->y, m_c);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double *vPtr = (double *)m_v;
Shinya Kitaoka 120a6e
    tlin::solve(m_invF[f].get(), (double *)m_c, vPtr);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fitTri[0].x = m_v[0], fitTri[0].y = m_v[1];
Shinya Kitaoka 120a6e
    fitTri[1].x = m_v[2], fitTri[1].y = m_v[3];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fitTri[2].x = fitTri[0].x + relCoord->x * (fitTri[1].x - fitTri[0].x) +
Shinya Kitaoka 120a6e
                  relCoord->y * (fitTri[1].y - fitTri[0].y);
Shinya Kitaoka 120a6e
    fitTri[2].y = fitTri[0].y + relCoord->x * (fitTri[1].y - fitTri[0].y) +
Shinya Kitaoka 120a6e
                  relCoord->y * (fitTri[0].x - fitTri[1].x);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Scale with respect to baricenter. The baricenter is used since it makes
Shinya Kitaoka 120a6e
    // distance from vertices equally
Shinya Kitaoka 120a6e
    // weighting - which is the same expected when minimizing positions (by
Shinya Kitaoka 120a6e
    // collateral effect) in the next step.
Shinya Kitaoka 120a6e
    TPointD baricenter((fitTri[0].x + fitTri[1].x + fitTri[2].x) / 3.0,
Shinya Kitaoka 120a6e
                       (fitTri[0].y + fitTri[1].y + fitTri[2].y) / 3.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double scale = sqrt(
Shinya Kitaoka 120a6e
        norm2(TPointD(p1.x - p0.x, p1.y - p0.y)) /
Shinya Kitaoka 120a6e
        norm2(TPointD(fitTri[1].x - fitTri[0].x, fitTri[1].y - fitTri[0].y)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fitTri[0] = scale * (fitTri[0] - baricenter) + baricenter;
Shinya Kitaoka 120a6e
    fitTri[1] = scale * (fitTri[1] - baricenter) + baricenter;
Shinya Kitaoka 120a6e
    fitTri[2] = scale * (fitTri[2] - baricenter) + baricenter;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Build f -- note: this should be part of step 3, we're just avoiding the
Shinya Kitaoka 120a6e
    // same cycle twice :)
Shinya Kitaoka 120a6e
    add_f_values(v0, v1, fitTri[0].x, fitTri[1].x,
Shinya Kitaoka 120a6e
                 std::min(p0.rigidity, p1.rigidity), m_fx.get());
Shinya Kitaoka 120a6e
    add_f_values(v0, v1, fitTri[0].y, fitTri[1].y,
Shinya Kitaoka 120a6e
                 std::min(p0.rigidity, p1.rigidity), m_fy.get());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    add_f_values(v1, v2, fitTri[1].x, fitTri[2].x,
Shinya Kitaoka 120a6e
                 std::min(p1.rigidity, p2.rigidity), m_fx.get());
Shinya Kitaoka 120a6e
    add_f_values(v1, v2, fitTri[1].y, fitTri[2].y,
Shinya Kitaoka 120a6e
                 std::min(p1.rigidity, p2.rigidity), m_fy.get());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    add_f_values(v2, v0, fitTri[2].x, fitTri[0].x,
Shinya Kitaoka 120a6e
                 std::min(p2.rigidity, p0.rigidity), m_fx.get());
Shinya Kitaoka 120a6e
    add_f_values(v2, v0, fitTri[2].y, fitTri[0].y,
Shinya Kitaoka 120a6e
                 std::min(p2.rigidity, p0.rigidity), m_fy.get());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef GL_DEBUG
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glColor3d(0.0, 0.0, 1.0);  // Blue
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Draw fit triangles
Shinya Kitaoka 120a6e
  fitTri = m_fitTriangles.get();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (f = 0; f < fCount; ++f, fitTri += 3) {
Shinya Kitaoka 120a6e
    glBegin(GL_LINE_LOOP);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    glVertex2d(fitTri[0].x, fitTri[0].y);
Shinya Kitaoka 120a6e
    glVertex2d(fitTri[1].x, fitTri[1].y);
Shinya Kitaoka 120a6e
    glVertex2d(fitTri[2].x, fitTri[2].y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    glEnd();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
//    Plastic Deformation Step 3
Toshihiro Shimizu 890ddd
//******************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::initializeStep3() {
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
  int vCount               = mesh.verticesCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_H = tlin::spmat(vCount, vCount);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int f, fCount = mesh.facesCount();
Shinya Kitaoka 120a6e
  for (f = 0; f < fCount; ++f) {
Shinya Kitaoka 120a6e
    int v0, v1, v2;
Shinya Kitaoka 120a6e
    mesh.faceVertices(f, v0, v1, v2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const RigidPoint &p0 = mesh.vertex(v0).P(), &p1 = mesh.vertex(v1).P(),
Shinya Kitaoka 120a6e
                     &p2 = mesh.vertex(v2).P();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    addHValues(v0, v1, std::min(p0.rigidity, p1.rigidity), m_H);
Shinya Kitaoka 120a6e
    addHValues(v1, v2, std::min(p1.rigidity, p2.rigidity), m_H);
Shinya Kitaoka 120a6e
    addHValues(v2, v0, std::min(p2.rigidity, p0.rigidity), m_H);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::compileStep3(
Shinya Kitaoka 120a6e
    const std::vector<plastichandle> &handles) {</plastichandle>
Shinya Kitaoka 120a6e
  // First, release resources
Shinya Kitaoka 120a6e
  m_invK.reset();
Shinya Kitaoka 120a6e
  m_x.reset();
Shinya Kitaoka 120a6e
  m_y.reset();
Shinya Kitaoka 120a6e
  m_fx.reset();
Shinya Kitaoka 120a6e
  m_fy.reset();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If compilation already failed, skip
Shinya Kitaoka 120a6e
  if (!m_compiled) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TTextureMesh &mesh = *m_mesh;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int vCount = mesh.verticesCount();
Shinya Kitaoka 120a6e
  int kSize  = vCount + m_constraints3.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize K with H
Shinya Kitaoka 120a6e
  tlin::SuperMatrix *trK = 0;
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    tlin::spmat K(kSize, kSize);
Shinya Kitaoka 120a6e
    K.entries()                      = m_H.entries();
Shinya Kitaoka 120a6e
    K.entries().hashFunctor().m_cols = K.cols();
Shinya Kitaoka 120a6e
    K.entries().rehash(K.entries()
Shinya Kitaoka 120a6e
                           .buckets()
Shinya Kitaoka 120a6e
                           .size());  // Rehash to entries according to K's size
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Add the entries constraining handles
Shinya Kitaoka 120a6e
    int c, cnstrCount = m_constraints3.size();
Shinya Kitaoka 120a6e
    for (c = 0; c < cnstrCount; ++c) {
Shinya Kitaoka 120a6e
      // Add the linear constraint to the system
Shinya Kitaoka 120a6e
      addConstraint1d(vCount + c, m_constraints3[c], K);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    tlin::traduceS(K, trK);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build m_invK
Shinya Kitaoka 120a6e
  tlin::SuperFactors *invK = 0;
Shinya Kitaoka 120a6e
  tlin::factorize(trK, invK);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tlin::freeS(trK);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (invK) {
Shinya Kitaoka 120a6e
    m_invK.reset(invK);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_x.reset((double *)malloc(kSize * sizeof(double)));
Shinya Kitaoka 120a6e
    m_y.reset((double *)malloc(kSize * sizeof(double)));
Shinya Kitaoka 120a6e
    m_fx.reset((double *)malloc(kSize * sizeof(double)));
Shinya Kitaoka 120a6e
    m_fy.reset((double *)malloc(kSize * sizeof(double)));
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    m_compiled = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::Imp::deformStep3(const TPointD *dstHandles,
Shinya Kitaoka 120a6e
                                       double *dstVerticesCoords) {
Shinya Kitaoka 120a6e
  int v, vCount = m_mesh->verticesCount();
Shinya Kitaoka 120a6e
  int c;
Shinya Kitaoka 120a6e
  int h, hCount = m_handles.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (c = 0, h = 0; h < hCount; ++h) {
Shinya Kitaoka 120a6e
    if (!m_handles[h].m_interpolate) continue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const TPointD &dstHandlePos = dstHandles[m_constraints1[h].m_h];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_fx[vCount + c] = dstHandlePos.x;
Shinya Kitaoka 120a6e
    m_fy[vCount + c] = dstHandlePos.y;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ++c;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double *x = m_x.get(), *y = m_y.get();
Shinya Kitaoka 120a6e
  tlin::solve(m_invK.get(), m_fx.get(), x);
Shinya Kitaoka 120a6e
  tlin::solve(m_invK.get(), m_fy.get(), y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = v = 0; v < vCount; ++v, i += 2) {
Shinya Kitaoka 120a6e
    dstVerticesCoords[i]     = m_x[v];
Shinya Kitaoka 120a6e
    dstVerticesCoords[i + 1] = m_y[v];
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
//    Plastic Deformer  implementation
Toshihiro Shimizu 890ddd
//**********************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlasticDeformer::PlasticDeformer() : m_imp(new Imp) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
PlasticDeformer::~PlasticDeformer() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformer::compiled() const { return m_imp->m_compiled; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::initialize(const TTextureMeshP &mesh) {
Shinya Kitaoka 120a6e
  m_imp->initialize(mesh);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool PlasticDeformer::compile(const std::vector<plastichandle> &handles,</plastichandle>
Shinya Kitaoka 120a6e
                              int *faceHints) {
Shinya Kitaoka 120a6e
  m_imp->compile(handles, faceHints);
Shinya Kitaoka 120a6e
  return compiled();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::deform(const TPointD *dstHandles,
Shinya Kitaoka 120a6e
                             double *dstVerticesCoords) const {
Shinya Kitaoka 120a6e
  m_imp->deform(dstHandles, dstVerticesCoords);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticDeformer::releaseInitializedData() {
Shinya Kitaoka 120a6e
  m_imp->releaseInitializedData();
Toshihiro Shimizu 890ddd
}