| |
| |
|
|
| #include "tcg/tcg_misc.h" |
| |
| |
| #include "tlin/tlin.h" |
| |
| |
| #include <assert.h> |
| #include <memory> |
| |
| #include "ext/plasticdeformer.h" |
| |
| #include <cstring> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifdef GL_DEBUG // NOTE: You should force deformations, |
| #include "tgl.h" // see plasticdeformersstorage.cpp |
| #endif |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| |
| struct LinearConstraint { |
| int m_h; |
| int m_v[3]; |
| double m_k[3]; |
| }; |
| |
| |
| |
| struct SuperFactors_free { |
| void operator()(tlin::SuperFactors *f) { tlin::freeF(f); } |
| }; |
| |
| |
| |
| using SuperFactorsPtr =std::unique_ptr<tlin::SuperFactors, SuperFactors_free>; |
| using DoublePtr =std::unique_ptr<double[]>; |
| using TPointDPtr =std::unique_ptr<TPointD[]>; |
| |
| } |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| inline void vertices(const TTextureMesh &mesh, int faceIdx, |
| const TPointD *&p0, const TPointD *&p1, const TPointD *&p2) |
| { |
| int v0, v1, v2; |
| mesh.faceVertices(faceIdx, v0, v1, v2); |
| |
| p0 = &mesh.vertex(v0).P(), p1 = &mesh.vertex(v1).P(), p2 = &mesh.vertex(v2).P(); |
| } |
| |
| |
| |
| inline void buildTriangularCoordinates(const TTextureMesh &mesh, int &faceIdx, const TPointD &p, |
| double &c0, double &c1, double &c2) |
| { |
| TPointD coords; |
| const TPointD *p0, *p1, *p2; |
| |
| |
| if (faceIdx >= 0 && faceIdx < mesh.facesCount() && |
| mesh.faceContains(faceIdx, p)) { |
| vertices(mesh, faceIdx, p0, p1, p2); |
| coords = tcg::point_ops::triCoords(p, *p0, *p1, *p2); |
| c1 = coords.x, c2 = coords.y, c0 = 1.0 - c1 - c2; |
| return; |
| } |
| |
| |
| faceIdx = mesh.faceContaining(p); |
| if (faceIdx >= 0) { |
| vertices(mesh, faceIdx, p0, p1, p2); |
| coords = tcg::point_ops::triCoords(p, *p0, *p1, *p2); |
| c1 = coords.x, c2 = coords.y, c0 = 1.0 - c1 - c2; |
| return; |
| } |
| } |
| |
| |
| |
| inline void addConstraint1d(int j, const LinearConstraint &cnstr, tlin::spmat &mat) |
| { |
| int i, var, nVars = 3; |
| for (i = 0; i < nVars; ++i) { |
| var = cnstr.m_v[i]; |
| mat.at(j, var) += cnstr.m_k[i]; |
| mat.at(var, j) = mat(j, var); |
| } |
| } |
| |
| |
| |
| inline void addConstraint2d(int j, const LinearConstraint &cnstr, tlin::spmat &mat) |
| { |
| int i, varX, varY, k = j + 1, nVars = 3; |
| for (i = 0; i < nVars; ++i) { |
| varX = 2 * cnstr.m_v[i], varY = varX + 1; |
| |
| mat.at(j, varX) += cnstr.m_k[i]; |
| mat.at(k, varY) += cnstr.m_k[i]; |
| mat.at(varX, j) = mat(j, varX); |
| mat.at(varY, k) = mat(k, varY); |
| } |
| } |
| |
| |
| |
| inline void addGValues( |
| int v0x, int v0y, int v1x, int v1y, int v2x, int v2y, |
| double px, double py, double w, tlin::spmat &G) |
| { |
| double sqPy = py * py, one_px = 1.0 - px; |
| double a = w * (one_px * one_px + sqPy), |
| b = w * (px * one_px - sqPy), |
| c = w * (py * one_px + px * py), |
| d = w * (px * px + sqPy); |
| |
| sqPy *= w; |
| one_px *= w; |
| px *= w; |
| py *= w; |
| |
| G.at(v0x, v0x) += a; |
| G.at(v0x, v1x) += b; |
| G.at(v0x, v1y) += c; |
| G.at(v0x, v2x) -= one_px; |
| G.at(v0x, v2y) -= py; |
| |
| G.at(v0y, v0y) += a; |
| G.at(v0y, v1x) -= py; |
| G.at(v0y, v1y) += b; |
| G.at(v0y, v2x) += py; |
| G.at(v0y, v2y) -= one_px; |
| |
| G.at(v1x, v0x) += b; |
| G.at(v1x, v0y) += -py; |
| G.at(v1x, v1x) += d; |
| G.at(v1x, v2x) += -px; |
| G.at(v1x, v2y) += py; |
| |
| G.at(v1y, v0x) += c; |
| G.at(v1y, v0y) += b; |
| G.at(v1y, v1y) += d; |
| G.at(v1y, v2x) -= py; |
| G.at(v1y, v2y) -= px; |
| |
| G.at(v2x, v0x) -= one_px; |
| G.at(v2x, v0y) += py; |
| G.at(v2x, v1x) -= px; |
| G.at(v2x, v1y) -= py; |
| G.at(v2x, v2x) += w; |
| |
| G.at(v2y, v0x) -= py; |
| G.at(v2y, v0y) -= one_px; |
| G.at(v2y, v1x) += py; |
| G.at(v2y, v1y) -= px; |
| G.at(v2y, v2y) += w; |
| } |
| |
| |
| |
| void buildF(double px, double py, tlin::spmat &F) |
| { |
| double one_px = 1.0 - px, sqPy = py * py; |
| |
| F.at(0, 0) = 1.0 + one_px * one_px + sqPy; |
| F.at(1, 1) = F(0, 0); |
| |
| F.at(0, 2) = px * one_px - sqPy; |
| F.at(0, 3) = py * one_px + px * py; |
| F.at(1, 2) = -F(0, 3); |
| F.at(1, 3) = F(0, 2); |
| |
| F.at(2, 0) = F(0, 2); |
| F.at(2, 1) = F(1, 2); |
| F.at(3, 0) = F(0, 3); |
| F.at(3, 1) = F(1, 3); |
| |
| F.at(2, 2) = 1.0 + px * px + sqPy; |
| F.at(3, 3) = F(2, 2); |
| } |
| |
| |
| |
| void build_c(double v0x, double v0y, double v1x, double v1y, double v2x, double v2y, double px, double py, double *c) |
| { |
| c[0] = (v0x + v2x * (1.0 - px) + v2y * py); |
| c[1] = (v0y - v2x * py + v2y * (1.0 - px)); |
| c[2] = (v1x + v2x * px - v2y * py); |
| c[3] = (v1y + v2y * px + v2x * py); |
| } |
| |
| |
| |
| inline void addHValues(int v0, int v1, double w, tlin::spmat &H) |
| { |
| H.at(v0, v0) += w; |
| H.at(v1, v0) -= w; |
| H.at(v0, v1) -= w; |
| H.at(v1, v1) += w; |
| } |
| |
| |
| |
| inline void add_f_values(int v0, int v1, double fit0, double fit1, double w, double *f) |
| { |
| double f0_f1 = w * (fit0 - fit1); |
| f[v0] += f0_f1; |
| f[v1] -= f0_f1; |
| } |
| |
| } |
| |
| |
| |
| |
| |
| class PlasticDeformer::Imp |
| { |
| public: |
| TTextureMeshP m_mesh; |
| std::vector<PlasticHandle> m_handles; |
| std::vector<LinearConstraint> m_constraints1, m_constraints3; |
| bool m_compiled; |
| |
| public: |
| Imp(); |
| |
| void initialize(const TTextureMeshP &mesh); |
| void compile(const std::vector<PlasticHandle> &handles, int *faceHints); |
| void deform(const TPointD *dstHandles, double *dstVerticesCoords); |
| |
| void copyOriginals(double *dstVerticesCoords); |
| |
| public: |
| tlin::spmat m_G; |
| |
| SuperFactorsPtr m_invC; |
| DoublePtr m_q; |
| DoublePtr m_out; |
| |
| |
| |
| void initializeStep1(); |
| void compileStep1(const std::vector<PlasticHandle> &handles); |
| void deformStep1(const TPointD *dstHandles, double *dstVerticesCoords); |
| |
| void releaseInitializedData(); |
| |
| public: |
| std::vector<SuperFactorsPtr> m_invF; |
| |
| TPointDPtr m_relativeCoords; |
| double m_v[4], m_c[4]; |
| |
| TPointDPtr m_fitTriangles; |
| |
| |
| |
| |
| void initializeStep2(); |
| void compileStep2(const std::vector<PlasticHandle> &handles); |
| void deformStep2(const TPointD *dstHandles, double *dstVerticesCoords); |
| |
| public: |
| |
| |
| tlin::spmat m_H; |
| SuperFactorsPtr m_invK; |
| |
| DoublePtr m_fx, m_fy; |
| DoublePtr m_x, m_y; |
| |
| |
| |
| void initializeStep3(); |
| void compileStep3(const std::vector<PlasticHandle> &handles); |
| void deformStep3(const TPointD *dstHandles, double *dstVerticesCoords); |
| }; |
| |
| |
| |
| PlasticDeformer::Imp::Imp() |
| { |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::initialize(const TTextureMeshP &mesh) |
| { |
| assert("Input mesh must be squeezed!" && |
| mesh->verticesCount() == mesh->vertices().nodesCount() && |
| mesh->edgesCount() == mesh->edges().nodesCount() && |
| mesh->facesCount() == mesh->faces().nodesCount()); |
| |
| m_mesh = mesh; |
| |
| initializeStep1(); |
| initializeStep2(); |
| initializeStep3(); |
| |
| m_compiled = false; |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::compile(const std::vector<PlasticHandle> &handles, |
| int *faceHints) |
| { |
| assert(m_mesh); |
| |
| m_handles.clear(), m_handles.reserve(handles.size()); |
| m_constraints1.clear(), m_constraints3.clear(); |
| |
| LinearConstraint constr; |
| |
| |
| int h, hCount = handles.size(); |
| for (h = 0; h < hCount; ++h) { |
| int localFaceIdx = -1, &faceIdx = faceHints ? faceHints[h] : localFaceIdx; |
| |
| ::buildTriangularCoordinates(*m_mesh, faceIdx, handles[h].m_pos, constr.m_k[0], constr.m_k[1], constr.m_k[2]); |
| |
| if (faceIdx >= 0) { |
| constr.m_h = h; |
| |
| m_mesh->faceVertices(faceIdx, constr.m_v[0], constr.m_v[1], constr.m_v[2]); |
| m_constraints1.push_back(constr); |
| if (handles[h].m_interpolate) |
| m_constraints3.push_back(constr); |
| |
| |
| m_handles.push_back(handles[h]); |
| } |
| } |
| |
| |
| |
| |
| |
| m_compiled = true; |
| |
| if (m_handles.size() < 2) |
| return; |
| |
| compileStep1(handles); |
| compileStep2(handles); |
| compileStep3(handles); |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::deform(const TPointD *dstHandles, double *dstVerticesCoords) |
| { |
| assert(m_mesh); |
| assert(dstVerticesCoords); |
| |
| |
| if (!m_compiled || m_handles.size() == 0) { |
| |
| copyOriginals(dstVerticesCoords); |
| return; |
| } |
| |
| assert(dstHandles); |
| |
| if (m_handles.size() == 1) { |
| |
| |
| const PlasticHandle &srcHandle = m_handles.front(); |
| const TPointD &dstHandlePos = dstHandles[m_constraints1.front().m_h]; |
| |
| TPointD shift(dstHandlePos - srcHandle.m_pos); |
| |
| int v, vCount = m_mesh->verticesCount(); |
| for (v = 0; v != vCount; ++v, dstVerticesCoords += 2) { |
| dstVerticesCoords[0] = m_mesh->vertex(v).P().x + shift.x; |
| dstVerticesCoords[1] = m_mesh->vertex(v).P().y + shift.y; |
| } |
| |
| return; |
| } |
| |
| deformStep1(dstHandles, dstVerticesCoords); |
| deformStep2(dstHandles, dstVerticesCoords); |
| deformStep3(dstHandles, dstVerticesCoords); |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::copyOriginals(double *dstVerticesCoords) |
| { |
| int v, vCount = m_mesh->verticesCount(); |
| for (v = 0; v != vCount; ++v, dstVerticesCoords += 2) { |
| dstVerticesCoords[0] = m_mesh->vertex(v).P().x; |
| dstVerticesCoords[1] = m_mesh->vertex(v).P().y; |
| } |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::releaseInitializedData() |
| { |
| |
| { |
| tlin::spmat temp; |
| swap(m_G, temp); |
| } |
| { |
| tlin::spmat temp; |
| swap(m_H, temp); |
| } |
| } |
| |
| |
| |
| |
| |
| void PlasticDeformer::Imp::initializeStep1() |
| { |
| const TTextureMesh &mesh = *m_mesh; |
| int vCount = mesh.verticesCount(), vCount_2 = 2 * vCount; |
| |
| m_G = tlin::spmat(vCount_2, vCount_2); |
| |
| |
| int f, fCount = mesh.facesCount(); |
| for (f = 0; f < fCount; ++f) { |
| int v0, v1, v2; |
| mesh.faceVertices(f, v0, v1, v2); |
| |
| int v0x = 2 * v0; |
| int v0y = v0x + 1; |
| int v1x = 2 * v1; |
| int v1y = v1x + 1; |
| int v2x = 2 * v2; |
| int v2y = v2x + 1; |
| |
| const TTextureMesh::vertex_type &vx0 = mesh.vertex(v0); |
| const TTextureMesh::vertex_type &vx1 = mesh.vertex(v1); |
| const TTextureMesh::vertex_type &vx2 = mesh.vertex(v2); |
| |
| TPointD c0, c1, c2; |
| c2 = tcg::point_ops::ortCoords(vx2.P(), vx0.P(), vx1.P()); |
| c0 = tcg::point_ops::ortCoords(vx0.P(), vx1.P(), vx2.P()); |
| c1 = tcg::point_ops::ortCoords(vx1.P(), vx2.P(), vx0.P()); |
| |
| addGValues(v0x, v0y, v1x, v1y, v2x, v2y, c2.x, c2.y, vx2.P().rigidity, m_G); |
| addGValues(v1x, v1y, v2x, v2y, v0x, v0y, c0.x, c0.y, vx0.P().rigidity, m_G); |
| addGValues(v2x, v2y, v0x, v0y, v1x, v1y, c1.x, c1.y, vx1.P().rigidity, m_G); |
| } |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::compileStep1(const std::vector<PlasticHandle> &handles) |
| { |
| |
| m_invC.reset(); |
| m_q.reset(); |
| m_out.reset(); |
| |
| |
| const TTextureMesh &mesh = *m_mesh; |
| int vCount = mesh.verticesCount(), hCount = m_handles.size(); |
| |
| int cSize = 2 * (vCount + hCount); |
| |
| |
| tlin::SuperMatrix *trC = 0; |
| { |
| tlin::spmat C(cSize, cSize); |
| C.entries() = m_G.entries(); |
| C.entries().hashFunctor().m_cols = C.cols(); |
| C.entries().rehash(C.entries().buckets().size()); |
| |
| |
| int i; |
| std::vector<LinearConstraint>::iterator ht, hEnd(m_constraints1.end()); |
| for (i = 0, ht = m_constraints1.begin(); ht != hEnd; ++i, ++ht) |
| addConstraint2d(2 * (vCount + i), *ht, C); |
| |
| tlin::traduceS(C, trC); |
| } |
| |
| |
| tlin::SuperFactors *invC = 0; |
| tlin::factorize(trC, invC); |
| |
| tlin::freeS(trC); |
| |
| if (invC) { |
| m_invC.reset(invC); |
| |
| |
| m_q.reset(new double[cSize]); |
| m_out.reset(new double[cSize]); |
| |
| memset(m_q.get(), 0, 2 * vCount * sizeof(double)); |
| } else |
| m_compiled = false; |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::deformStep1(const TPointD *dstHandles, double *dstVerticesCoords) |
| { |
| int vCount2 = 2 * m_mesh->verticesCount(); |
| int cSize = vCount2 + 2 * m_handles.size(); |
| |
| |
| int i, h; |
| for (i = vCount2, h = 0; i < cSize; i += 2, ++h) { |
| const TPointD &dstHandlePos = dstHandles[m_constraints1[h].m_h]; |
| |
| m_q[i] = dstHandlePos.x; |
| m_q[i + 1] = dstHandlePos.y; |
| } |
| |
| |
| double *out = m_out.get(); |
| tlin::solve(m_invC.get(), m_q.get(), out); |
| |
| #ifdef GL_DEBUG |
| |
| glColor3d(1.0, 0.0, 0.0); |
| glBegin(GL_LINES); |
| |
| |
| int e, eCount = m_mesh->edgesCount(); |
| for (e = 0; e < eCount; ++e) { |
| const TTextureMesh::edge_type &ed = m_mesh->edge(e); |
| |
| double *x0 = out + 2 * ed.vertex(0), *x1 = out + 2 * ed.vertex(1); |
| |
| glVertex2d(*x0, *(x0 + 1)); |
| glVertex2d(*x1, *(x1 + 1)); |
| } |
| |
| glEnd(); |
| |
| #endif |
| } |
| |
| |
| |
| |
| |
| void PlasticDeformer::Imp::initializeStep2() |
| { |
| const TTextureMesh &mesh = *m_mesh; |
| int f, fCount = mesh.facesCount(); |
| |
| |
| tlin::spmat F(4, 4); |
| tlin::SuperMatrix *trF; |
| |
| std::vector<SuperFactorsPtr>(fCount).swap(m_invF); |
| |
| m_relativeCoords.reset(new TPointD[fCount]); |
| m_fitTriangles.reset(new TPointD[3 * fCount]); |
| |
| |
| const TPointD *p0, *p1, *p2; |
| |
| for (f = 0; f < fCount; ++f) { |
| ::vertices(mesh, f, p0, p1, p2); |
| |
| TPointD c(tcg::point_ops::ortCoords(*p2, *p0, *p1)); |
| m_relativeCoords[f] = c; |
| |
| F.clear(); |
| buildF(c.x, c.y, F); |
| |
| trF = 0; |
| tlin::traduceS(F, trF); |
| |
| tlin::SuperFactors *invF = 0; |
| |
| tlin::factorize(trF, invF); |
| m_invF[f].reset(invF); |
| |
| tlin::freeS(trF); |
| } |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::compileStep2(const std::vector<PlasticHandle> &handles) |
| { |
| |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::deformStep2(const TPointD *dstHandles, double *dstVerticesCoords) |
| { |
| const TTextureMesh &mesh = *m_mesh; |
| int vCount = mesh.verticesCount(); |
| |
| memset(m_fx.get(), 0, vCount * sizeof(double)); |
| memset(m_fy.get(), 0, vCount * sizeof(double)); |
| |
| |
| TPointD *fitTri = m_fitTriangles.get(), *relCoord = m_relativeCoords.get(); |
| double *out1 = m_out.get(); |
| |
| int f, fCount = mesh.facesCount(); |
| for (f = 0; f < fCount; ++f, fitTri += 3, ++relCoord) { |
| int v0, v1, v2; |
| m_mesh->faceVertices(f, v0, v1, v2); |
| |
| const RigidPoint &p0 = mesh.vertex(v0).P(), &p1 = mesh.vertex(v1).P(), &p2 = mesh.vertex(v2).P(); |
| |
| double *v0x = out1 + (v0 << 1), *v0y = v0x + 1, |
| *v1x = out1 + (v1 << 1), *v1y = v1x + 1, |
| *v2x = out1 + (v2 << 1), *v2y = v2x + 1; |
| |
| build_c( |
| *v0x, *v0y, |
| *v1x, *v1y, |
| *v2x, *v2y, |
| relCoord->x, relCoord->y, m_c); |
| |
| double *vPtr = (double *)m_v; |
| tlin::solve(m_invF[f].get(), (double *)m_c, vPtr); |
| |
| fitTri[0].x = m_v[0], fitTri[0].y = m_v[1]; |
| fitTri[1].x = m_v[2], fitTri[1].y = m_v[3]; |
| |
| fitTri[2].x = fitTri[0].x + relCoord->x * (fitTri[1].x - fitTri[0].x) + relCoord->y * (fitTri[1].y - fitTri[0].y); |
| fitTri[2].y = fitTri[0].y + relCoord->x * (fitTri[1].y - fitTri[0].y) + relCoord->y * (fitTri[0].x - fitTri[1].x); |
| |
| |
| |
| TPointD baricenter( |
| (fitTri[0].x + fitTri[1].x + fitTri[2].x) / 3.0, |
| (fitTri[0].y + fitTri[1].y + fitTri[2].y) / 3.0); |
| |
| double scale = sqrt( |
| norm2(TPointD(p1.x - p0.x, p1.y - p0.y)) / |
| norm2(TPointD(fitTri[1].x - fitTri[0].x, fitTri[1].y - fitTri[0].y))); |
| |
| fitTri[0] = scale * (fitTri[0] - baricenter) + baricenter; |
| fitTri[1] = scale * (fitTri[1] - baricenter) + baricenter; |
| fitTri[2] = scale * (fitTri[2] - baricenter) + baricenter; |
| |
| |
| add_f_values(v0, v1, fitTri[0].x, fitTri[1].x, std::min(p0.rigidity, p1.rigidity), m_fx.get()); |
| add_f_values(v0, v1, fitTri[0].y, fitTri[1].y, std::min(p0.rigidity, p1.rigidity), m_fy.get()); |
| |
| add_f_values(v1, v2, fitTri[1].x, fitTri[2].x, std::min(p1.rigidity, p2.rigidity), m_fx.get()); |
| add_f_values(v1, v2, fitTri[1].y, fitTri[2].y, std::min(p1.rigidity, p2.rigidity), m_fy.get()); |
| |
| add_f_values(v2, v0, fitTri[2].x, fitTri[0].x, std::min(p2.rigidity, p0.rigidity), m_fx.get()); |
| add_f_values(v2, v0, fitTri[2].y, fitTri[0].y, std::min(p2.rigidity, p0.rigidity), m_fy.get()); |
| } |
| |
| #ifdef GL_DEBUG |
| |
| glColor3d(0.0, 0.0, 1.0); |
| |
| |
| fitTri = m_fitTriangles.get(); |
| |
| for (f = 0; f < fCount; ++f, fitTri += 3) { |
| glBegin(GL_LINE_LOOP); |
| |
| glVertex2d(fitTri[0].x, fitTri[0].y); |
| glVertex2d(fitTri[1].x, fitTri[1].y); |
| glVertex2d(fitTri[2].x, fitTri[2].y); |
| |
| glEnd(); |
| } |
| |
| #endif |
| } |
| |
| |
| |
| |
| |
| void PlasticDeformer::Imp::initializeStep3() |
| { |
| const TTextureMesh &mesh = *m_mesh; |
| int vCount = mesh.verticesCount(); |
| |
| m_H = tlin::spmat(vCount, vCount); |
| |
| int f, fCount = mesh.facesCount(); |
| for (f = 0; f < fCount; ++f) { |
| int v0, v1, v2; |
| mesh.faceVertices(f, v0, v1, v2); |
| |
| const RigidPoint &p0 = mesh.vertex(v0).P(), |
| &p1 = mesh.vertex(v1).P(), |
| &p2 = mesh.vertex(v2).P(); |
| |
| addHValues(v0, v1, std::min(p0.rigidity, p1.rigidity), m_H); |
| addHValues(v1, v2, std::min(p1.rigidity, p2.rigidity), m_H); |
| addHValues(v2, v0, std::min(p2.rigidity, p0.rigidity), m_H); |
| } |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::compileStep3(const std::vector<PlasticHandle> &handles) |
| { |
| |
| m_invK.reset(); |
| m_x.reset(); |
| m_y.reset(); |
| m_fx.reset(); |
| m_fy.reset(); |
| |
| |
| if (!m_compiled) |
| return; |
| |
| const TTextureMesh &mesh = *m_mesh; |
| |
| int vCount = mesh.verticesCount(); |
| int kSize = vCount + m_constraints3.size(); |
| |
| |
| tlin::SuperMatrix *trK = 0; |
| { |
| tlin::spmat K(kSize, kSize); |
| K.entries() = m_H.entries(); |
| K.entries().hashFunctor().m_cols = K.cols(); |
| K.entries().rehash(K.entries().buckets().size()); |
| |
| |
| int c, cnstrCount = m_constraints3.size(); |
| for (c = 0; c < cnstrCount; ++c) { |
| |
| addConstraint1d(vCount + c, m_constraints3[c], K); |
| } |
| |
| tlin::traduceS(K, trK); |
| } |
| |
| |
| tlin::SuperFactors *invK = 0; |
| tlin::factorize(trK, invK); |
| |
| tlin::freeS(trK); |
| |
| if (invK) { |
| m_invK.reset(invK); |
| |
| m_x.reset((double *)malloc(kSize * sizeof(double))); |
| m_y.reset((double *)malloc(kSize * sizeof(double))); |
| m_fx.reset((double *)malloc(kSize * sizeof(double))); |
| m_fy.reset((double *)malloc(kSize * sizeof(double))); |
| } else |
| m_compiled = false; |
| } |
| |
| |
| |
| void PlasticDeformer::Imp::deformStep3(const TPointD *dstHandles, double *dstVerticesCoords) |
| { |
| int v, vCount = m_mesh->verticesCount(); |
| int c; |
| int h, hCount = m_handles.size(); |
| |
| for (c = 0, h = 0; h < hCount; ++h) { |
| if (!m_handles[h].m_interpolate) |
| continue; |
| |
| const TPointD &dstHandlePos = dstHandles[m_constraints1[h].m_h]; |
| |
| m_fx[vCount + c] = dstHandlePos.x; |
| m_fy[vCount + c] = dstHandlePos.y; |
| |
| ++c; |
| } |
| |
| double *x = m_x.get(), *y = m_y.get(); |
| tlin::solve(m_invK.get(), m_fx.get(), x); |
| tlin::solve(m_invK.get(), m_fy.get(), y); |
| |
| int i; |
| for (i = v = 0; v < vCount; ++v, i += 2) { |
| dstVerticesCoords[i] = m_x[v]; |
| dstVerticesCoords[i + 1] = m_y[v]; |
| } |
| } |
| |
| |
| |
| |
| |
| PlasticDeformer::PlasticDeformer() |
| : m_imp(new Imp) |
| { |
| } |
| |
| |
| |
| PlasticDeformer::~PlasticDeformer() |
| { |
| } |
| |
| |
| |
| bool PlasticDeformer::compiled() const |
| { |
| return m_imp->m_compiled; |
| } |
| |
| |
| |
| void PlasticDeformer::initialize(const TTextureMeshP &mesh) |
| { |
| m_imp->initialize(mesh); |
| } |
| |
| |
| |
| bool PlasticDeformer::compile(const std::vector<PlasticHandle> &handles, int *faceHints) |
| { |
| m_imp->compile(handles, faceHints); |
| return compiled(); |
| } |
| |
| |
| |
| void PlasticDeformer::deform(const TPointD *dstHandles, double *dstVerticesCoords) const |
| { |
| m_imp->deform(dstHandles, dstVerticesCoords); |
| } |
| |
| |
| |
| void PlasticDeformer::releaseInitializedData() |
| { |
| m_imp->releaseInitializedData(); |
| } |
| |