Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectspline.h"
Toshihiro Shimizu 890ddd
#include "tconst.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tstream.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "tdoubleparam.h"
Toshihiro Shimizu 890ddd
#include "tdoublekeyframe.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qdebug></qdebug>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PERSIST_IDENTIFIER(TStageObjectSpline, "pegbarspline")
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DEFINE_CLASS_CODE(TStageObjectSpline, 19)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
int idBaseCode = 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// PosPathKeyframesUpdater
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// When the spline changes its shape, the PosPathKeyframesUpdater update the
Toshihiro Shimizu 890ddd
// PosPath channel keyframes.
Toshihiro Shimizu 890ddd
// If an object is close to a spline control point it must remain close to it
Toshihiro Shimizu 890ddd
// If the object is between two control points, then the ratio of the distances
Toshihiro Shimizu 890ddd
// along the spline to the two control points remain the same.
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class PosPathKeyframesUpdater {
Shinya Kitaoka 120a6e
  std::vector<double> m_oldControlPointsLengths;</double>
Shinya Kitaoka 120a6e
  std::vector<double> m_newControlPointsLengths;</double>
Shinya Kitaoka 120a6e
  double m_oldSplineLength, m_newSplineLength;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  PosPathKeyframesUpdater(TStroke *oldSpline, TStroke *newSpline)
Shinya Kitaoka 120a6e
      : m_oldSplineLength(0), m_newSplineLength(0) {
Shinya Kitaoka 120a6e
    assert(oldSpline);
Shinya Kitaoka 120a6e
    assert(newSpline);
Shinya Kitaoka 120a6e
    m_oldSplineLength = oldSpline->getLength();
Shinya Kitaoka 120a6e
    m_newSplineLength = newSpline->getLength();
Shinya Kitaoka 120a6e
    int m;
Shinya Kitaoka 120a6e
    m = oldSpline->getControlPointCount();
Shinya Kitaoka 120a6e
    for (int i = 0; i < m; i += 4)
Shinya Kitaoka 120a6e
      m_oldControlPointsLengths.push_back(
Shinya Kitaoka 120a6e
          oldSpline->getLengthAtControlPoint(i));
Shinya Kitaoka 120a6e
    m = newSpline->getControlPointCount();
Shinya Kitaoka 120a6e
    for (int i = 0; i < m; i += 4)
Shinya Kitaoka 120a6e
      m_newControlPointsLengths.push_back(
Shinya Kitaoka 120a6e
          newSpline->getLengthAtControlPoint(i));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void update(TDoubleParam *param) {
Shinya Kitaoka 120a6e
    assert(m_newSplineLength > 0);
Shinya Kitaoka 120a6e
    if (m_newSplineLength <= 0) return;
Shinya Kitaoka 120a6e
    for (int j = 0; j < param->getKeyframeCount(); j++) {
Shinya Kitaoka 120a6e
      TDoubleKeyframe kf = param->getKeyframe(j);
Shinya Kitaoka 120a6e
      double s           = m_oldSplineLength * kf.m_value * 0.01;
Shinya Kitaoka 120a6e
      update(s);
Shinya Kitaoka 120a6e
      double updatedValue = s * 100.0 / m_newSplineLength;
Shinya Kitaoka 120a6e
      kf.m_value          = updatedValue;
Shinya Kitaoka 120a6e
      param->setKeyframe(j, kf);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void update(double &s);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PosPathKeyframesUpdater::update(double &s) {
Shinya Kitaoka 120a6e
  int k    = 0;
Shinya Kitaoka 120a6e
  int oldm = (int)m_oldControlPointsLengths.size();
Shinya Kitaoka 120a6e
  int newm = (int)m_newControlPointsLengths.size();
Shinya Kitaoka 120a6e
  while (k < oldm && m_oldControlPointsLengths[k] <= s) k++;
Shinya Kitaoka 120a6e
  if (k >= oldm) {
Shinya Kitaoka 120a6e
    // all CP lengths <=s
Shinya Kitaoka 120a6e
    if (oldm - 1 < newm)
Shinya Kitaoka 120a6e
      s = m_newControlPointsLengths[oldm - 1];
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      s = m_newSplineLength;
Shinya Kitaoka 120a6e
  } else if (k == 0) {
Shinya Kitaoka 120a6e
    // all CP lengths >s
Shinya Kitaoka 120a6e
    s = 0;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    if (k >= newm)
Shinya Kitaoka 120a6e
      s = m_newSplineLength;
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      double sa    = m_oldControlPointsLengths[k - 1];
Shinya Kitaoka 120a6e
      double sb    = m_oldControlPointsLengths[k];
Shinya Kitaoka 120a6e
      double newSa = m_newControlPointsLengths[k - 1];
Shinya Kitaoka 120a6e
      double newSb = m_newControlPointsLengths[k];
Shinya Kitaoka 120a6e
      assert(sa <= s && s < sb);
Shinya Kitaoka 120a6e
      if (sa >= sb) {
Shinya Kitaoka 120a6e
        s = (newSa + newSb) * 0.5;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        s = newSa + (newSb - newSa) * (s - sa) / (sb - sa);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// TStageObjectSpline
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStageObjectSpline::TStageObjectSpline()
Shinya Kitaoka 120a6e
    : TSmartObject(m_classCode)
Shinya Kitaoka 120a6e
    , m_stroke(0)
Shinya Kitaoka 120a6e
    , m_dagNodePos(TConst::nowhere)
Shinya Kitaoka 120a6e
    , m_id(-1)
Shinya Kitaoka 120a6e
    , m_idBase(std::to_string(idBaseCode++))
Shinya Kitaoka 120a6e
    , m_name("")
Shinya Kitaoka 120a6e
    , m_isOpened(false) {
Shinya Kitaoka 120a6e
  double d = 30;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
  points.push_back(TPointD(0, 0));
Shinya Kitaoka 120a6e
  points.push_back(TPointD(d, 0));
Shinya Kitaoka 120a6e
  points.push_back(TPointD(2.0 * d, 0));
Shinya Kitaoka 120a6e
  m_stroke = new TStroke(points);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStageObjectSpline::~TStageObjectSpline() {
Shinya Kitaoka 120a6e
  delete m_stroke;
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_posPathParams.size(); i++)
Shinya Kitaoka 120a6e
    m_posPathParams[i]->release();
Shinya Kitaoka 120a6e
  m_posPathParams.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStageObjectSpline *TStageObjectSpline::clone() const {
Shinya Kitaoka 120a6e
  TStageObjectSpline *clonedSpline = new TStageObjectSpline();
Shinya Kitaoka 120a6e
  clonedSpline->m_id               = m_id;
Shinya Kitaoka 120a6e
  clonedSpline->m_name             = m_name;
Shinya Kitaoka 120a6e
  clonedSpline->m_stroke           = new TStroke(*m_stroke);
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_posPathParams.size(); i++)
Shinya Kitaoka 120a6e
    clonedSpline->m_posPathParams.push_back(
Shinya Kitaoka 120a6e
        (TDoubleParam *)m_posPathParams[i]->clone());
Shinya Kitaoka 120a6e
  return clonedSpline;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const TStroke *TStageObjectSpline::getStroke() const { return m_stroke; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::updatePosPathKeyframes(TStroke *oldSpline,
Shinya Kitaoka 120a6e
                                                TStroke *newSpline) {
Shinya Kitaoka 120a6e
  if (m_posPathParams.empty()) return;
Shinya Kitaoka 120a6e
  PosPathKeyframesUpdater updater(oldSpline, newSpline);
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_posPathParams.size(); i++) {
Shinya Kitaoka 120a6e
    updater.update(m_posPathParams[i]);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::setStroke(TStroke *stroke) {
Shinya Kitaoka 120a6e
  if (stroke != m_stroke) {
Shinya Kitaoka 120a6e
    if (!m_posPathParams.empty() && stroke != 0 && m_stroke != 0)
Shinya Kitaoka 120a6e
      updatePosPathKeyframes(m_stroke, stroke);
Shinya Kitaoka 120a6e
    delete m_stroke;
Shinya Kitaoka 120a6e
    m_stroke = stroke;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::loadData(TIStream &is) {
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
  VersionNumber tnzVersion = is.getVersion();
Shinya Kitaoka 120a6e
  if (tnzVersion < VersionNumber(1, 16)) {
Shinya Kitaoka 120a6e
    while (!is.eos()) {
Shinya Kitaoka 120a6e
      TThickPoint p;
Shinya Kitaoka 120a6e
      is >> p.x >> p.y >> p.thick;
Shinya Kitaoka 120a6e
      points.push_back(p);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    std::string tagName;
Shinya Kitaoka 120a6e
    while (is.matchTag(tagName)) {
Shinya Kitaoka 120a6e
      if (tagName == "splineId")
Shinya Kitaoka 120a6e
        is >> m_id;
Shinya Kitaoka 120a6e
      else if (tagName == "name")
Shinya Kitaoka 120a6e
        is >> m_name;
Shinya Kitaoka 120a6e
      else if (tagName == "pos")
Shinya Kitaoka 120a6e
        is >> m_dagNodePos.x >> m_dagNodePos.y;
Shinya Kitaoka 120a6e
      else if (tagName == "isOpened") {
Shinya Kitaoka 120a6e
        int v = 0;
Shinya Kitaoka 120a6e
        is >> v;
Shinya Kitaoka 120a6e
        m_isOpened = (bool)v;
Shinya Kitaoka 120a6e
      } else if (tagName == "stroke") {
Shinya Kitaoka 120a6e
        int i, n = 0;
Shinya Kitaoka 120a6e
        is >> n;
Shinya Kitaoka 120a6e
        for (i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
          TThickPoint p;
Shinya Kitaoka 120a6e
          is >> p.x >> p.y >> p.thick;
Shinya Kitaoka 120a6e
          points.push_back(p);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      is.matchEndTag();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  delete m_stroke;
Shinya Kitaoka 120a6e
  m_stroke = new TStroke(points);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::saveData(TOStream &os) {
Shinya Kitaoka 120a6e
  const TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  os.child("splineId") << (int)m_id;
Shinya Kitaoka 120a6e
  if (!m_name.empty()) os.child("name") << m_name;
Shinya Kitaoka 120a6e
  os.child("isOpened") << (int)m_isOpened;
Shinya Kitaoka 120a6e
  os.child("pos") << m_dagNodePos.x << m_dagNodePos.y;
Shinya Kitaoka 120a6e
  os.openChild("stroke");
Shinya Kitaoka 120a6e
  int n = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
  os << n;
Shinya Kitaoka 120a6e
  for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    TThickPoint p = stroke->getControlPoint(i);
Shinya Kitaoka 120a6e
    os << p.x << p.y << p.thick;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  os.closeChild();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::setId(int id) { m_id = id; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStageObjectSpline::getId() const { return m_id; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string TStageObjectSpline::getName() const {
Shinya Kitaoka 120a6e
  if (m_name == "") return "Path" + std::to_string(m_id + 1);
Shinya Kitaoka 120a6e
  return m_name;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
std::string TStageObjectSpline::getIconId() { return "spline" + m_idBase; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::addParam(TDoubleParam *param) {
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_posPathParams.size(); i++)
Shinya Kitaoka 120a6e
    if (param == m_posPathParams[i]) return;
Shinya Kitaoka 120a6e
  m_posPathParams.push_back(param);
Shinya Kitaoka 120a6e
  param->addRef();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStageObjectSpline::removeParam(TDoubleParam *param) {
Shinya Kitaoka 120a6e
  std::vector<tdoubleparam *="">::iterator it =</tdoubleparam>
Shinya Kitaoka 120a6e
      std::find(m_posPathParams.begin(), m_posPathParams.end(), param);
Shinya Kitaoka 120a6e
  if (it == m_posPathParams.end()) return;
Shinya Kitaoka 120a6e
  (*it)->release();
Shinya Kitaoka 120a6e
  m_posPathParams.erase(it);
Toshihiro Shimizu 890ddd
}