Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "tsimplecolorstyles.h"
Toshihiro Shimizu 890ddd
#include "tstrokeoutline.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int MY_ERROR = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// Iron
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// index must be between 0 and controlPointCount-1
Shinya Kitaoka 120a6e
inline bool isIncluded(int index, int left, int rigth) {
Shinya Kitaoka 120a6e
  if (left < rigth) {
Shinya Kitaoka 120a6e
    return left <= index && index <= rigth;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    return left <= index || index <= rigth;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// IronTool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class IronTool : public TTool {
Shinya Kitaoka 120a6e
  TStroke *m_strokeRef, *m_oldStroke;
Shinya Kitaoka 120a6e
  TUndo *m_undo;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DoublePair m_range;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_draw;
Shinya Kitaoka 120a6e
  bool m_dragged;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThickPoint m_cursor;
Shinya Kitaoka 120a6e
  int m_selectedStroke;
Shinya Kitaoka 120a6e
  TPointD m_beginPoint;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m_cpIndexMin, m_cpIndexMax;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_active;
Shinya Kitaoka 120a6e
  int m_cursorId;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  IronTool()
Shinya Kitaoka 120a6e
      : TTool("T_Iron")
Shinya Kitaoka 120a6e
      , m_strokeRef(0)
Shinya Kitaoka 120a6e
      , m_draw(false)
Shinya Kitaoka 120a6e
      , m_active(false)
Shinya Kitaoka 120a6e
      , m_dragged(false)
Shinya Kitaoka 120a6e
      , m_undo(0)
Shinya Kitaoka 120a6e
      , m_cpIndexMin(-1)
Shinya Kitaoka 120a6e
      , m_cpIndexMax(-1)
Shinya Kitaoka 120a6e
      , m_oldStroke(0)
Shinya Kitaoka 120a6e
      , m_cursorId(ToolCursor::IronCursor) {
Shinya Kitaoka 120a6e
    bind(TTool::Vectors);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  ToolType getToolType() const override { return TTool::LevelWriteTool; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void draw() override {
Shinya Kitaoka 120a6e
    if (m_draw && (TVectorImageP)getImage(false)) {
Shinya Kitaoka 120a6e
      glColor3d(1, 0, 1);
Shinya Kitaoka 120a6e
      if (m_cursor.thick > 0) tglDrawCircle(m_cursor, m_cursor.thick);
Shinya Kitaoka 120a6e
      tglDrawCircle(m_cursor, m_cursor.thick + 4 * getPixelSize());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonDown(const TPointD &pos, const TMouseEvent &) override {
Shinya Kitaoka 120a6e
    if (m_active) return;
Shinya Kitaoka 120a6e
    assert(m_undo == 0);
Shinya Kitaoka 120a6e
    m_active = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // select nearest stroke and finds its parameter
Shinya Kitaoka 120a6e
    double dist;
Shinya Kitaoka 120a6e
    UINT stroke;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!vi->getNearestStroke(pos, m_range.first, stroke, dist)) {
Shinya Kitaoka 120a6e
      m_strokeRef      = 0;
Shinya Kitaoka 120a6e
      m_selectedStroke = MY_ERROR;
Shinya Kitaoka 120a6e
      m_draw           = false;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_draw           = true;
Shinya Kitaoka 120a6e
      m_active         = true;
Shinya Kitaoka 120a6e
      m_strokeRef      = vi->getStroke(stroke);
Shinya Kitaoka 120a6e
      m_selectedStroke = stroke;
Shinya Kitaoka 120a6e
      m_beginPoint     = m_strokeRef->getPoint(m_range.first);
Shinya Kitaoka 120a6e
      m_oldStroke      = new TStroke(*vi->getStroke(stroke));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_range.second = m_range.first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (TTool::getApplication()->getCurrentObject()->isSpline())
Shinya Kitaoka 120a6e
        m_undo = new UndoPath(
Shinya Kitaoka 120a6e
            getXsheet()->getStageObject(getObjectId())->getSpline());
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        TXshSimpleLevel *sl =
Shinya Kitaoka 120a6e
            TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
        assert(sl);
Shinya Kitaoka 120a6e
        TFrameId id = getCurrentFid();
Shinya Kitaoka 120a6e
        m_undo      = new UndoModifyStrokeAndPaint(sl, id, stroke);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_strokeRef) m_cpIndexMin = m_strokeRef->getControlPointCount();
Shinya Kitaoka 120a6e
    m_cpIndexMax                  = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override {
Shinya Kitaoka 120a6e
    TVectorImageP vi(getImage(true));
Shinya Kitaoka 120a6e
    if (!m_active || !vi || !m_strokeRef) {
Shinya Kitaoka 120a6e
      delete m_undo;
Shinya Kitaoka 120a6e
      m_undo = 0;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_range.second = m_strokeRef->getW(pos);
Shinya Kitaoka 120a6e
    m_cursor       = m_strokeRef->getThickPoint(m_range.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double v0        = std::min(m_range.first, m_range.second);
Shinya Kitaoka 120a6e
    double v1        = std::max(m_range.first, m_range.second);
Shinya Kitaoka 120a6e
    const double eps = 0.005;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (v1 - v0 < eps && !(m_strokeRef->isSelfLoop() && 1 - (v1 - v0) < eps)) {
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD point2 = m_strokeRef->getPoint(m_range.second);
Shinya Kitaoka 120a6e
    double tdist2  = tdistance2(m_beginPoint, point2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
    if (tdist2 < 100 * pixelSize * pixelSize) {
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double draggedStrokeLen = m_strokeRef->getLength(v0, v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double totalStrokeLen = m_strokeRef->getLength();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool direction = !m_strokeRef->isSelfLoop() ||
Shinya Kitaoka 120a6e
                     draggedStrokeLen < totalStrokeLen - draggedStrokeLen;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!direction) {
Shinya Kitaoka 120a6e
      draggedStrokeLen = totalStrokeLen - draggedStrokeLen;
Shinya Kitaoka 120a6e
      tswap(v0, v1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // se la lunghezza della parte di stroke tra i due punti di inizio e fine
Shinya Kitaoka 120a6e
    // drag
Shinya Kitaoka 120a6e
    // e' piu' del quadruplo della distanza tra i due punti, allora non si fa
Shinya Kitaoka 120a6e
    // nulla perche'
Shinya Kitaoka 120a6e
    // molto probabilmente si sta facendo drag tra due punti vicini di una curva
Shinya Kitaoka 120a6e
    // piu' lunga
Shinya Kitaoka 120a6e
    if ((draggedStrokeLen * draggedStrokeLen) > 16.0 * tdist2) {
Shinya Kitaoka 120a6e
      m_beginPoint = point2;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    int maxCP = m_strokeRef->getControlPointCount() - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // iCP0 is the control point index before v0 (or just on v0)
Shinya Kitaoka 120a6e
    int iCP0 = (int)(maxCP * v0);
Shinya Kitaoka 120a6e
    int iCP1 = m_strokeRef->getControlPointIndexAfterParameter(v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (iCP0 > maxCP) {
Shinya Kitaoka 120a6e
      if (!direction)
Shinya Kitaoka 120a6e
        iCP0 = maxCP;
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        invalidate();
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (iCP1 > maxCP) iCP1 = maxCP;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (direction && (iCP1 - iCP0) < 2) {
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!direction && maxCP + 1 - (iCP1 - iCP0) < 3) {
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //*********************************************** point of no return
Shinya Kitaoka 120a6e
    //**************************
Shinya Kitaoka 120a6e
    m_dragged    = true;
Shinya Kitaoka 120a6e
    m_beginPoint = point2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_strokeRef->isSelfLoop()) {
Shinya Kitaoka 120a6e
      if (m_cpIndexMin > iCP0) m_cpIndexMin = iCP0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_cpIndexMax < iCP1) m_cpIndexMax = iCP1;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (m_cpIndexMin == m_strokeRef->getControlPointCount() &&
Shinya Kitaoka 120a6e
          m_cpIndexMax == -1) {
Shinya Kitaoka 120a6e
        m_cpIndexMin = iCP0;
Shinya Kitaoka 120a6e
        m_cpIndexMax = iCP1;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (isIncluded(iCP0, m_cpIndexMin, m_cpIndexMax)) {
Shinya Kitaoka 120a6e
          if (!isIncluded(iCP1, m_cpIndexMin, m_cpIndexMax)) {
Shinya Kitaoka 120a6e
            m_cpIndexMax = iCP1;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else if (isIncluded(iCP1, m_cpIndexMin, m_cpIndexMax)) {
Shinya Kitaoka 120a6e
          assert(!isIncluded(iCP0, m_cpIndexMin, m_cpIndexMax));
Shinya Kitaoka 120a6e
          m_cpIndexMin = iCP0;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          int sgn             = tsign(m_range.second - m_range.first);
Shinya Kitaoka 120a6e
          if (!direction) sgn = -sgn;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          switch (sgn) {
Shinya Kitaoka 120a6e
          case 1:
Shinya Kitaoka 120a6e
            m_cpIndexMax = iCP1;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case -1:
Shinya Kitaoka 120a6e
            m_cpIndexMin = iCP0;
Shinya Kitaoka 120a6e
            break;
Shinya Kitaoka 120a6e
          case 0:
Shinya Kitaoka 120a6e
            assert(0);
Shinya Kitaoka 120a6e
          default:
Shinya Kitaoka 120a6e
            assert(0);
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_range.first = m_range.second;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(m_cpIndexMin != m_cpIndexMax);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    v0 = m_strokeRef->getParameterAtControlPoint(iCP0);
Shinya Kitaoka 120a6e
    v1 = m_strokeRef->getParameterAtControlPoint(iCP1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // double smoothFactor =
Shinya Kitaoka 120a6e
    // getApplication()->getVectorToolsParameters().getToolSize();
Shinya Kitaoka 120a6e
    // smoothFactor *= 0.01;
Shinya Kitaoka 120a6e
    // smoothFactor = (smoothFactor*smoothFactor*smoothFactor)*0.7;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const double smoothFactor = 0.08;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double wDistance = (direction) ? v1 - v0 : 1 - (v0 - v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double smoothFP = smoothFactor / wDistance;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD pf0 = m_strokeRef->getControlPoint(iCP0) * smoothFP;
Shinya Kitaoka 120a6e
    TPointD pf1 = m_strokeRef->getControlPoint(iCP1) * smoothFP;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD appDPoint;
Shinya Kitaoka 120a6e
    TThickPoint appThickPoint;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double oppSmoothFactor = 1.0 - smoothFactor;
Shinya Kitaoka 120a6e
    double vp, v1vp, vpv0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    i = (iCP0 == maxCP || (iCP0 == 0 && !direction)) ? 1 : iCP0 + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (; i != iCP1;) {
Shinya Kitaoka 120a6e
      vp = m_strokeRef->getParameterAtControlPoint(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      appThickPoint = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
      appDPoint     = appThickPoint;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      v1vp = v1 - vp;
Shinya Kitaoka 120a6e
      if (v1vp < 0) {
Shinya Kitaoka 120a6e
        if (!direction)
Shinya Kitaoka 120a6e
          v1vp += 1;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          assert(0);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      vpv0 = vp - v0;
Shinya Kitaoka 120a6e
      if (vpv0 < 0) {
Shinya Kitaoka 120a6e
        if (!direction)
Shinya Kitaoka 120a6e
          vpv0 += 1;
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          assert(0);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert(isAlmostZero(v1vp + vpv0 - wDistance));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert(isAlmostZero((smoothFP * v1vp + smoothFP * vpv0) +
Shinya Kitaoka 120a6e
                          oppSmoothFactor - 1.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_strokeRef->setControlPoint(
Shinya Kitaoka 120a6e
          i, TThickPoint(pf0 * v1vp + pf1 * vpv0 + appDPoint * oppSmoothFactor,
Shinya Kitaoka 120a6e
                         appThickPoint.thick));
Shinya Kitaoka 120a6e
      // this is like
Shinya Kitaoka 120a6e
      //
Shinya Kitaoka 120a6e
      // averageP = ( p0*(v1-vp)/(v1-v0) + p1*(vp-v0)/(v1-v0));
Shinya Kitaoka 120a6e
      // newCP(i) = oldCP(i)*(1-smoothFactor) + averageP*smoothFactor
Shinya Kitaoka 120a6e
      //
Shinya Kitaoka 120a6e
      // but faster
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      if (i == maxCP + 1) {
Shinya Kitaoka 120a6e
        m_strokeRef->setControlPoint(0, m_strokeRef->getControlPoint(maxCP));
Shinya Kitaoka 120a6e
        i = 1;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_strokeRef->invalidate();
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonUp(const TPointD &pos, const TMouseEvent &) override {
Shinya Kitaoka 120a6e
    if (!m_active) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_active = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TVectorImageP vi(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi || !m_strokeRef || !m_dragged) {
Shinya Kitaoka 120a6e
      delete m_undo;
Shinya Kitaoka 120a6e
      m_undo = 0;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    QMutexLocker lock(vi->getMutex());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // TStroke *oldStroke = new TStroke(*(vi->getStroke(m_selectedStroke)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //------------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT cpCount = m_strokeRef->getControlPointCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_cpIndexMin &= ~1;  // nearest even value less or equal to m_cpIndexMin
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_cpIndexMax & 1)  // odd
Shinya Kitaoka 120a6e
      m_cpIndexMax++;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i      = 0;
Shinya Kitaoka 120a6e
    UINT count = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if ((m_cpIndexMin == 0 && (UINT)m_cpIndexMax == cpCount - 1) ||
Shinya Kitaoka 120a6e
        (m_cpIndexMin == m_cpIndexMax && m_strokeRef->isSelfLoop())) {
Shinya Kitaoka 120a6e
      /*
Shinya Kitaoka 120a6e
e' meglio rilevarli i corners.
Shinya Kitaoka 120a6e
Tanto se hai appiattito abbastanza, se ne vanno da soli,
Shinya Kitaoka 120a6e
senza lasciare ingrati compiti alla reuceControlPoints
Shinya Kitaoka 120a6e
Altrimenti non si fa altro che aumentarli i punti di controllo
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
      std::vector<int> corners;</int>
Shinya Kitaoka 120a6e
      corners.push_back(0);
Shinya Kitaoka 120a6e
      detectCorners(m_strokeRef, 45, corners);
Shinya Kitaoka 120a6e
      corners.push_back(m_strokeRef->getChunkCount());
Shinya Kitaoka 120a6e
      m_strokeRef->reduceControlPoints(2.0 * getPixelSize(), corners);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (m_cpIndexMin < m_cpIndexMax) {
Shinya Kitaoka 120a6e
        std::vector<tthickpoint> hitPoints(m_cpIndexMax - m_cpIndexMin + 1);</tthickpoint>
Shinya Kitaoka 120a6e
        count = 0;
Shinya Kitaoka 120a6e
        for (i = m_cpIndexMin; i <= m_cpIndexMax; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        TStroke *newStroke = new TStroke(hitPoints);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        std::vector<int> corners;</int>
Shinya Kitaoka 120a6e
        corners.push_back(0);
Shinya Kitaoka 120a6e
        detectCorners(newStroke, 45, corners);
Shinya Kitaoka 120a6e
        corners.push_back(newStroke->getChunkCount());
Shinya Kitaoka 120a6e
        newStroke->reduceControlPoints(2.0 * getPixelSize(), corners);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        hitPoints.resize(m_cpIndexMin + newStroke->getControlPointCount() +
Shinya Kitaoka 120a6e
                         cpCount - 1 - m_cpIndexMax);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        count = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (i = 0; i < m_cpIndexMin; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (i = 0; i < newStroke->getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = newStroke->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (i = m_cpIndexMax + 1; i < (int)cpCount; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_strokeRef->reshape(&hitPoints[0], hitPoints.size());
Shinya Kitaoka 120a6e
        delete newStroke;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        assert(m_cpIndexMin != m_cpIndexMax);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        std::vector<tthickpoint> hitPoints(cpCount - m_cpIndexMin);</tthickpoint>
Shinya Kitaoka 120a6e
        count = 0;
Shinya Kitaoka 120a6e
        for (i = m_cpIndexMin; i < (int)cpCount; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        TStroke *newStroke1 = new TStroke(hitPoints);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        std::vector<int> corners;</int>
Shinya Kitaoka 120a6e
        corners.push_back(0);
Shinya Kitaoka 120a6e
        detectCorners(newStroke1, 45, corners);
Shinya Kitaoka 120a6e
        corners.push_back(newStroke1->getChunkCount());
Shinya Kitaoka 120a6e
        newStroke1->reduceControlPoints(2.0 * getPixelSize(), corners);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        hitPoints.resize(m_cpIndexMax + 1);
Shinya Kitaoka 120a6e
        count = 0;
Shinya Kitaoka 120a6e
        for (i = 0; i <= m_cpIndexMax; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        TStroke *newStroke2 = new TStroke(hitPoints);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        corners.clear();
Shinya Kitaoka 120a6e
        corners.push_back(0);
Shinya Kitaoka 120a6e
        detectCorners(newStroke2, 45, corners);
Shinya Kitaoka 120a6e
        corners.push_back(newStroke2->getChunkCount());
Shinya Kitaoka 120a6e
        newStroke2->reduceControlPoints(2.0 * getPixelSize(), corners);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        hitPoints.resize(newStroke1->getControlPointCount() +
Shinya Kitaoka 120a6e
                         newStroke2->getControlPointCount() + m_cpIndexMin -
Shinya Kitaoka 120a6e
                         m_cpIndexMax - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        count = 0;
Shinya Kitaoka 120a6e
        for (i = 0; i < newStroke2->getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = newStroke2->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        for (i = m_cpIndexMax + 1; i < m_cpIndexMin; i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = m_strokeRef->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        for (i = 0; i < newStroke1->getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
          hitPoints[count++] = newStroke1->getControlPoint(i);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_strokeRef->reshape(&hitPoints[0], hitPoints.size());
Shinya Kitaoka 120a6e
        delete newStroke1;
Shinya Kitaoka 120a6e
        delete newStroke2;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_dragged = false;
Shinya Kitaoka 120a6e
    assert(m_undo);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(m_oldStroke);
Shinya Kitaoka 120a6e
    vi->notifyChangedStrokes(m_selectedStroke, m_oldStroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
    m_undo = 0;
Shinya Kitaoka 120a6e
    delete m_oldStroke;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void invalidateCursorArea() {
Shinya Kitaoka 120a6e
    double r = m_cursor.thick + 6;
Shinya Kitaoka 120a6e
    TPointD d(r, r);
Shinya Kitaoka 120a6e
    invalidate(TRectD(m_cursor - d, m_cursor + d));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void mouseMove(const TPointD &pos, const TMouseEvent &e) override {
Shinya Kitaoka 120a6e
    TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) {
Shinya Kitaoka 120a6e
      m_draw = false;
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // select nearest stroke and finds its parameter
Shinya Kitaoka 120a6e
    double dist, pW;
Shinya Kitaoka 120a6e
    UINT stroke;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (vi->getNearestStroke(pos, pW, stroke, dist)) {
Shinya Kitaoka 120a6e
      m_draw             = true;
Shinya Kitaoka 120a6e
      TStroke *strokeRef = vi->getStroke(stroke);
Shinya Kitaoka 120a6e
      m_cursor           = strokeRef->getThickPoint(pW);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      m_draw = false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool moveCursor(const TPointD &pos) { return false; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onActivate() override {
Shinya Kitaoka 120a6e
    //      getApplication()->editImageOrSpline();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onLeave() override { m_draw = false; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getCursorId() const override { return m_cursorId; }
Shinya Kitaoka 473e70
  void onEnter() override {
Shinya Kitaoka 120a6e
    m_draw = true;
Shinya Kitaoka 120a6e
    if ((TVectorImageP)getImage(false))
Shinya Kitaoka 120a6e
      m_cursorId = ToolCursor::IronCursor;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      m_cursorId = ToolCursor::CURSOR_NO;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} ironTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawPoint(const TPointD &p, double pixelSize) {
Shinya Kitaoka 120a6e
  double sizeX = pixelSize;
Shinya Kitaoka 120a6e
  double sizeY = pixelSize;
Shinya Kitaoka 120a6e
  glBegin(GL_QUADS);
Shinya Kitaoka 120a6e
  glVertex2d(p.x - sizeX, p.y - sizeY);
Shinya Kitaoka 120a6e
  glVertex2d(p.x - sizeX, p.y + sizeY);
Shinya Kitaoka 120a6e
  glVertex2d(p.x + sizeX, p.y + sizeY);
Shinya Kitaoka 120a6e
  glVertex2d(p.x + sizeX, p.y - sizeY);
Shinya Kitaoka 120a6e
  glEnd();
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawControlPoints(const TStroke *&stroke, double pixelSize) {
Shinya Kitaoka 120a6e
  int n = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i < n; ++i) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *chunk = stroke->getChunk(i);
Shinya Kitaoka 120a6e
    TPointD p0                   = chunk->getP0();
Shinya Kitaoka 120a6e
    TPointD p1                   = chunk->getP1();
Shinya Kitaoka 120a6e
    glColor3d(1.0, 0.0, 0.0);
Shinya Kitaoka 120a6e
    drawPoint(p0, pixelSize);
Shinya Kitaoka 120a6e
    glColor3d(1.0, 1.0, 1.0);
Shinya Kitaoka 120a6e
    drawPoint(p1, pixelSize);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  const TThickQuadratic *chunk = stroke->getChunk(n - 1);
Shinya Kitaoka 120a6e
  glColor3d(1.0, 0.0, 0.0);
Shinya Kitaoka 120a6e
  TPointD p2 = chunk->getP2();
Shinya Kitaoka 120a6e
  drawPoint(p2, pixelSize);
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
// end solo per debug
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// TTool *getIronTool() {return &ironTool;}