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 "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
#include "tstrokedeformations.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tproperty.h"
Toshihiro Shimizu 890ddd
#include "drawutil.h"
Toshihiro Shimizu 890ddd
#include "tcurveutil.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
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// For Qt translation support
Toshihiro Shimizu 890ddd
#include <qcoreapplication></qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
 Controlla se il primo punto della prima sotto_stroke
Toshihiro Shimizu 890ddd
 e' interno al cerchio, nel caso la stroke successiva
Toshihiro Shimizu 890ddd
 deve essere quella esterna e cosi' via, basta allora
Toshihiro Shimizu 890ddd
 fissare un contatore in modo da prendere le stroke
Toshihiro Shimizu 890ddd
 alternativamente (interne/esterne).
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void selectStrokeToMove(const ArrayOfStroke &v, const TPointD ¢er,
Shinya Kitaoka 120a6e
                        double radius, ArrayOfStroke &toMove) {
Shinya Kitaoka 120a6e
  if (v.empty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT counter;
Shinya Kitaoka 120a6e
  if (tdistance2(v.front()->getPoint(0), center) < sq(radius))
Shinya Kitaoka 120a6e
    counter = 0;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    counter = 1;
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    toMove.push_back(v[counter]);
Shinya Kitaoka 120a6e
    counter += 2;
Shinya Kitaoka 120a6e
  } while (counter < v.size());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
inline  double computeStep(const TQuadratic& quad, double invOfPixelSize)
Shinya Kitaoka 120a6e
{
Toshihiro Shimizu 890ddd
  double step = std::numeric_limits<double>::max();</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD A = quad.getP0() - 2.0*quad.getP1() + quad.getP2(); // 2*A is the
Shinya Kitaoka 120a6e
acceleration of the curve
Toshihiro Shimizu 890ddd
  double  A_len = norm(A);
Shinya Kitaoka 120a6e
  if (A_len > 0)  step = sqrt(2 * invOfPixelSize / A_len);
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
  return  step;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void drawQuadratic(const TQuadratic &quad, double pixelSize) {
Shinya Kitaoka 120a6e
  double m_min_step_at_normal_size = computeStep(quad, pixelSize);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // It draws the curve as a linear piecewise approximation
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double invSqrtScale = 1.0;
Shinya Kitaoka 120a6e
  // First of all, it computes the control circles of the curve in screen
Shinya Kitaoka 120a6e
  // coordinates
Shinya Kitaoka 120a6e
  TPointD scP0 = quad.getP0();
Shinya Kitaoka 120a6e
  TPointD scP1 = quad.getP1();
Shinya Kitaoka 120a6e
  TPointD scP2 = quad.getP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD A = scP0 - 2 * scP1 + scP2;
Shinya Kitaoka 120a6e
  TPointD B = scP0 - scP1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double h;
Shinya Kitaoka 120a6e
  h         = invSqrtScale * m_min_step_at_normal_size;
Shinya Kitaoka 120a6e
  double h2 = h * h;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD P = scP0, D2 = 2 * h2 * A, D1 = A * h2 - 2 * B * h;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (h < 0 || isAlmostZero(h)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // It draws the whole curve, using forward differencing
Shinya Kitaoka 120a6e
  glBegin(GL_LINE_STRIP);  // The curve starts from scP0
Shinya Kitaoka 120a6e
  glVertex2d(scP0.x, scP0.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (double t = h; t < 1; t = t + h) {
Shinya Kitaoka 120a6e
    P  = P + D1;
Shinya Kitaoka 120a6e
    D1 = D1 + D2;
Shinya Kitaoka 120a6e
    glVertex2d(P.x, P.y);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  glVertex2d(scP2.x, scP2.y);  // The curve ends in scP2
Shinya Kitaoka 120a6e
  glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// MagnetTool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class MagnetTool final : public TTool {
Shinya Kitaoka 120a6e
  Q_DECLARE_TR_FUNCTIONS(MagnetTool)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_active;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD m_startingPos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD m_oldPos, m_pointAtMouseDown, m_pointAtMove;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DoublePair m_extremes;
Shinya Kitaoka 120a6e
  int m_cursorId;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double m_pointSize;
Shinya Kitaoka 120a6e
  TUndo *m_undo;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typedef struct {
Shinya Kitaoka 120a6e
    TStroke *m_parent;
Shinya Kitaoka 120a6e
    ArrayOfStroke m_splitted;
Shinya Kitaoka 120a6e
    ArrayOfStroke m_splittedToMove;
Shinya Kitaoka 120a6e
  } strokeCollection;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<strokecollection> m_strokeToModify;</strokecollection>
Shinya Kitaoka 120a6e
  // vector<strokeinfo>  m_info;</strokeinfo>
Shinya Kitaoka 120a6e
  std::vector<tstroke *=""> m_strokeHit, m_oldStrokesArray;</tstroke>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<int> m_changedStrokes;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<std::vector<int> *> m_hitStrokeCorners, m_strokeToModifyCorners;</std::vector<int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TDoubleProperty m_toolSize;
Shinya Kitaoka 120a6e
  TPropertyGroup m_prop;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  MagnetTool()
Shinya Kitaoka 120a6e
      : TTool("T_Magnet")
Shinya Kitaoka 120a6e
      , m_active(false)
Shinya Kitaoka 120a6e
      , m_pointSize(-1)
Shinya Kitaoka 120a6e
      , m_oldStrokesArray()
Shinya Kitaoka 120a6e
      , m_toolSize("Size:", 0, 100, 20)  // W_ToolOptions_MagnetTool
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    bind(TTool::Vectors);
Shinya Kitaoka 120a6e
    m_prop.bind(m_toolSize);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  ToolType getToolType() const override { return TTool::LevelWriteTool; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void updateTranslation() override { m_toolSize.setQStringName(tr("Size:")); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onEnter() override {
Shinya Kitaoka 120a6e
    if ((TVectorImageP)getImage(false))
Shinya Kitaoka 120a6e
      m_cursorId = ToolCursor::MagnetCursor;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      m_cursorId = ToolCursor::CURSOR_NO;
Shinya Kitaoka 120a6e
Martin van Zijl 238783
    updatePointSize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onLeave() override { m_pointSize = -1; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override {
Shinya Kitaoka 120a6e
    TPointD p(pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_oldPos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_pointAtMouseDown = p;
Shinya Kitaoka 120a6e
    m_startingPos      = p;
Shinya Kitaoka 120a6e
    m_active           = false;
Shinya Kitaoka 120a6e
    TVectorImageP vi   = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) return;
Shinya Kitaoka 120a6e
    QMutexLocker lock(vi->getMutex());
Shinya Kitaoka 120a6e
    m_active = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_pointAtMove = m_pointAtMouseDown = p;
Shinya Kitaoka 120a6e
    m_strokeHit.clear();
Shinya Kitaoka 120a6e
    m_changedStrokes.clear();
Shinya Kitaoka 120a6e
    m_strokeToModify.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::vector<tstroke *=""> strokeUndo;</tstroke>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *ref;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_hitStrokeCorners.clear();
Shinya Kitaoka 120a6e
    m_strokeToModifyCorners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT i = 0;
Shinya Kitaoka 120a6e
    for (; i < vi->getStrokeCount(); ++i) {
Shinya Kitaoka 120a6e
      if (!vi->inCurrentGroup(i)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TStroke *stroke = vi->getStroke(i);
Shinya Kitaoka 120a6e
      ref             = stroke;
Shinya Kitaoka 120a6e
      //  calcola le intersezioni
Shinya Kitaoka 120a6e
      std::vector<double> intersections;</double>
Shinya Kitaoka 120a6e
      intersect(*ref, p, m_pointSize, intersections);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (intersections.empty()) {
Shinya Kitaoka 120a6e
        if (increaseControlPoints(*ref,
Shinya Kitaoka 120a6e
                                  TStrokePointDeformation(p, m_pointSize))) {
Shinya Kitaoka 120a6e
          m_changedStrokes.push_back(i);
Shinya Kitaoka 120a6e
          m_strokeHit.push_back(ref);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          std::vector<int> *corners = new std::vector<int>;</int></int>
Shinya Kitaoka 120a6e
          corners->push_back(0);
Shinya Kitaoka 120a6e
          detectCorners(ref, 20, *corners);
Shinya Kitaoka 120a6e
          corners->push_back(ref->getChunkCount());
Shinya Kitaoka 120a6e
          m_hitStrokeCorners.push_back(corners);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          ref->disableComputeOfCaches();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          strokeUndo.push_back(ref);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        strokeUndo.push_back(ref);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        MagnetTool::strokeCollection sc;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        sc.m_parent = ref;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        splitStroke(*sc.m_parent, intersections, sc.m_splitted);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        selectStrokeToMove(sc.m_splitted, p, m_pointSize, sc.m_splittedToMove);
Shinya Kitaoka 120a6e
        for (UINT ii = 0; ii < sc.m_splittedToMove.size(); ++ii) {
Shinya Kitaoka 120a6e
          TStroke *temp = sc.m_splittedToMove[ii];
Shinya Kitaoka 120a6e
          bool test     = increaseControlPoints(
Shinya Kitaoka 120a6e
              *temp, TStrokePointDeformation(p, m_pointSize));
Shinya Kitaoka 120a6e
          assert(test);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          std::vector<int> *corners = new std::vector<int>;</int></int>
Shinya Kitaoka 120a6e
          corners->push_back(0);
Shinya Kitaoka 120a6e
          detectCorners(temp, 20, *corners);
Shinya Kitaoka 120a6e
          corners->push_back(temp->getChunkCount());
Shinya Kitaoka 120a6e
          m_strokeToModifyCorners.push_back(corners);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_strokeToModify.push_back(sc);
Shinya Kitaoka 120a6e
        m_changedStrokes.push_back(i);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_oldStrokesArray.resize(m_changedStrokes.size());
Shinya Kitaoka 120a6e
    for (i                 = 0; i < m_changedStrokes.size(); i++)
Shinya Kitaoka 120a6e
      m_oldStrokesArray[i] = new TStroke(*(vi->getStroke(m_changedStrokes[i])));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!strokeUndo.empty()) {
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 UndoModifyListStroke(sl, id, strokeUndo);
Toshihiro Shimizu 890ddd
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    // vi->validateRegionEdges(ref, true);
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonDrag(const TPointD &p, const TMouseEvent &) override {
Shinya Kitaoka 120a6e
    if (!m_active) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //      double dx = p.x - m_pointAtMouseDown.x;
Shinya Kitaoka 120a6e
    double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
    if (tdistance2(p, m_oldPos) < 9.0 * pixelSize * pixelSize) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_oldPos           = p;
Shinya Kitaoka 120a6e
    m_pointAtMouseDown = p;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // double sc = exp(0.001 * (double)dx);
Shinya Kitaoka 120a6e
    TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) return;
Shinya Kitaoka 120a6e
    QMutexLocker lock(vi->getMutex());
Shinya Kitaoka 120a6e
    TPointD offset = p - m_pointAtMove;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
if( tdistance2(m_pointAtMouseDown, p ) > sq(m_pointSize * 0.5) ) // reincremento
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
leftButtonUp(p);
Shinya Kitaoka 120a6e
lefrightButtonDown(p);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
    UINT i, j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_strokeHit.size(); ++i)
Shinya Kitaoka 120a6e
      modifyControlPoints(*m_strokeHit[i],
Shinya Kitaoka 120a6e
                          TStrokePointDeformation(offset, m_pointAtMouseDown,
Shinya Kitaoka 120a6e
                                                  m_pointSize * 0.7));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_strokeToModify.size(); ++i)
Shinya Kitaoka 120a6e
      for (j = 0; j < m_strokeToModify[i].m_splittedToMove.size(); ++j) {
Shinya Kitaoka 120a6e
        TStroke *temp = m_strokeToModify[i].m_splittedToMove[j];
Shinya Kitaoka 120a6e
        modifyControlPoints(*temp,
Shinya Kitaoka 120a6e
                            TStrokePointDeformation(offset, m_pointAtMouseDown,
Shinya Kitaoka 120a6e
                                                    m_pointSize * 0.7));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_pointAtMove = p;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void mouseMove(const TPointD &p, const TMouseEvent &e) override {
Shinya Kitaoka 120a6e
    m_pointAtMove    = p;
Shinya Kitaoka 120a6e
    double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
    if (tdistance2(p, m_oldPos) < 9.0 * pixelSize * pixelSize) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_oldPos = p;
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void leftButtonUp(const TPointD &, const TMouseEvent &) override {
Shinya Kitaoka 120a6e
    if (!m_active) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_active           = false;
Shinya Kitaoka 120a6e
    m_pointAtMouseDown = m_pointAtMove = TConsts::napd;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *ref;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) return;
Shinya Kitaoka 120a6e
    QMutexLocker lock(vi->getMutex());
Shinya Kitaoka 120a6e
    UINT i, j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_strokeHit.size(); ++i) {
Shinya Kitaoka 120a6e
      ref = m_strokeHit[i];
Shinya Kitaoka 120a6e
      ref->enableComputeOfCaches();
Shinya Kitaoka 120a6e
      ref->reduceControlPoints(getPixelSize() * ReduceControlPointCorrection,
Shinya Kitaoka 120a6e
                               *(m_hitStrokeCorners[i]));
Shinya Kitaoka 120a6e
      // vi->validateRegionEdges(ref, false);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    clearPointerContainer(m_hitStrokeCorners);
Shinya Kitaoka 120a6e
    m_hitStrokeCorners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT count = 0;
Shinya Kitaoka 120a6e
    for (i = 0; i < m_strokeToModify.size(); ++i) {
Shinya Kitaoka 120a6e
      // recupero la stroke collection
Shinya Kitaoka 120a6e
      MagnetTool::strokeCollection &sc = m_strokeToModify[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (j = 0; j < sc.m_splittedToMove.size(); ++j) {
Shinya Kitaoka 120a6e
        ref = sc.m_splittedToMove[j];
Shinya Kitaoka 120a6e
        ref->enableComputeOfCaches();
Shinya Kitaoka 120a6e
        ref->reduceControlPoints(getPixelSize() * ReduceControlPointCorrection,
Shinya Kitaoka 120a6e
                                 *(m_strokeToModifyCorners[count++]));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // ricostruisco una stroke con quella data
Shinya Kitaoka 120a6e
      ref = merge(sc.m_splitted);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (sc.m_parent->isSelfLoop()) {
Shinya Kitaoka 120a6e
        int cpCount      = ref->getControlPointCount();
Shinya Kitaoka 120a6e
        TThickPoint p1   = ref->getControlPoint(0);
Shinya Kitaoka 120a6e
        TThickPoint p2   = ref->getControlPoint(cpCount - 1);
Shinya Kitaoka 120a6e
        TThickPoint midP = (p1 + p2) * 0.5;
Shinya Kitaoka 120a6e
        ref->setControlPoint(0, midP);
Shinya Kitaoka 120a6e
        ref->setControlPoint(cpCount - 1, midP);
Shinya Kitaoka 120a6e
        ref->setSelfLoop(true);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      sc.m_parent->swapGeometry(*ref);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      delete ref;  // elimino la curva temporanea
Shinya Kitaoka 120a6e
      clearPointerContainer(
Shinya Kitaoka 120a6e
          sc.m_splitted);           // pulisco le stroke trovate con lo split
Shinya Kitaoka 120a6e
      sc.m_splittedToMove.clear();  // pulisco il contenitore ( le stroke
Shinya Kitaoka 120a6e
                                    // che erano contenute qua sono state
Shinya Kitaoka 120a6e
                                    // eliminate nella clearPointer....
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    clearPointerContainer(m_strokeToModifyCorners);
Shinya Kitaoka 120a6e
    m_strokeToModifyCorners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < vi->getStrokeCount(); ++i) {
Shinya Kitaoka 120a6e
      ref = vi->getStroke(i);
Shinya Kitaoka 120a6e
      ref->invalidate();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    vi->notifyChangedStrokes(m_changedStrokes, m_oldStrokesArray);
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
    if (m_undo) TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
    m_undo = 0;
Shinya Kitaoka 120a6e
    clearPointerContainer(m_oldStrokesArray);
Shinya Kitaoka 120a6e
    m_oldStrokesArray.clear();
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void draw() override {
Shinya Kitaoka 120a6e
    TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
    if (!vi) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // TAffine viewMatrix = getViewer()->getViewMatrix();
Shinya Kitaoka 120a6e
    // glPushMatrix();
Shinya Kitaoka 120a6e
    // tglMultMatrix(viewMatrix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_pointSize > 0) {
Shinya Kitaoka 120a6e
      tglColor(TPixel32::Red);
Shinya Kitaoka 120a6e
      tglDrawCircle(m_pointAtMove, m_pointSize);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_active) {
Shinya Kitaoka 120a6e
      // glPopMatrix();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD delta = m_pointAtMouseDown - m_startingPos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //    glPushMatrix();
Shinya Kitaoka 120a6e
    // tglMultMatrix(m_referenceMatrix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_strokeHit.empty())
Shinya Kitaoka 120a6e
      for (UINT i = 0; i < m_strokeHit.size(); ++i)
Shinya Kitaoka 120a6e
        drawStrokeCenterline(*m_strokeHit[i], getPixelSize());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    tglColor(TPixel32::Red);
Shinya Kitaoka 120a6e
    UINT i, j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_strokeToModify.size(); ++i)
Shinya Kitaoka 120a6e
      for (j = 0; j < m_strokeToModify[i].m_splittedToMove.size(); ++j) {
Shinya Kitaoka 120a6e
        TStroke *temp = m_strokeToModify[i].m_splittedToMove[j];
Shinya Kitaoka 120a6e
        drawStrokeCenterline(*temp, getPixelSize());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //    glPopMatrix();
Shinya Kitaoka 120a6e
    // glPopMatrix();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onActivate() override {
Shinya Kitaoka 120a6e
    //        getApplication()->editImageOrSpline();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getCursorId() const override { return m_cursorId; }
Toshihiro Shimizu 890ddd
Martin van Zijl 238783
  bool onPropertyChanged(std::string propertyName) override
Martin van Zijl 238783
  {
Martin van Zijl 238783
    if(propertyName == m_toolSize.getName()) {
Martin van Zijl 238783
      updatePointSize();
Martin van Zijl 238783
      invalidate();
Martin van Zijl 238783
    }
Martin van Zijl 238783
Martin van Zijl 238783
    return true;
Martin van Zijl 238783
  }
Martin van Zijl 238783
Martin van Zijl 238783
private:
Martin van Zijl 238783
  /// Update point size based on property.
Martin van Zijl 238783
  void updatePointSize()
Martin van Zijl 238783
  {
Martin van Zijl 238783
    double x = m_toolSize.getValue();
Martin van Zijl 238783
Martin van Zijl 238783
    double minRange = 1;
Martin van Zijl 238783
    double maxRange = 100;
Martin van Zijl 238783
Martin van Zijl 238783
    double minSize = 10;
Martin van Zijl 238783
    double maxSize = 100;
Martin van Zijl 238783
Martin van Zijl 238783
    m_pointSize =
Martin van Zijl 238783
        (x - minRange) / (maxRange - minRange) * (maxSize - minSize) + minSize;
Martin van Zijl 238783
  }
Toshihiro Shimizu 890ddd
} magnetTool;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// TTool *getMagnetTool() {return &magnetTool;}