Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/**
Toshihiro Shimizu 890ddd
 * @author  Fabrizio Morciano <fabrizio.morciano@gmail.com></fabrizio.morciano@gmail.com>
Toshihiro Shimizu 890ddd
 */
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define _STLP_DEBUG 1
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "ext/StrokeDeformationImpl.h"
Toshihiro Shimizu 890ddd
#include "ext/StrokeDeformation.h"
Toshihiro Shimizu 890ddd
#include "ext/SquarePotential.h"
Toshihiro Shimizu 890ddd
#include "ext/StrokeParametricDeformer.h"
MCCCS a0ce32
//#include "ext/NotSymmetricBezierPotential.h"
Toshihiro Shimizu 890ddd
#include "ext/ContextStatus.h"
Toshihiro Shimizu 890ddd
#include "ext/Designer.h"
Toshihiro Shimizu 890ddd
//#include "ext/TriParam.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <tcurves.h></tcurves.h>
Toshihiro Shimizu 890ddd
#include <tstrokeutil.h></tstrokeutil.h>
Toshihiro Shimizu 890ddd
//#include <tvectorimage.h></tvectorimage.h>
Toshihiro Shimizu 890ddd
#include <tmathutil.h></tmathutil.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
#include <iterator></iterator>
Toshihiro Shimizu 890ddd
#include <vector></vector>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "DeformationSelector.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace ToonzExt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
   * Avoid to reduce curves with great zoom out.
Toshihiro Shimizu 890ddd
   * assert that pixelSize and factor > 0.0
Toshihiro Shimizu 890ddd
   */
