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$

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