Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "morphtool.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tvectorgl.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
shun-iwasawa 7f1e30
#include <qkeyevent></qkeyevent>
shun-iwasawa 7f1e30
Shinya Kitaoka 120a6e
class Deformation {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  std::vector<tpointd> m_controlPoints;</tpointd>
Shinya Kitaoka 120a6e
  int m_selected;
Shinya Kitaoka 120a6e
  TAffine m_aff;
Shinya Kitaoka 120a6e
  std::vector<tpointd> m_delta;</tpointd>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int getClosest(const TPointD &p) const;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Deformation();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void update() {
Shinya Kitaoka 120a6e
    TPointD p0 = m_controlPoints[0];
Shinya Kitaoka 120a6e
    TPointD p1 = m_controlPoints[2];
Shinya Kitaoka 120a6e
    TPointD p2 = m_controlPoints[4];
Shinya Kitaoka 120a6e
    double a00 = p0.x - p2.x, a01 = p1.x - p2.x, a10 = p0.y - p2.y,
Shinya Kitaoka 120a6e
           a11 = p1.y - p2.y;
Shinya Kitaoka 120a6e
    TAffine aff(a00, a01, 0, a10, a11, 0);
Shinya Kitaoka 120a6e
    aff       = aff.inv();
Shinya Kitaoka 120a6e
    TPointD d = -(aff * p2);
Shinya Kitaoka 120a6e
    aff.a13   = d.x;
Shinya Kitaoka 120a6e
    aff.a23   = d.y;
Shinya Kitaoka 120a6e
    m_aff     = aff;
Shinya Kitaoka 120a6e
    m_delta.resize(3);
Shinya Kitaoka 120a6e
    m_delta[0] = m_controlPoints[1] - p0;
Shinya Kitaoka 120a6e
    m_delta[1] = m_controlPoints[3] - p1;
Shinya Kitaoka 120a6e
    m_delta[2] = m_controlPoints[5] - p2;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD apply(const TPointD &p, double t = 1.0) {
Shinya Kitaoka 120a6e
    TPointD d = m_aff * p;
Shinya Kitaoka 120a6e
    double c0 = d.x, c1 = d.y, c2 = 1 - c0 - c1;
Shinya Kitaoka 120a6e
    TPointD delta = c0 * m_delta[0] + c1 * m_delta[1] + c2 * m_delta[2];
Shinya Kitaoka 120a6e
    return p + delta * t;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void deform(TStroke *dstStroke, const TStroke *srcStroke, double t = 1.0) {
Shinya Kitaoka 120a6e
    int n = srcStroke->getControlPointCount();
Shinya Kitaoka 120a6e
    if (dstStroke->getControlPointCount() < n)
Shinya Kitaoka 120a6e
      n = dstStroke->getControlPointCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
      TThickPoint srcPoint = srcStroke->getControlPoint(i);
Shinya Kitaoka 120a6e
      dstStroke->setControlPoint(i, apply(srcPoint, t));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void deform(TVectorImage *dstImage, const TVectorImage *srcImage,
Shinya Kitaoka 120a6e
              double t = 1.0) {
Shinya Kitaoka 120a6e
    update();
Shinya Kitaoka 120a6e
    int n                                      = srcImage->getStrokeCount();
Shinya Kitaoka 120a6e
    if ((int)dstImage->getStrokeCount() < n) n = dstImage->getStrokeCount();
Shinya Kitaoka 120a6e
    std::vector<int> ii(n);</int>
Shinya Kitaoka 120a6e
    std::vector<tstroke *=""> oldStrokes(n);</tstroke>
Shinya Kitaoka 120a6e
    for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
      ii[i]         = i;
Shinya Kitaoka 120a6e
      oldStrokes[i] = srcImage->getStroke(i);
Shinya Kitaoka 120a6e
      deform(dstImage->getStroke(i), oldStrokes[i], t);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    dstImage->notifyChangedStrokes(ii, oldStrokes);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void updateLevel() {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (!app->getCurrentLevel()->getLevel()) return;
Shinya Kitaoka 120a6e
    TXshSimpleLevelP xl = app->getCurrentLevel()->getLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
    if (app->getCurrentFrame()->getFrameType() != TFrameHandle::LevelFrame)
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFrameId fid      = app->getCurrentFrame()->getFid();
Shinya Kitaoka 120a6e
    TVectorImageP src = xl->getFrame(fid, true);
Shinya Kitaoka 120a6e
    int count         = src->getStrokeCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int i = 1; i < 10; i++) {
Shinya Kitaoka 120a6e
      ++fid;
Shinya Kitaoka 120a6e
      if (!xl->isFid(fid)) {
Shinya Kitaoka 120a6e
        TVectorImageP vi = new TVectorImage();
Shinya Kitaoka 120a6e
        xl->setFrame(fid, vi);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      TVectorImageP vi  = xl->getFrame(fid, true);
Shinya Kitaoka 120a6e
      TVectorImageP dst = src->clone();
Shinya Kitaoka 120a6e
      deform(dst.getPointer(), src.getPointer(), (double)i / (double)9);
Shinya Kitaoka 120a6e
      count = dst->getStrokeCount();
Shinya Kitaoka 120a6e
      vi->mergeImage(dst, TAffine());
Shinya Kitaoka 120a6e
      app->getCurrentTool()->getTool()->notifyImageChanged(fid);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Deformation::Deformation() : m_selected(-1) {
Shinya Kitaoka 120a6e
  m_controlPoints.resize(6);
Shinya Kitaoka 120a6e
  m_controlPoints[0] = TPointD(-250, 100);
Shinya Kitaoka 120a6e
  m_controlPoints[2] = TPointD(0, -300);
Shinya Kitaoka 120a6e
  m_controlPoints[4] = TPointD(250, 100);
Shinya Kitaoka 120a6e
  for (int i = 0; i < 6; i += 2) m_controlPoints[i + 1] = m_controlPoints[i];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int Deformation::getClosest(const TPointD &p) const {
Shinya Kitaoka 120a6e
  int k            = -1;
Shinya Kitaoka 120a6e
  double closestD2 = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_controlPoints.size(); i++) {
Shinya Kitaoka 120a6e
    TPointD cp = m_controlPoints[i];
Shinya Kitaoka 120a6e
    double d2  = norm2(p - cp);
Shinya Kitaoka 120a6e
    if (k < 0 || d2 <= closestD2) {
Shinya Kitaoka 120a6e
      closestD2 = d2;
Shinya Kitaoka 120a6e
      k         = i;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return closestD2 < 100 ? k : -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Deformation deformation;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
TThickPoint deform(const TThickPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  double r2 = p.x*p.x+p.y*p.y;
Toshihiro Shimizu 890ddd
  double f = exp(-r2*0.001);
Toshihiro Shimizu 890ddd
  return p + delta * f;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MorphTool::MorphTool() : m_pixelSize(1) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
MorphTool::~MorphTool() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MorphTool::setImage(const TVectorImageP &vi) { m_vi = vi; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MorphTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_lastPos = m_firstPos = pos;
Shinya Kitaoka 120a6e
  int index              = deformation.getClosest(pos);
Shinya Kitaoka 120a6e
  if (index >= 0)
Shinya Kitaoka 120a6e
    deformation.m_selected = index;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    deformation.m_selected = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_vi && index >= 0) {
Shinya Kitaoka 120a6e
    m_vi2 = m_vi->clone();
Shinya Kitaoka 120a6e
    deformation.deform(m_vi2.getPointer(), m_vi.getPointer());
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_vi2 = TVectorImageP();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MorphTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (deformation.m_selected < 0) return;
Shinya Kitaoka 120a6e
  TPointD delta = pos - m_lastPos;
Shinya Kitaoka 120a6e
  m_lastPos     = pos;
Shinya Kitaoka 120a6e
  deformation.m_controlPoints[deformation.m_selected] += delta;
Shinya Kitaoka 120a6e
  if ((deformation.m_selected & 1) == 0)
Shinya Kitaoka 120a6e
    deformation.m_controlPoints[deformation.m_selected + 1] += delta;
Shinya Kitaoka 120a6e
  if (m_vi2 && m_vi) deformation.deform(m_vi2.getPointer(), m_vi.getPointer());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MorphTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_vi2 = TVectorImageP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void MorphTool::draw() {
Shinya Kitaoka 120a6e
  m_pixelSize = sqrt(tglGetPixelSize2());
Shinya Kitaoka 120a6e
  if (m_vi2) {
Shinya Kitaoka 120a6e
    TVectorRenderData rd(TTranslation(10, 10), TRect(), 0, 0);
Shinya Kitaoka 120a6e
    tglDraw(rd, m_vi2.getPointer());
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double u = m_pixelSize * 5;
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)deformation.m_controlPoints.size(); i++) {
Shinya Kitaoka 120a6e
    TPointD p     = deformation.m_controlPoints[i];
Shinya Kitaoka 120a6e
    bool selected = deformation.m_selected == i;
Shinya Kitaoka 120a6e
    bool base     = (i & 1) == 0;
Shinya Kitaoka 120a6e
    if (base)
Shinya Kitaoka 120a6e
      if (selected)
Shinya Kitaoka 120a6e
        glColor3d(0.8, 0.8, 0.1);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        glColor3d(0.5, 0.5, 0.1);
Shinya Kitaoka 120a6e
    else if (selected)
Shinya Kitaoka 120a6e
      glColor3d(0.8, 0.3, 0.1);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      glColor3d(0.5, 0.1, 0.1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double r = base ? u * 2 : u * 1;
Shinya Kitaoka 120a6e
    tglDrawDisk(p, r);
Shinya Kitaoka 120a6e
    glColor3d(0, 0, 0);
Shinya Kitaoka 120a6e
    tglDrawCircle(p, r);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  glColor3f(0, 1, 0);
Shinya Kitaoka 120a6e
  for (int i = 0; i + 1 < (int)deformation.m_controlPoints.size(); i += 2) {
Shinya Kitaoka 120a6e
    TPointD a = deformation.m_controlPoints[i];
Shinya Kitaoka 120a6e
    TPointD b = deformation.m_controlPoints[i + 1];
Shinya Kitaoka 120a6e
    tglDrawSegment(a, b);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
deformation.update();
Shinya Kitaoka 120a6e
glBegin(GL_LINES);
Shinya Kitaoka 120a6e
for(double x = -200; x<=200; x+=20)
Shinya Kitaoka 120a6e
for(double y = -200; y<=200; y+=20)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
TPointD p0(x,y);
Shinya Kitaoka 120a6e
TPointD p1 = deformation.apply(p0);
Shinya Kitaoka 120a6e
glColor3d(0,1,0);
Shinya Kitaoka 120a6e
tglVertex(p0);
Shinya Kitaoka 120a6e
glColor3d(1,0,0);
Shinya Kitaoka 120a6e
tglVertex(p1);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
glEnd();
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
shun-iwasawa 7f1e30
bool MorphTool::keyDown(QKeyEvent *event) {
shun-iwasawa 7f1e30
  if (event->key() == Qt::Key_A)
Shinya Kitaoka 120a6e
    deformation.updateLevel();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}