Shinya Kitaoka 120a6e
double computeReductionFactor(double pixelSize, double factor) {
Shinya Kitaoka 120a6e
  assert(pixelSize > 0.0 && factor > 0.0);
Shinya Kitaoka 120a6e
  if (factor <= 0.0) factor                          = 1.0;
Shinya Kitaoka 120a6e
  if (pixelSize <= 0.0 || pixelSize > 1.0) pixelSize = 1.0;
Shinya Kitaoka 120a6e
  return pixelSize * factor;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
double retrieveParamAtLengthWithOffset(const TStroke *stroke2change,
Shinya Kitaoka 120a6e
                                       double length,  // = 0.5 * strokeLength,
Shinya Kitaoka 120a6e
                                       double offset) {
Shinya Kitaoka 120a6e
  if (!isValid(stroke2change) || !isValid(offset) || length < 0) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double strokeLength = stroke2change->getLength();
Shinya Kitaoka 120a6e
  assert(strokeLength >= 0.0 && "Not valid length");
Shinya Kitaoka 120a6e
  if (strokeLength < 0) {
Shinya Kitaoka 120a6e
    return -1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double lengthAtW = stroke2change->getLength(offset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(strokeLength >= lengthAtW &&
Shinya Kitaoka 120a6e
         "Position of parameter is greater than stroke length!!!");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (strokeLength < lengthAtW) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double newLength = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke2change->isSelfLoop()) {
Shinya Kitaoka 120a6e
    if (length >= 0)
Shinya Kitaoka 120a6e
      newLength = length > lengthAtW ? length + lengthAtW : lengthAtW - length;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    newLength = std::min(length + lengthAtW, strokeLength);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return stroke2change->getParameterAtLength(newLength);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool rotateStroke(const TStroke *stroke2change, TStroke *&rotated, double &from,
Shinya Kitaoka 120a6e
                  double &to, TPointD &old_w0_pos) {
Shinya Kitaoka 120a6e
  if (!stroke2change || !isValid(from) || !isValid(to)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rotated = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // save position of w=0 (useful to retrieve this
Shinya Kitaoka 120a6e
  //  position after changes)
Shinya Kitaoka 120a6e
  old_w0_pos = convert(stroke2change->getControlPoint(0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double rotateAtLength = stroke2change->getLength(to);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(rotateAtLength >= 0.0);
Shinya Kitaoka 120a6e
  if (rotateAtLength < 0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // TStroke*
Shinya Kitaoka 120a6e
  rotated = ToonzExt::rotateControlPoint(stroke2change, ToonzExt::EvenInt(0),
Shinya Kitaoka 120a6e
                                         rotateAtLength);
Shinya Kitaoka 120a6e
  if (!rotated) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  from = rotated->getW(stroke2change->getPoint(from));
Shinya Kitaoka 120a6e
  to   = rotated->getW(stroke2change->getPoint(to));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // save some other information (style, etc..)
Shinya Kitaoka 120a6e
  ToonzExt::cloneStrokeStatus(stroke2change, rotated);
Shinya Kitaoka 120a6e
  return true;  // rotated;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *rotateControlPointAtPoint(const TStroke *stroke, const TPointD &pnt) {
Shinya Kitaoka 120a6e
  if (!stroke || tdistance2(stroke->getPoint(0.0), pnt) < sq(TConsts::epsilon))
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double w           = stroke->getW(pnt);
Shinya Kitaoka 120a6e
  TPointD theSamePnt = stroke->getPoint(w);
Shinya Kitaoka 120a6e
  double length      = stroke->getLength(w);
Shinya Kitaoka 120a6e
  return ToonzExt::rotateControlPoint(stroke, ToonzExt::EvenInt(0), length);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool findExtremesFromActionLength(double toolActionLength,
Shinya Kitaoka 120a6e
                                  const TStroke *stroke, double w,
Shinya Kitaoka 120a6e
                                  ToonzExt::Interval &out) {
Shinya Kitaoka 120a6e
  out = ToonzExt::Interval(-1.0, -1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!stroke || 0.0 > w || w > 1.0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double emiToolSize   = 0.5 * toolActionLength;
Shinya Kitaoka 120a6e
  double strokelength  = stroke->getLength();
Shinya Kitaoka 120a6e
  double lengthAtParam = stroke->getLength(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(emiToolSize >= 0.0 && strokelength >= 0.0 && lengthAtParam >= 0.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (emiToolSize > strokelength * 0.5) {
Shinya Kitaoka 120a6e
    if (stroke->isSelfLoop()) {
Shinya Kitaoka 120a6e
      emiToolSize = strokelength * 0.5;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // first and second are the same
Shinya Kitaoka 120a6e
      lengthAtParam += emiToolSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (lengthAtParam > strokelength) lengthAtParam -= strokelength;
Shinya Kitaoka 120a6e
      out.first = out.second = stroke->getParameterAtLength(lengthAtParam);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      out.first  = 0.0;
Shinya Kitaoka 120a6e
      out.second = 1.0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (emiToolSize < 0.0 || strokelength < 0.0 || lengthAtParam < 0.0)
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // [out] now is length, range 0,length
Shinya Kitaoka 120a6e
  out.first  = lengthAtParam - emiToolSize;
Shinya Kitaoka 120a6e
  out.second = lengthAtParam + emiToolSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop()) {
Shinya Kitaoka 120a6e
    if (out.first < 0.0) {
Shinya Kitaoka 120a6e
      out.first = strokelength + out.first;
Shinya Kitaoka 120a6e
      assert(out.first < strokelength);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (out.second > strokelength) {
Shinya Kitaoka 120a6e
      out.second = out.second - strokelength;
Shinya Kitaoka 120a6e
      assert(0.0 < out.second && out.second < strokelength);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    out.first  = std::max(out.first, 0.0);
Shinya Kitaoka 120a6e
    out.second = std::min(out.second, strokelength);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // [out] now is parameter, range 0,1
Shinya Kitaoka 120a6e
  out.first  = stroke->getParameterAtLength(out.first);
Shinya Kitaoka 120a6e
  out.second = stroke->getParameterAtLength(out.second);
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
  if (!stroke->isSelfLoop()) assert(out.first <= out.second);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool areDifferent(const TStroke *ref1, const TStroke *ref2) {
Shinya Kitaoka 120a6e
  if (!isValid(ref1) || !isValid(ref2)) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int cpCount1 = ref1->getControlPointCount();
Shinya Kitaoka 120a6e
  int cpCount2 = ref2->getControlPointCount();
Shinya Kitaoka 120a6e
  if (cpCount1 != cpCount2) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (--cpCount1 >= 0) {
Shinya Kitaoka 120a6e
    if (ref1->getControlPoint(cpCount1) != ref2->getControlPoint(cpCount1))
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  assert(cpCount1 == -1);
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *StrokeDeformationImpl::copyOfLastSelectedStroke_ =
Shinya Kitaoka 120a6e
    0;  // deep copy stroke selected previously
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const ContextStatus *&StrokeDeformationImpl::getImplStatus() {
Shinya Kitaoka 120a6e
  // if multi threading this datas need to be serialized
Shinya Kitaoka 120a6e
  // a ref to status
Shinya Kitaoka 120a6e
  static const ContextStatus *contextStatus_instance;
Shinya Kitaoka 120a6e
  return contextStatus_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *&StrokeDeformationImpl::getLastSelectedStroke() {
Shinya Kitaoka 120a6e
  static TStroke *lastSelectedStroke_instance;
Shinya Kitaoka 120a6e
  return lastSelectedStroke_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::setLastSelectedStroke(TStroke *stroke) {
Shinya Kitaoka 120a6e
  TStroke *&lastSelStroke = getLastSelectedStroke();
Shinya Kitaoka 120a6e
  lastSelStroke           = stroke;
Shinya Kitaoka 120a6e
  if (lastSelStroke) {
Shinya Kitaoka 120a6e
    delete copyOfLastSelectedStroke_;
Shinya Kitaoka 120a6e
    copyOfLastSelectedStroke_ = new TStroke(*lastSelStroke);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int &StrokeDeformationImpl::getLastSelectedDegree() {
Shinya Kitaoka 120a6e
  static int lastSelectedDegree_instance;
Shinya Kitaoka 120a6e
  return lastSelectedDegree_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::setLastSelectedDegree(int degree) {
Shinya Kitaoka 120a6e
  getLastSelectedDegree() = degree;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToonzExt::Intervals &StrokeDeformationImpl::getSpiresList() {
Shinya Kitaoka 120a6e
  static ToonzExt::Intervals listOfSpire_instance;
Shinya Kitaoka 120a6e
  return listOfSpire_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToonzExt::Intervals &StrokeDeformationImpl::getStraightsList() {
Shinya Kitaoka 120a6e
  static ToonzExt::Intervals listOfStraight_instance;
Shinya Kitaoka 120a6e
  return listOfStraight_instance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
StrokeDeformationImpl::StrokeDeformationImpl() {
Shinya Kitaoka 120a6e
  shortcutKey_ = ContextStatus::NONE;
Shinya Kitaoka 120a6e
  cursorId_    = -1;
Shinya Kitaoka 120a6e
  this->reset();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
StrokeDeformationImpl::~StrokeDeformationImpl() {
Shinya Kitaoka 120a6e
  clearPointerContainer(strokes_);
Shinya Kitaoka 120a6e
  delete potential_;
Shinya Kitaoka 120a6e
  potential_ = 0;
Shinya Kitaoka 120a6e
  delete deformer_;
Shinya Kitaoka 120a6e
  deformer_ = 0;
Shinya Kitaoka 120a6e
  delete copyOfLastSelectedStroke_;
Shinya Kitaoka 120a6e
  copyOfLastSelectedStroke_ = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool StrokeDeformationImpl::activate_impl(const ContextStatus *status) {
Shinya Kitaoka 120a6e
  assert(status && "Not status available");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!status || !this->init(status)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double w = status->w_;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Interval extremes = this->getExtremes();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStroke *stroke2transform;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!this->computeStroke2Transform(status, stroke2transform, w, extremes))
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // to avoid strange behaviour in limit's value
Shinya Kitaoka 120a6e
  if (areAlmostEqual(extremes.first, w)) w = extremes.first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (areAlmostEqual(extremes.second, w)) w = extremes.second;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(extremes.first <= w && w <= extremes.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (extremes.first > w || w > extremes.second) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> splitParameter;</double>
Shinya Kitaoka 120a6e
  splitParameter.push_back(extremes.first);
Shinya Kitaoka 120a6e
  splitParameter.push_back(extremes.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(strokes_.empty());
Shinya Kitaoka 120a6e
  if (!strokes_.empty()) clearPointerContainer(strokes_);
Shinya Kitaoka 120a6e
  splitStroke(*stroke2transform, splitParameter, strokes_);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(strokes_.size() == 3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // I don't know how to manage properly this case
Shinya Kitaoka 120a6e
  if (strokes_.size() != 3) {
Shinya Kitaoka 120a6e
    clearPointerContainer(strokes_);
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // stroke to change
Shinya Kitaoka 120a6e
  stroke2manipulate_ = strokes_[1];
Shinya Kitaoka 120a6e
  assert(stroke2manipulate_ && " Not valid reference to stroke to move!!!");
Shinya Kitaoka 120a6e
  if (!stroke2manipulate_) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // remove empty stroke
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    TStroke *tmp_stroke = strokes_[2];
Shinya Kitaoka 120a6e
    if (isAlmostZero(tmp_stroke->getLength())) {
Shinya Kitaoka 120a6e
      std::vector<tstroke *="">::iterator it = strokes_.begin();</tstroke>
Shinya Kitaoka 120a6e
      std::advance(it, 2);
Shinya Kitaoka 120a6e
      strokes_.erase(it);
Shinya Kitaoka 120a6e
      delete tmp_stroke;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tmp_stroke = strokes_[0];
Shinya Kitaoka 120a6e
    if (isAlmostZero(tmp_stroke->getLength())) {
Shinya Kitaoka 120a6e
      strokes_.erase(strokes_.begin());
Shinya Kitaoka 120a6e
      delete tmp_stroke;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // little movement of control points to have not empty
Shinya Kitaoka 120a6e
    //  length
Shinya Kitaoka 120a6e
    if (isAlmostZero(stroke2manipulate_->getLength())) {
Shinya Kitaoka 120a6e
      int count = stroke2manipulate_->getControlPointCount() - 1;
Shinya Kitaoka 120a6e
      assert(count > 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TThickPoint pnt0  = stroke2manipulate_->getControlPoint(0),
Shinya Kitaoka 120a6e
                  pntn  = stroke2manipulate_->getControlPoint(count),
Shinya Kitaoka 120a6e
                  delta = TThickPoint(2.0 * TConsts::epsilon,
Shinya Kitaoka 120a6e
                                      -2.0 * TConsts::epsilon, 0.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      stroke2manipulate_->setControlPoint(0, pnt0 - delta);
Shinya Kitaoka 120a6e
      stroke2manipulate_->setControlPoint(count, pntn + delta);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // simple check for empty chunk
Shinya Kitaoka 120a6e
  int cp_count = stroke2manipulate_->getChunkCount();
Shinya Kitaoka 120a6e
  const TThickQuadratic *tq;
Shinya Kitaoka 120a6e
  bool haveEmpty = false;
Shinya Kitaoka 120a6e
  while (--cp_count >= 0) {
Shinya Kitaoka 120a6e
    tq = stroke2manipulate_->getChunk(cp_count);
Shinya Kitaoka 120a6e
    //    assert( tq->getLength() != 0.0 );
Shinya Kitaoka 120a6e
    if (tq->getLength() == 0.0) haveEmpty = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (haveEmpty) {
Shinya Kitaoka 120a6e
    const double reductionFactor =
Shinya Kitaoka 120a6e
        computeReductionFactor(getImplStatus()->pixelSize_, 1.0);
Shinya Kitaoka 120a6e
    stroke2manipulate_->reduceControlPoints(reductionFactor);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD pntOnStroke = stroke2transform->getPoint(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // parameter need to be recomputed to match
Shinya Kitaoka 120a6e
  // with new stroke
Shinya Kitaoka 120a6e
  w = stroke2manipulate_->getW(pntOnStroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  prevStyle_ = stroke2transform->getStyle();
Shinya Kitaoka 120a6e
  //  set a style for error
Shinya Kitaoka 120a6e
  //  stroke2manipulate_->setStyle( 4 );
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // in this deformer all stroke need to be moved
Shinya Kitaoka 120a6e
  double lengthOfAction = this->findActionLength();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool exception = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    // create a new stroke deformer
Shinya Kitaoka 120a6e
    delete deformer_;
Shinya Kitaoka 120a6e
    deformer_ = new StrokeParametricDeformer(
Shinya Kitaoka 120a6e
        lengthOfAction, w, stroke2manipulate_, potential_->clone());
Shinya Kitaoka 120a6e
  } catch (std::invalid_argument &) {
Shinya Kitaoka 120a6e
    exception = true;
Shinya Kitaoka 120a6e
    assert(!"Invalid argument");
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
    exception = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(deformer_ && "Deformer is not available");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (exception) {
Shinya Kitaoka 120a6e
    deformer_ = 0;
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(getImplStatus() != 0 && "ContextStatus is null???");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!getImplStatus()) {
Shinya Kitaoka 120a6e
    delete deformer_;
Shinya Kitaoka 120a6e
    this->reset();
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // change the threshold value of increser,
Shinya Kitaoka 120a6e
  //  if value is greater than diff add control points
Campbell Barton f49389
  deformer_->setDiff(getImplStatus()->deformerSensitivity_);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // just to be sure to have a control point where
Shinya Kitaoka 120a6e
  // stroke is selected
Shinya Kitaoka 120a6e
  stroke2manipulate_->insertControlPoints(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  two different case:
Shinya Kitaoka 120a6e
  //  (1) point at w=0 is not in stroke to transform
Shinya Kitaoka 120a6e
  //  (2) point at w=0 is in stroke to transform
Shinya Kitaoka 120a6e
  //  in case (2) it is mandatory to retrieve the
Shinya Kitaoka 120a6e
  //  parameter where stroke2transform is equal to
Shinya Kitaoka 120a6e
  //  w=0 and store it.
Shinya Kitaoka 120a6e
  //  old_w0_pos_ will be used in deactivate method
Shinya Kitaoka 120a6e
  if (old_w0_pos_ != TConsts::napd) {
Shinya Kitaoka 120a6e
    double w    = stroke2manipulate_->getW(old_w0_pos_);
Shinya Kitaoka 120a6e
    TPointD pnt = stroke2manipulate_->getPoint(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (tdistance2(pnt, old_w0_pos_) < sq(TConsts::epsilon)) {
Shinya Kitaoka 120a6e
      // the this position can be modifyed during drag
Shinya Kitaoka 120a6e
      old_w0_ = w;
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      old_w0_ = -1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool test = increaseControlPoints(*stroke2manipulate_, *deformer_,
Shinya Kitaoka 120a6e
                                    getImplStatus()->pixelSize_);
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
// New Increaser behaviour
Shinya Kitaoka 120a6e
deformer_->setMouseMove(0,100);
Shinya Kitaoka 120a6e
extremes_ = Toonz::increase_cp (stroke2manipulate_,
Shinya Kitaoka 120a6e
deformer_);
Shinya Kitaoka 120a6e
//*/
Shinya Kitaoka 120a6e
  if (!test) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  stroke2manipulate_->disableComputeOfCaches();
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::update_impl(const TPointD &delta) {
Shinya Kitaoka 120a6e
  assert(stroke2manipulate_ && deformer_ &&
Shinya Kitaoka 120a6e
         "Stroke and Deformer are available");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!stroke2manipulate_ || !deformer_) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // update delta in deformer
Shinya Kitaoka 120a6e
  deformer_->setMouseMove(delta.x, delta.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  modifyControlPoints(*stroke2manipulate_, *deformer_);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *StrokeDeformationImpl::deactivate_impl() {
Shinya Kitaoka 120a6e
  if (!stroke2manipulate_ || !getImplStatus()) {
Shinya Kitaoka 120a6e
    this->reset();
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // retrieve the point
Shinya Kitaoka 120a6e
  if (old_w0_ != -1) old_w0_pos_ = stroke2manipulate_->getPoint(old_w0_);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const double reductionFactor =
Shinya Kitaoka 120a6e
      computeReductionFactor(getImplStatus()->pixelSize_, 3.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // stroke2manipulate_->enableComputeOfCaches ();
Shinya Kitaoka 120a6e
  // stroke2manipulate_->reduceControlPoints (reductionFactor);
Shinya Kitaoka 120a6e
  const int size = stroke2manipulate_->getControlPointCount();
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> pnt(size);</tthickpoint>
Shinya Kitaoka 120a6e
  for (int i = 0; i < size; ++i)
Shinya Kitaoka 120a6e
    pnt[i]   = stroke2manipulate_->getControlPoint(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tstroke *="">::iterator it =</tstroke>
Shinya Kitaoka 120a6e
      std::find(strokes_.begin(), strokes_.end(), stroke2manipulate_);
Shinya Kitaoka 120a6e
  assert(it != strokes_.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int pos            = std::distance(strokes_.begin(), it);
Shinya Kitaoka 120a6e
  stroke2manipulate_ = 0;
Shinya Kitaoka 120a6e
  delete strokes_[pos];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStroke *tmpStroke = new TStroke(pnt);
Shinya Kitaoka 120a6e
  assert((tmpStroke != 0) && "Not valid stroke!");
Shinya Kitaoka 120a6e
  strokes_[pos] = tmpStroke;
Shinya Kitaoka 120a6e
  strokes_[pos]->reduceControlPoints(reductionFactor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // strokes_[pos] = TStroke::interpolate(pnt,
Shinya Kitaoka 120a6e
  //                                   reductionFactor,
Shinya Kitaoka 120a6e
  //                                   false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStroke *ref = Toonz::merge(strokes_);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::cloneStrokeStatus(getImplStatus()->stroke2change_, ref);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (old_w0_pos_ != TConsts::napd) {
Shinya Kitaoka 120a6e
    // restore (if necessary) the initial position of
Shinya Kitaoka 120a6e
    // a stroke
Shinya Kitaoka 120a6e
    TStroke *rotated = rotateControlPointAtPoint(ref, old_w0_pos_);
Shinya Kitaoka 120a6e
    if (rotated) {
Shinya Kitaoka 120a6e
      delete ref;
Shinya Kitaoka 120a6e
      ref = rotated;
Shinya Kitaoka 120a6e
      if (getImplStatus())
Shinya Kitaoka 120a6e
        ToonzExt::cloneStrokeStatus(getImplStatus()->stroke2change_, ref);
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        delete ref;
Shinya Kitaoka 120a6e
        ref = 0;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  this->reset();
Shinya Kitaoka 120a6e
  return ref;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::reset() {
Shinya Kitaoka 120a6e
  old_w0_     = -1;
Shinya Kitaoka 120a6e
  old_w0_pos_ = TConsts::napd;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  deformer_       = 0;
Shinya Kitaoka 120a6e
  getImplStatus() = 0;
Shinya Kitaoka 120a6e
  this->setLastSelectedDegree(-1);
Shinya Kitaoka 120a6e
  this->setLastSelectedStroke(0);
Shinya Kitaoka 120a6e
  this->getSpiresList().clear();
Shinya Kitaoka 120a6e
  this->getStraightsList().clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  stroke2manipulate_ = 0;
Shinya Kitaoka 120a6e
  clearPointerContainer(strokes_);  // stroke2move is deleted here (it
Shinya Kitaoka 120a6e
                                    // is in vector)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *StrokeDeformationImpl::getTransformedStroke() {
Shinya Kitaoka 120a6e
  return this->stroke2manipulate_;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToonzExt::Potential *StrokeDeformationImpl::getPotential() {
Shinya Kitaoka 120a6e
  return this->potential_;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::draw(Designer *designer) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void StrokeDeformationImpl::setPotential(Potential *potential) {
Shinya Kitaoka 120a6e
  assert(potential);
Shinya Kitaoka 120a6e
  potential_ = potential;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool StrokeDeformationImpl::check(const ContextStatus *status) {
Shinya Kitaoka 120a6e
  if (!status || !this->init(status)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return this->check_(status);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPointD &StrokeDeformationImpl::oldW0() { return old_w0_pos_; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ToonzExt::Interval StrokeDeformationImpl::getExtremes() {
Shinya Kitaoka 120a6e
  ToonzExt::Interval extremes = ToonzExt::Interval(-1.0, -1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!getImplStatus()) return extremes;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // if it is manual
Shinya Kitaoka 120a6e
  if (getImplStatus()->isManual_ == true) {
Shinya Kitaoka 120a6e
    findExtremesFromActionLength(getImplStatus()->lengthOfAction_,
Shinya Kitaoka 120a6e
                                 getImplStatus()->stroke2change_,
Shinya Kitaoka 120a6e
                                 getImplStatus()->w_, extremes);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // if there are some special key down all will be managed in deformation
Shinya Kitaoka 120a6e
    this->findExtremes_(getImplStatus(), extremes);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return extremes;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool StrokeDeformationImpl::init(const ContextStatus *status) {
Shinya Kitaoka 120a6e
  if (!status || !isValid(status->stroke2change_) || !isValid(status->w_)) {
Shinya Kitaoka 120a6e
    this->reset();
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  getImplStatus() = status;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!this->getLastSelectedStroke() ||
Shinya Kitaoka 120a6e
      this->getLastSelectedStroke() != status->stroke2change_ ||
Shinya Kitaoka 120a6e
      areDifferent(copyOfLastSelectedStroke_, status->stroke2change_) ||
Shinya Kitaoka 120a6e
      (this->getLastSelectedDegree() == -1) ||
Shinya Kitaoka 120a6e
      (this->getLastSelectedDegree() != status->cornerSize_)) {
Shinya Kitaoka 120a6e
    this->getSpiresList().clear();
Shinya Kitaoka 120a6e
    this->getStraightsList().clear();
Shinya Kitaoka 120a6e
    // recompute cache
Shinya Kitaoka 120a6e
    ToonzExt::findCorners(status->stroke2change_, this->getSpiresList(),
Shinya Kitaoka 120a6e
                          this->getStraightsList(), status->cornerSize_,
Shinya Kitaoka 120a6e
                          TConsts::epsilon);
Shinya Kitaoka 120a6e
    this->setLastSelectedStroke(status->stroke2change_);
Shinya Kitaoka 120a6e
    this->setLastSelectedDegree(status->cornerSize_);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool StrokeDeformationImpl::computeStroke2Transform(
Shinya Kitaoka 120a6e
    const ContextStatus *status, TStroke *&stroke2transform, double &w,
Shinya Kitaoka 120a6e
    ToonzExt::Interval &extremes) {
Shinya Kitaoka 120a6e
  if (!status || !isValid(w)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  stroke2transform = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (status->stroke2change_->isSelfLoop()) {
Shinya Kitaoka 120a6e
    if (extremes.first > extremes.second) {
Shinya Kitaoka 120a6e
      double new_w = (extremes.first + extremes.second) * 0.5;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!rotateStroke(status->stroke2change_, stroke2transform, w, new_w,
Shinya Kitaoka 120a6e
                        old_w0_pos_))
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ContextStatus tmpStatus  = *status;
Shinya Kitaoka 120a6e
      tmpStatus.stroke2change_ = stroke2transform;
Shinya Kitaoka 120a6e
      tmpStatus.w_             = w;
Shinya Kitaoka 120a6e
      this->check(&tmpStatus);
Shinya Kitaoka 120a6e
      extremes = this->getExtremes();
Shinya Kitaoka 120a6e
      this->init(status);
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    } else if (extremes.first == extremes.second) {
Shinya Kitaoka 120a6e
      double positionOfFixPoint = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // there are two different cases
Shinya Kitaoka 120a6e
      //  a) only one corner
Shinya Kitaoka 120a6e
      //  b) only two corners
Shinya Kitaoka 120a6e
      switch (this->getSpiresList().size()) {
Shinya Kitaoka 120a6e
      case 0:
Shinya Kitaoka 120a6e
        assert(extremes.first == -1);
Shinya Kitaoka 120a6e
        positionOfFixPoint = retrieveParamAtLengthWithOffset(
Shinya Kitaoka 120a6e
            status->stroke2change_, status->stroke2change_->getLength() * 0.5,
Shinya Kitaoka 120a6e
            w);
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 1:
Shinya Kitaoka 120a6e
        if (extremes.first != -1)
Shinya Kitaoka 120a6e
          positionOfFixPoint = retrieveParamAtLengthWithOffset(
Shinya Kitaoka 120a6e
              status->stroke2change_, status->stroke2change_->getLength() * 0.5,
Shinya Kitaoka 120a6e
              w);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          positionOfFixPoint = this->getSpiresList()[0].first;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      case 2:
Shinya Kitaoka 120a6e
      // also forced mode
Shinya Kitaoka 120a6e
      default:
Shinya Kitaoka 120a6e
        assert(extremes.first != -1);
Shinya Kitaoka 120a6e
        // if( extremes.first == -1 )
Shinya Kitaoka 120a6e
        //  positionOfFixPoint=retrieveParamAtLengthWithOffset(status->stroke2change_,
Shinya Kitaoka 120a6e
        //                                                     status->stroke2change_->getLength()*0.5,
Shinya Kitaoka 120a6e
        //                                                     w);
Shinya Kitaoka 120a6e
        // else
Shinya Kitaoka 120a6e
        positionOfFixPoint = extremes.first;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!rotateStroke(status->stroke2change_, stroke2transform, w,
Shinya Kitaoka 120a6e
                        positionOfFixPoint, old_w0_pos_))
Shinya Kitaoka 120a6e
        return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      extremes = ToonzExt::Interval(0.0, 1.0);
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isValid(extremes.first) || !isValid(extremes.second)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  try {
Shinya Kitaoka 120a6e
    if (!stroke2transform)
Shinya Kitaoka 120a6e
      stroke2transform = new TStroke(*status->stroke2change_);
Shinya Kitaoka 120a6e
  } catch (...) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  End Of File
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------