Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "controlpointselection.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.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
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isLinearPoint(const TPointD &p0, const TPointD &p1,
Shinya Kitaoka 120a6e
                          const TPointD &p2) {
Shinya Kitaoka 120a6e
  return (tdistance(p0, p1) < 0.02) && (tdistance(p1, p2) < 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Ritorna \b true se il punto \b p1 e' una cuspide.
Shinya Kitaoka 120a6e
bool isCuspPoint(const TPointD &p0, const TPointD &p1, const TPointD &p2) {
Shinya Kitaoka 120a6e
  TPointD p0_p1(p0 - p1), p2_p1(p2 - p1);
Shinya Kitaoka 120a6e
  double n1 = norm(p0_p1), n2 = norm(p2_p1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Partial linear points are ALWAYS cusps (since directions from them are
Shinya Kitaoka 120a6e
  // determined by neighbours, not by the points themselves)
Shinya Kitaoka 120a6e
  if ((n1 < 0.02) || (n2 < 0.02)) return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  p0_p1 = p0_p1 * (1.0 / n1);
Shinya Kitaoka 120a6e
  p2_p1 = p2_p1 * (1.0 / n2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return (p0_p1 * p2_p1 > 0) ||
Shinya Kitaoka 120a6e
         (fabs(cross(p0_p1, p2_p1)) > 0.09);  // more than 5° is yes
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Distance-based check. Unscalable...
Shinya Kitaoka 120a6e
  // return
Shinya Kitaoka 120a6e
  // !areAlmostEqual(tdistance(p0,p2),tdistance(p0,p1)+tdistance(p1,p2),2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint computeLinearPoint(const TThickPoint &p1, const TThickPoint &p2,
Shinya Kitaoka 120a6e
                               double factor, bool isIn) {
Shinya Kitaoka 120a6e
  TThickPoint p = p2 - p1;
Shinya Kitaoka 120a6e
  TThickPoint v = p * (1 / norm(p));
Shinya Kitaoka 120a6e
  if (isIn) return p2 - factor * v;
Shinya Kitaoka 120a6e
  return p1 + factor * v;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Insert a point in the most long chunk between chunk \b indexA and chunk \b
Shinya Kitaoka 120a6e
 * indexB. */
Shinya Kitaoka 120a6e
void insertPoint(TStroke *stroke, int indexA, int indexB) {
Shinya Kitaoka 120a6e
  assert(stroke);
Shinya Kitaoka 120a6e
  int j          = 0;
Shinya Kitaoka 120a6e
  int chunkCount = indexB - indexA;
Shinya Kitaoka 120a6e
  if (chunkCount % 2 == 0) return;
Shinya Kitaoka 120a6e
  double length = 0;
Shinya Kitaoka 120a6e
  double firstW, lastW;
Shinya Kitaoka 120a6e
  for (j = indexA; j < indexB; j++) {
Shinya Kitaoka 120a6e
    // cerco il chunk piu' lungo
Shinya Kitaoka 120a6e
    double w0 = stroke->getW(stroke->getChunk(j)->getP0());
Shinya Kitaoka 120a6e
    double w1;
Shinya Kitaoka 120a6e
    if (j == stroke->getChunkCount() - 1)
Shinya Kitaoka 120a6e
      w1 = 1;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      w1           = stroke->getW(stroke->getChunk(j)->getP2());
Shinya Kitaoka 120a6e
    double length0 = stroke->getLength(w0);
Shinya Kitaoka 120a6e
    double length1 = stroke->getLength(w1);
Shinya Kitaoka 120a6e
    if (length < length1 - length0) {
Shinya Kitaoka 120a6e
      firstW = w0;
Shinya Kitaoka 120a6e
      lastW  = w1;
Shinya Kitaoka 120a6e
      length = length1 - length0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  stroke->insertControlPoints((firstW + lastW) * 0.5);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ControlPointEditorStroke
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ControlPointEditorStroke *ControlPointEditorStroke::clone() const {
Shinya Kitaoka 120a6e
  ControlPointEditorStroke *controlPointEditorStroke =
Shinya Kitaoka 120a6e
      new ControlPointEditorStroke();
Shinya Kitaoka 120a6e
  controlPointEditorStroke->setStroke(m_vi->clone(), m_strokeIndex);
Shinya Kitaoka 120a6e
  return controlPointEditorStroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int ControlPointEditorStroke::nextIndex(int index) const {
Shinya Kitaoka 120a6e
  int cpCount = m_controlPoints.size();
Shinya Kitaoka 120a6e
  if (++index < cpCount) return index;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isSelfLoop()) {
Shinya Kitaoka 120a6e
    index %= cpCount;
Shinya Kitaoka 120a6e
    return (index < 0) ? index + cpCount : index;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int ControlPointEditorStroke::prevIndex(int index) const {
Shinya Kitaoka 120a6e
  int cpCount = m_controlPoints.size();
Shinya Kitaoka 120a6e
  if (--index >= 0) return index;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isSelfLoop()) {
Shinya Kitaoka 120a6e
    index %= cpCount;
Shinya Kitaoka 120a6e
    return (index < 0) ? index + cpCount : index;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::adjustChunkParity() {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
  int firstChunk;
Shinya Kitaoka 120a6e
  int secondChunk = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = stroke->getChunkCount() - 1; i > 0; i--) {
Shinya Kitaoka 120a6e
    if (tdistance(stroke->getChunk(i - 1)->getP0(),
Shinya Kitaoka 120a6e
                  stroke->getChunk(i)->getP2()) < 0.5)
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    TPointD p0 = stroke->getChunk(i - 1)->getP1();
Shinya Kitaoka 120a6e
    TPointD p1 = stroke->getChunk(i - 1)->getP2();
Shinya Kitaoka 120a6e
    TPointD p2 = stroke->getChunk(i)->getP1();
Shinya Kitaoka 120a6e
    if (isCuspPoint(p0, p1, p2) || isLinearPoint(p0, p1, p2)) {
Shinya Kitaoka 120a6e
      firstChunk = i;
Shinya Kitaoka 120a6e
      insertPoint(stroke, firstChunk, secondChunk);
Shinya Kitaoka 120a6e
      secondChunk = firstChunk;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  insertPoint(stroke, 0, secondChunk);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::resetControlPoints() {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
  m_controlPoints.clear();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  int cpCount = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
  if (cpCount == 3) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *chunk = stroke->getChunk(0);
Shinya Kitaoka 120a6e
    if (chunk->getP0() == chunk->getP1() &&
Shinya Kitaoka 120a6e
        chunk->getP0() == chunk->getP2())  // E' un punto
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      m_controlPoints.push_back(
Shinya Kitaoka 120a6e
          ControlPoint(0, TPointD(0.0, 0.0), TPointD(0.0, 0.0), true));
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = 0; i < cpCount; i = i + 4) {
Shinya Kitaoka 120a6e
    TThickPoint speedIn, speedOut;
Shinya Kitaoka 120a6e
    bool isPickOut    = false;
Shinya Kitaoka 120a6e
    TThickPoint p     = stroke->getControlPoint(i);
Shinya Kitaoka 120a6e
    TThickPoint precP = stroke->getControlPoint(i - 1);
Shinya Kitaoka 120a6e
    TThickPoint nextP = stroke->getControlPoint(i + 1);
Shinya Kitaoka 120a6e
    if (0 < i && i < cpCount - 1)  // calcola speedIn e speedOut
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      speedIn  = p - precP;
Shinya Kitaoka 120a6e
      speedOut = nextP - p;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (i == 0)  // calcola solo lo speedOut
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      speedOut                  = nextP - p;
Shinya Kitaoka 120a6e
      if (isSelfLoop()) speedIn = p - stroke->getControlPoint(cpCount - 2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (i == cpCount - 1)  // calcola solo lo speedIn
Shinya Kitaoka 120a6e
      speedIn = p - precP;
Shinya Kitaoka 120a6e
    if (i == cpCount - 1 && isSelfLoop())
Shinya Kitaoka 120a6e
      break;  // Se lo stroke e' selfLoop inserisco solo il primo dei due punti
Shinya Kitaoka 120a6e
              // coincidenti
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool isCusp = ((i != 0 && i != cpCount - 1) || (isSelfLoop() && i == 0))
Shinya Kitaoka 120a6e
                      ? isCuspPoint(precP, p, nextP)
Shinya Kitaoka 120a6e
                      : true;
Shinya Kitaoka 120a6e
    m_controlPoints.push_back(ControlPoint(i, speedIn, speedOut, isCusp));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint ControlPointEditorStroke::getPureDependentPoint(int index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return TThickPoint();
Shinya Kitaoka 120a6e
  bool selfLoop = isSelfLoop();
Shinya Kitaoka 120a6e
  int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Shinya Kitaoka 120a6e
  int nextIndex  = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Shinya Kitaoka 120a6e
  int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThickPoint oldP(stroke->getControlPoint(pointIndex + 2));
Shinya Kitaoka 120a6e
  TPointD oldSpeedOutP = stroke->getControlPoint(pointIndex + 1);
Shinya Kitaoka 120a6e
  TPointD oldSpeedInP  = stroke->getControlPoint(pointIndex + 3);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double dist = tdistance(oldSpeedOutP, oldSpeedInP);
Shinya Kitaoka 120a6e
  double t = (dist > 1e-4) ? tdistance(oldSpeedInP, convert(oldP)) / dist : 0.5;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD speedOutPoint(getSpeedOutPoint(index));
Shinya Kitaoka 120a6e
  TPointD nextSpeedInPoint(getSpeedInPoint(nextIndex));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return TThickPoint((1 - t) * nextSpeedInPoint + t * speedOutPoint,
Shinya Kitaoka 120a6e
                     oldP.thick);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // return TThickPoint(0.5 * (speedOutPoint + nextSpeedInPoint), oldThick);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::getDependentPoints(
Shinya Kitaoka 120a6e
    int index, std::vector<std::pair<int, tthickpoint="">> &points) const {</std::pair<int,>
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int cpCount = m_controlPoints.size();
Shinya Kitaoka 120a6e
  if (index == cpCount && isSelfLoop())  // strange, but was treated...
Shinya Kitaoka 120a6e
    index = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (index == 0 && cpCount == 1) {
Shinya Kitaoka 120a6e
    // Single point case
Shinya Kitaoka 120a6e
    TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
    TThickPoint pos(stroke->getControlPoint(m_controlPoints[0].m_pointIndex));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    points.push_back(std::make_pair(1, pos));
Shinya Kitaoka 120a6e
    points.push_back(std::make_pair(2, pos));
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int prev = prevIndex(index);
Shinya Kitaoka 120a6e
  if (prev >= 0) {
Shinya Kitaoka 120a6e
    int prevPointIndex = m_controlPoints[prev].m_pointIndex;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (isSpeedOutLinear(prev))
Shinya Kitaoka 120a6e
      points.push_back(
Shinya Kitaoka 120a6e
          std::make_pair(prevPointIndex + 1, getSpeedOutPoint(prev)));
Shinya Kitaoka 120a6e
    points.push_back(
Shinya Kitaoka 120a6e
        std::make_pair(prevPointIndex + 2, getPureDependentPoint(prev)));
Shinya Kitaoka 120a6e
    points.push_back(
Shinya Kitaoka 120a6e
        std::make_pair(prevPointIndex + 3, getSpeedInPoint(index)));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int next = nextIndex(index);
Shinya Kitaoka 120a6e
  if (next >= 0) {
Shinya Kitaoka 120a6e
    int pointIndex = m_controlPoints[index].m_pointIndex;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    points.push_back(std::make_pair(pointIndex + 1, getSpeedOutPoint(index)));
Shinya Kitaoka 120a6e
    points.push_back(
Shinya Kitaoka 120a6e
        std::make_pair(pointIndex + 2, getPureDependentPoint(index)));
Shinya Kitaoka 120a6e
    if (isSpeedInLinear(next))
Shinya Kitaoka 120a6e
      points.push_back(std::make_pair(pointIndex + 3, getSpeedInPoint(next)));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::updatePoints() {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
  bool selfLoop = isSelfLoop();
Shinya Kitaoka 120a6e
  // Se e' rimasto un unico punto non ha senso che la stroke sia selfloop
Shinya Kitaoka 120a6e
  if (selfLoop && m_controlPoints.size() == 1) {
Shinya Kitaoka 120a6e
    stroke->setSelfLoop(false);
Shinya Kitaoka 120a6e
    selfLoop = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Se e' self loop  devo aggiungere un punto in piu' al cpCount
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Shinya Kitaoka 120a6e
  if (cpCount == 1)
Shinya Kitaoka 120a6e
    // Single point case
Shinya Kitaoka 120a6e
    points.resize(3, getControlPoint(0));
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    std::vector<std::pair<int, tthickpoint="">> dependentPoints;</std::pair<int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    points.push_back(getControlPoint(0));
Shinya Kitaoka 120a6e
    points.push_back(getSpeedOutPoint(0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i, pointIndex, currPointIndex = m_controlPoints[0].m_pointIndex + 1;
Shinya Kitaoka 120a6e
    for (i = 1; i < cpCount; ++i) {
Shinya Kitaoka 120a6e
      bool isLastSelfLoopPoint = (selfLoop && i == cpCount - 1);
Shinya Kitaoka 120a6e
      int index                = isLastSelfLoopPoint ? 0 : i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TThickPoint p = getControlPoint(index);
Shinya Kitaoka 120a6e
      pointIndex    = isLastSelfLoopPoint ? getStroke()->getControlPointCount()
Shinya Kitaoka 120a6e
                                       : m_controlPoints[index].m_pointIndex;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      dependentPoints.clear();
Shinya Kitaoka 120a6e
      getDependentPoints(index, dependentPoints);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int j;
Shinya Kitaoka 120a6e
      for (j = 0; j < (int)dependentPoints.size() &&
Shinya Kitaoka 120a6e
                  dependentPoints[j].first < pointIndex;
Shinya Kitaoka 120a6e
           j++) {
Shinya Kitaoka 120a6e
        if (currPointIndex < dependentPoints[j].first) {
Shinya Kitaoka 120a6e
          currPointIndex = dependentPoints[j].first;
Shinya Kitaoka 120a6e
          points.push_back(dependentPoints[j].second);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      points.push_back(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (; j < (int)dependentPoints.size(); j++) {
Shinya Kitaoka 120a6e
        if (currPointIndex < dependentPoints[j].first) {
Shinya Kitaoka 120a6e
          currPointIndex = dependentPoints[j].first;
Shinya Kitaoka 120a6e
          points.push_back(dependentPoints[j].second);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  stroke->reshape(&points[0], points.size());
Shinya Kitaoka 120a6e
  m_vi->notifyChangedStrokes(m_strokeIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::updateDependentPoint(int index) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, tthickpoint="">> points;</std::pair<int,>
Shinya Kitaoka 120a6e
  getDependentPoints(index, points);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)points.size(); i++)
Shinya Kitaoka 120a6e
    stroke->setControlPoint(points[i].first, points[i].second);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_vi->notifyChangedStrokes(m_strokeIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveSpeedOut(int index, const TPointD &delta,
Shinya Kitaoka 120a6e
                                            double minDistance) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If the next cp has linear speed in, it must be recomputed
Shinya Kitaoka 120a6e
  bool selfLoop = isSelfLoop();
Shinya Kitaoka 120a6e
  int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Shinya Kitaoka 120a6e
  int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Shinya Kitaoka 120a6e
  if (m_controlPoints[nextIndex].m_isCusp && isSpeedInLinear(nextIndex))
Shinya Kitaoka 120a6e
    setLinearSpeedIn(nextIndex, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Update the speedOut
Shinya Kitaoka 120a6e
  m_controlPoints[index].m_speedOut += delta;
Shinya Kitaoka 120a6e
  TPointD newP = m_controlPoints[index].m_speedOut;
Shinya Kitaoka 120a6e
  if (areAlmostEqual(newP.x, 0, minDistance) &&
Shinya Kitaoka 120a6e
      areAlmostEqual(newP.y, 0, minDistance))  // Setto a linear
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    setLinearSpeedOut(index);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!m_controlPoints[index].m_isCusp && !isSpeedInLinear(index)) {
Shinya Kitaoka 120a6e
    // Devo ricalcolare lo SpeedIn
Shinya Kitaoka 120a6e
    TPointD v(m_controlPoints[index].m_speedOut *
Shinya Kitaoka 120a6e
              (1.0 / norm(m_controlPoints[index].m_speedOut)));
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedIn =
Shinya Kitaoka 120a6e
        TThickPoint(v * norm(m_controlPoints[index].m_speedIn),
Shinya Kitaoka 120a6e
                    m_controlPoints[index].m_speedIn.thick);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveSpeedIn(int index, const TPointD &delta,
Shinya Kitaoka 120a6e
                                           double minDistance) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If the prev cp has linear speed out, it must be recomputed
Shinya Kitaoka 120a6e
  bool selfLoop = isSelfLoop();
Shinya Kitaoka 120a6e
  int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Shinya Kitaoka 120a6e
  int prevIndex = (selfLoop && index == 0) ? cpCount - 2 : index - 1;
Shinya Kitaoka 120a6e
  if (m_controlPoints[prevIndex].m_isCusp && isSpeedOutLinear(prevIndex))
Shinya Kitaoka 120a6e
    setLinearSpeedOut(prevIndex, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Update the speedOut
Shinya Kitaoka 120a6e
  m_controlPoints[index].m_speedIn -= delta;
Shinya Kitaoka 120a6e
  TPointD newP = m_controlPoints[index].m_speedIn;
Shinya Kitaoka 120a6e
  if (areAlmostEqual(newP.x, 0, minDistance) &&
Shinya Kitaoka 120a6e
      areAlmostEqual(newP.y, 0, minDistance))  // Setto a linear
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    setLinearSpeedIn(index);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!m_controlPoints[index].m_isCusp && !isSpeedOutLinear(index)) {
Shinya Kitaoka 120a6e
    // Devo ricalcolare lo SpeedOut
Shinya Kitaoka 120a6e
    TPointD v(m_controlPoints[index].m_speedIn *
Shinya Kitaoka 120a6e
              (1.0 / norm(m_controlPoints[index].m_speedIn)));
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedOut =
Shinya Kitaoka 120a6e
        TThickPoint(v * norm(m_controlPoints[index].m_speedOut),
Shinya Kitaoka 120a6e
                    m_controlPoints[index].m_speedOut.thick);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveSingleControlPoint(int index,
Shinya Kitaoka 120a6e
                                                      const TPointD &delta) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int pointIndex = m_controlPoints[index].m_pointIndex;
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= pointIndex &&
Shinya Kitaoka 120a6e
         pointIndex < stroke->getControlPointCount());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool selfLoop = isSelfLoop();
Shinya Kitaoka 120a6e
  int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickPoint p = stroke->getControlPoint(pointIndex);
Shinya Kitaoka 120a6e
  p             = TThickPoint(p + delta, p.thick);
Shinya Kitaoka 120a6e
  stroke->setControlPoint(pointIndex, p);
Shinya Kitaoka 120a6e
  if (pointIndex == 0 && selfLoop)
Shinya Kitaoka 120a6e
    stroke->setControlPoint(stroke->getControlPointCount() - 1, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Directions must be recalculated in the linear cases
Shinya Kitaoka 120a6e
  if ((selfLoop || index > 0) && isSpeedInLinear(index)) {
Shinya Kitaoka 120a6e
    setLinearSpeedIn(index, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Furthermore, if the NEIGHBOUR point is linear, it has to be
Shinya Kitaoka 120a6e
    // recalculated too
Shinya Kitaoka 120a6e
    int prevIndex = (selfLoop && index == 0) ? cpCount - 2 : index - 1;
Shinya Kitaoka 120a6e
    if (m_controlPoints[prevIndex].m_isCusp && isSpeedOutLinear(prevIndex))
Shinya Kitaoka 120a6e
      setLinearSpeedOut(prevIndex, true, false);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((selfLoop || index < cpCount - 1) && isSpeedOutLinear(index)) {
Shinya Kitaoka 120a6e
    setLinearSpeedOut(index, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Shinya Kitaoka 120a6e
    if (m_controlPoints[nextIndex].m_isCusp && isSpeedInLinear(nextIndex))
Shinya Kitaoka 120a6e
      setLinearSpeedIn(nextIndex, true, false);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::setStroke(const TVectorImageP &vi,
Shinya Kitaoka 120a6e
                                         int strokeIndex) {
Shinya Kitaoka 120a6e
  m_strokeIndex = strokeIndex;
Shinya Kitaoka 120a6e
  m_vi          = vi;
Shinya Kitaoka 120a6e
  if (!vi || strokeIndex == -1) {
Shinya Kitaoka 120a6e
    m_controlPoints.clear();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TStroke *stroke              = getStroke();
Shinya Kitaoka 120a6e
  const TThickQuadratic *chunk = stroke->getChunk(0);
Shinya Kitaoka 120a6e
  if (stroke->getControlPointCount() == 3 && chunk->getP0() == chunk->getP1() &&
Shinya Kitaoka 120a6e
      chunk->getP0() == chunk->getP2()) {
Shinya Kitaoka 120a6e
    resetControlPoints();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  adjustChunkParity();
Shinya Kitaoka 120a6e
  resetControlPoints();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint ControlPointEditorStroke::getControlPoint(int index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Shinya Kitaoka 120a6e
  return stroke->getControlPoint(m_controlPoints[index].m_pointIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int ControlPointEditorStroke::getIndexPointInStroke(int index) const {
Shinya Kitaoka 120a6e
  return m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint ControlPointEditorStroke::getSpeedInPoint(int index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ControlPoint cp = m_controlPoints[index];
Shinya Kitaoka 120a6e
  return stroke->getControlPoint(cp.m_pointIndex) - cp.m_speedIn;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint ControlPointEditorStroke::getSpeedOutPoint(int index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ControlPoint cp = m_controlPoints[index];
Shinya Kitaoka 120a6e
  return stroke->getControlPoint(cp.m_pointIndex) + cp.m_speedOut;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointEditorStroke::isCusp(int index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)getControlPointCount());
Shinya Kitaoka 120a6e
  return m_controlPoints[index].m_isCusp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::setCusp(int index, bool isCusp,
Shinya Kitaoka 120a6e
                                       bool setSpeedIn) {
Shinya Kitaoka 120a6e
  m_controlPoints[index].m_isCusp = isCusp;
Shinya Kitaoka 120a6e
  if (isCusp == true) return;
Shinya Kitaoka 120a6e
  moveSpeed(index, TPointD(0.0, 0.0), setSpeedIn, 0.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointEditorStroke::isSpeedInLinear(int index) const {
Shinya Kitaoka 120a6e
  assert(index < (int)m_controlPoints.size());
Shinya Kitaoka 120a6e
  return (fabs(m_controlPoints[index].m_speedIn.x) <= 0.02) &&
Shinya Kitaoka 120a6e
         (fabs(m_controlPoints[index].m_speedIn.y) <= 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointEditorStroke::isSpeedOutLinear(int index) const {
Shinya Kitaoka 120a6e
  assert(index < (int)m_controlPoints.size());
Shinya Kitaoka 120a6e
  return (fabs(m_controlPoints[index].m_speedOut.x) <= 0.02) &&
Shinya Kitaoka 120a6e
         (fabs(m_controlPoints[index].m_speedOut.y) <= 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::setLinearSpeedIn(int index, bool linear,
Shinya Kitaoka 120a6e
                                                bool updatePoints) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke || m_controlPoints.size() == 1) return;
Shinya Kitaoka 120a6e
  int pointIndex = m_controlPoints[index].m_pointIndex;
Shinya Kitaoka 120a6e
  if (pointIndex == 0) {
Shinya Kitaoka 120a6e
    if (isSelfLoop())
Shinya Kitaoka 120a6e
      pointIndex = stroke->getControlPointCount() - 1;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int precIndex =
Shinya Kitaoka 120a6e
      (index == 0 && isSelfLoop()) ? m_controlPoints.size() - 1 : index - 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickPoint point     = stroke->getControlPoint(pointIndex);
Shinya Kitaoka 120a6e
  TThickPoint precPoint = (pointIndex > 2)
Shinya Kitaoka 120a6e
                              ? stroke->getControlPoint(pointIndex - 3)
Shinya Kitaoka 120a6e
                              : TThickPoint();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (linear) {
Shinya Kitaoka 120a6e
    TThickPoint p(point - precPoint);
Shinya Kitaoka 120a6e
    double n = norm(p);
Shinya Kitaoka 120a6e
    TThickPoint speedIn =
Shinya Kitaoka 120a6e
        (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0);
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedIn = speedIn;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TThickPoint newPrec2             = (precPoint + point) * 0.5;
Shinya Kitaoka 120a6e
    TThickPoint speedIn              = (point - newPrec2) * 0.5;
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedIn = speedIn;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (updatePoints) updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::setLinearSpeedOut(int index, bool linear,
Shinya Kitaoka 120a6e
                                                 bool updatePoints) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke || m_controlPoints.size() == 1) return;
Shinya Kitaoka 120a6e
  int cpCount    = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
  int pointIndex = m_controlPoints[index].m_pointIndex;
Shinya Kitaoka 120a6e
  if (pointIndex == cpCount - 1) {
Shinya Kitaoka 120a6e
    if (isSelfLoop())
Shinya Kitaoka 120a6e
      pointIndex = 0;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int nextIndex =
Shinya Kitaoka 120a6e
      (index == m_controlPoints.size() - 1 && isSelfLoop()) ? 0 : index + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickPoint point     = stroke->getControlPoint(pointIndex);
Shinya Kitaoka 120a6e
  TThickPoint nextPoint = (pointIndex < cpCount - 3)
Shinya Kitaoka 120a6e
                              ? stroke->getControlPoint(pointIndex + 3)
Shinya Kitaoka 120a6e
                              : TThickPoint();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (linear) {
Shinya Kitaoka 120a6e
    TThickPoint p(nextPoint - point);
Shinya Kitaoka 120a6e
    double n = norm(p);
Shinya Kitaoka 120a6e
    TThickPoint speedOut =
Shinya Kitaoka 120a6e
        (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0);
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedOut = speedOut;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TThickPoint newNext2              = (nextPoint + point) * 0.5;
Shinya Kitaoka 120a6e
    TThickPoint speedOut              = (newNext2 - point) * 0.5;
Shinya Kitaoka 120a6e
    m_controlPoints[index].m_speedOut = speedOut;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (updatePoints) updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointEditorStroke::setLinear(int index, bool isLinear,
Shinya Kitaoka 120a6e
                                         bool updatePoints) {
Shinya Kitaoka 120a6e
  bool movePrec = (!isSelfLoop()) ? index > 0 : true;
Shinya Kitaoka 120a6e
  bool moveNext = (!isSelfLoop()) ? (index < getControlPointCount() - 1) : true;
Shinya Kitaoka 120a6e
  if (isLinear != isSpeedInLinear(index))
Shinya Kitaoka 120a6e
    setLinearSpeedIn(index, isLinear, updatePoints);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    movePrec = false;
Shinya Kitaoka 120a6e
  if (isLinear != isSpeedOutLinear(index))
Shinya Kitaoka 120a6e
    setLinearSpeedOut(index, isLinear, updatePoints);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    moveNext                               = false;
Shinya Kitaoka 120a6e
  bool ret                                 = moveNext || movePrec;
Shinya Kitaoka 120a6e
  if (ret) m_controlPoints[index].m_isCusp = true;
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointEditorStroke::setControlPointsLinear(std::set<int> points,</int>
Shinya Kitaoka 120a6e
                                                      bool isLinear) {
Shinya Kitaoka 120a6e
  std::set<int>::iterator it;</int>
Shinya Kitaoka 120a6e
  bool isChanged = false;
Shinya Kitaoka 120a6e
  for (it = points.begin(); it != points.end(); it++)
Shinya Kitaoka 120a6e
    isChanged = setLinear(*it, isLinear, false) || isChanged;
Shinya Kitaoka 120a6e
  for (it = points.begin(); it != points.end(); it++) updateDependentPoint(*it);
Shinya Kitaoka 120a6e
  return isChanged;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveControlPoint(int index,
Shinya Kitaoka 120a6e
                                                const TPointD &delta) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)getControlPointCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  moveSingleControlPoint(index, delta);
Shinya Kitaoka 120a6e
  updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int ControlPointEditorStroke::addControlPoint(const TPointD &pos) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return -1;
Shinya Kitaoka 120a6e
  double d = 0.01;
Shinya Kitaoka 120a6e
  int indexAtPos;
Shinya Kitaoka 120a6e
  int cpCount = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
  if (cpCount <= 3)  // e' un unico chunk e in questo caso rappresenta un punto
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    getPointTypeAt(pos, d, indexAtPos);
Shinya Kitaoka 120a6e
    return indexAtPos;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double w       = stroke->getW(pos);
Shinya Kitaoka 120a6e
  int pointIndex = stroke->getControlPointIndexAfterParameter(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i, index;
Shinya Kitaoka 120a6e
  for (i = 0; i < getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
    // Cerco il ControlPoint corrispondente all'indice pointIndex. OSS.:
Shinya Kitaoka 120a6e
    // Effettuo il
Shinya Kitaoka 120a6e
    // controllo da zero a getControlPointCount()-1 per gestire il caso del
Shinya Kitaoka 120a6e
    // selfLoop
Shinya Kitaoka 120a6e
    if (pointIndex == m_controlPoints[i].m_pointIndex + 1 ||
Shinya Kitaoka 120a6e
        pointIndex == m_controlPoints[i].m_pointIndex + 2 ||
Shinya Kitaoka 120a6e
        pointIndex == m_controlPoints[i].m_pointIndex + 3 ||
Shinya Kitaoka 120a6e
        pointIndex == m_controlPoints[i].m_pointIndex + 4)
Shinya Kitaoka 120a6e
      index = i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ControlPoint precCp = m_controlPoints[index];
Shinya Kitaoka 120a6e
  assert(precCp.m_pointIndex >= 0);
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < cpCount; i++) {
Shinya Kitaoka 120a6e
    if (i != precCp.m_pointIndex + 1 && i != precCp.m_pointIndex + 2 &&
Shinya Kitaoka 120a6e
        i != precCp.m_pointIndex + 3)
Shinya Kitaoka 120a6e
      points.push_back(stroke->getControlPoint(i));
Shinya Kitaoka 120a6e
    if (i == precCp.m_pointIndex + 2) {
Shinya Kitaoka 120a6e
      bool isBeforePointLinear = isSpeedOutLinear(index);
Shinya Kitaoka 120a6e
      int nextIndex =
Shinya Kitaoka 120a6e
          (isSelfLoop() && index == m_controlPoints.size() - 1) ? 0 : index + 1;
Shinya Kitaoka 120a6e
      bool isNextPointLinear =
Shinya Kitaoka 120a6e
          nextIndex < (int)m_controlPoints.size() && isSpeedInLinear(nextIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TThickPoint a0 = stroke->getControlPoint(precCp.m_pointIndex);
Shinya Kitaoka 120a6e
      TThickPoint a1 = stroke->getControlPoint(precCp.m_pointIndex + 1);
Shinya Kitaoka 120a6e
      TThickPoint a2 = stroke->getControlPoint(precCp.m_pointIndex + 2);
Shinya Kitaoka 120a6e
      TThickPoint a3 = stroke->getControlPoint(precCp.m_pointIndex + 3);
Shinya Kitaoka 120a6e
      TThickPoint a4 = stroke->getControlPoint(precCp.m_pointIndex + 4);
Shinya Kitaoka 120a6e
      double dist2   = tdistance2(pos, TPointD(a2));
Shinya Kitaoka 120a6e
      TThickPoint d0, d1, d2, d3, d4, d5, d6;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (isBeforePointLinear && isNextPointLinear) {
Shinya Kitaoka 120a6e
        // Se sono entrambi i punti lineari  inserisco un punto lineare
Shinya Kitaoka 120a6e
        d0 = a1;
Shinya Kitaoka 120a6e
        d3 = stroke->getThickPoint(w);
Shinya Kitaoka 120a6e
        d6 = a3;
Shinya Kitaoka 120a6e
        d2 = computeLinearPoint(d0, d3, 0.01, true);   // SpeedIn
Shinya Kitaoka 120a6e
        d4 = computeLinearPoint(d3, d6, 0.01, false);  // SpeedOut
Shinya Kitaoka 120a6e
        d1 = 0.5 * (d0 + d2);
Shinya Kitaoka 120a6e
        d5 = 0.5 * (d4 + d6);
Shinya Kitaoka 120a6e
      } else if (dist2 < 32) {
Shinya Kitaoka 120a6e
        // Sono molto vicino al punto che non viene visualizzato
Shinya Kitaoka 120a6e
        TThickPoint b0 = 0.5 * (a0 + a1);
Shinya Kitaoka 120a6e
        TThickPoint b1 = 0.5 * (a2 + a1);
Shinya Kitaoka 120a6e
        TThickPoint c0 = 0.5 * (b0 + b1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TThickPoint b2 = 0.5 * (a2 + a3);
Shinya Kitaoka 120a6e
        TThickPoint b3 = 0.5 * (a3 + a4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TThickPoint c1 = 0.5 * (b2 + b3);
Shinya Kitaoka 120a6e
        d0             = b0;
Shinya Kitaoka 120a6e
        d1             = c0;
Shinya Kitaoka 120a6e
        d2             = b1;
Shinya Kitaoka 120a6e
        d3             = a2;
Shinya Kitaoka 120a6e
        d4             = b2;
Shinya Kitaoka 120a6e
        d5             = c1;
Shinya Kitaoka 120a6e
        d6             = b3;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        bool isInFirstChunk = true;
Shinya Kitaoka 120a6e
        if (pointIndex > precCp.m_pointIndex + 2) {
Shinya Kitaoka 120a6e
          // nel caso in cui sono nel secondo chunk scambio i punti
Shinya Kitaoka 120a6e
          a0 = a4;
Shinya Kitaoka 120a6e
          tswap(a1, a3);
Shinya Kitaoka 120a6e
          isInFirstChunk = false;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        double w0 = (isSelfLoop() && precCp.m_pointIndex + 4 == cpCount - 1 &&
Shinya Kitaoka 120a6e
                     !isInFirstChunk)
Shinya Kitaoka 120a6e
                        ? 1
Shinya Kitaoka 120a6e
                        : stroke->getW(a0);
Shinya Kitaoka 120a6e
        double w1 = stroke->getW(a2);
Shinya Kitaoka 120a6e
        double t  = (w - w0) / (w1 - w0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TThickPoint p  = stroke->getThickPoint(w);
Shinya Kitaoka 120a6e
        TThickPoint b0 = TThickPoint((1 - t) * a0 + t * a1,
Shinya Kitaoka 120a6e
                                     (1 - t) * a0.thick + t * a1.thick);
Shinya Kitaoka 120a6e
        TThickPoint b1 = TThickPoint((1 - t) * a1 + t * a2,
Shinya Kitaoka 120a6e
                                     (1 - t) * a1.thick + t * a2.thick);
Shinya Kitaoka 120a6e
        TThickPoint c0 =
Shinya Kitaoka 120a6e
            TThickPoint(0.5 * a0 + 0.5 * b0, (1 - t) * a0.thick + t * b0.thick);
Shinya Kitaoka 120a6e
        TThickPoint c1 =
Shinya Kitaoka 120a6e
            TThickPoint(0.5 * b0 + 0.5 * p, (1 - t) * b0.thick + t * p.thick);
Shinya Kitaoka 120a6e
        TThickPoint c2 =
Shinya Kitaoka 120a6e
            TThickPoint(0.5 * c0 + 0.5 * c1, (1 - t) * c0.thick + t * c1.thick);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        d0 = (isInFirstChunk) ? c0 : a3;
Shinya Kitaoka 120a6e
        d1 = (isInFirstChunk) ? c2 : a2;
Shinya Kitaoka 120a6e
        d2 = (isInFirstChunk) ? c1 : b1;
Shinya Kitaoka 120a6e
        d3 = p;
Shinya Kitaoka 120a6e
        d4 = (isInFirstChunk) ? b1 : c1;
Shinya Kitaoka 120a6e
        d5 = (isInFirstChunk) ? a2 : c2;
Shinya Kitaoka 120a6e
        d6 = (isInFirstChunk) ? a3 : c0;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (isBeforePointLinear && !isNextPointLinear)
Shinya Kitaoka 120a6e
        d1 = computeLinearPoint(d0, d2, 0.01, false);
Shinya Kitaoka 120a6e
      else if (isNextPointLinear && !isBeforePointLinear)
Shinya Kitaoka 120a6e
        d5 = computeLinearPoint(d4, d6, 0.01, true);
Shinya Kitaoka 120a6e
      points.push_back(d0);
Shinya Kitaoka 120a6e
      points.push_back(d1);
Shinya Kitaoka 120a6e
      points.push_back(d2);
Shinya Kitaoka 120a6e
      points.push_back(d3);
Shinya Kitaoka 120a6e
      points.push_back(d4);
Shinya Kitaoka 120a6e
      points.push_back(d5);
Shinya Kitaoka 120a6e
      points.push_back(d6);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  stroke->reshape(&points[0], points.size());
Shinya Kitaoka 120a6e
  resetControlPoints();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  getPointTypeAt(pos, d, indexAtPos);
Shinya Kitaoka 120a6e
  return indexAtPos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::deleteControlPoint(int index) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(stroke && 0 <= index && index < (int)getControlPointCount());
Shinya Kitaoka 120a6e
  // E' un unico chunk e in questo caso rappresenta un punto
Shinya Kitaoka 120a6e
  if (stroke->getControlPointCount() <= 3 ||
Shinya Kitaoka 120a6e
      (isSelfLoop() && stroke->getControlPointCount() <= 5)) {
Shinya Kitaoka 120a6e
    m_controlPoints.clear();
Shinya Kitaoka 120a6e
    m_vi->deleteStroke(m_strokeIndex);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QList<int> newPointsIndex;</int>
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)getControlPointCount() - 1; i++)
Shinya Kitaoka 120a6e
    newPointsIndex.push_back(m_controlPoints[i].m_pointIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_controlPoints.removeAt(index);
Shinya Kitaoka 120a6e
  updatePoints();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Aggiorno gli indici dei punti nella stroke
Shinya Kitaoka 120a6e
  assert((int)newPointsIndex.size() == (int)getControlPointCount());
Shinya Kitaoka 120a6e
  for (i                            = 0; i < (int)getControlPointCount(); i++)
Shinya Kitaoka 120a6e
    m_controlPoints[i].m_pointIndex = newPointsIndex.at(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int prev = prevIndex(index);
Shinya Kitaoka 120a6e
  if (prev >= 0 && isSpeedOutLinear(prev)) {
Shinya Kitaoka 120a6e
    setLinearSpeedOut(prev);
Shinya Kitaoka 120a6e
    updateDependentPoint(prev);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (index < (int)m_controlPoints.size() && isSpeedInLinear(index)) {
Shinya Kitaoka 120a6e
    setLinearSpeedIn(index);
Shinya Kitaoka 120a6e
    updateDependentPoint(index);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveSpeed(int index, const TPointD &delta,
Shinya Kitaoka 120a6e
                                         bool isIn, double minDistance) {
Shinya Kitaoka 120a6e
  if (!isIn)
Shinya Kitaoka 120a6e
    moveSpeedOut(index, delta, minDistance);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    moveSpeedIn(index, delta, minDistance);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointEditorStroke::moveSegment(int beforeIndex, int nextIndex,
Shinya Kitaoka 120a6e
                                           const TPointD &delta,
Shinya Kitaoka 120a6e
                                           const TPointD &pos) {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int cpCount = getControlPointCount();
Shinya Kitaoka 120a6e
  // Verifiche per il caso in cui lo stroke e' selfLoop
Shinya Kitaoka 120a6e
  if (isSelfLoop() && beforeIndex == 0 && nextIndex == cpCount - 1)
Shinya Kitaoka 120a6e
    tswap(beforeIndex, nextIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int beforePointIndex = m_controlPoints[beforeIndex].m_pointIndex;
Shinya Kitaoka 120a6e
  int nextPointIndex   = (isSelfLoop() && nextIndex == 0)
Shinya Kitaoka 120a6e
                           ? stroke->getControlPointCount() - 1
Shinya Kitaoka 120a6e
                           : m_controlPoints[nextIndex].m_pointIndex;
Shinya Kitaoka 120a6e
  double w  = stroke->getW(pos);
Shinya Kitaoka 120a6e
  double w0 = stroke->getParameterAtControlPoint(beforePointIndex);
Shinya Kitaoka 120a6e
  double w4 = stroke->getParameterAtControlPoint(nextPointIndex);
Shinya Kitaoka 120a6e
  assert(w0 <= w && w <= w4);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double t = 1;
Shinya Kitaoka 120a6e
  double s = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isSpeedOutLinear(beforeIndex)) {
Shinya Kitaoka 120a6e
    m_controlPoints[beforeIndex].m_speedOut =
Shinya Kitaoka 120a6e
        (stroke->getControlPoint(nextPointIndex) -
Shinya Kitaoka 120a6e
         stroke->getControlPoint(beforePointIndex)) *
Shinya Kitaoka 120a6e
        0.3;
Shinya Kitaoka 120a6e
    if (!isSpeedInLinear(beforeIndex))
Shinya Kitaoka 120a6e
      m_controlPoints[beforeIndex].m_isCusp = true;
Shinya Kitaoka 120a6e
  } else if (!isSpeedOutLinear(beforeIndex) && !isSpeedInLinear(beforeIndex) &&
Shinya Kitaoka 120a6e
             !isCusp(beforeIndex)) {
Shinya Kitaoka 120a6e
    t = 1 - abs(w - w0) / abs(w4 - w0);
Shinya Kitaoka 120a6e
    moveSingleControlPoint(beforeIndex, t * delta);
Shinya Kitaoka 120a6e
    t = 1 - t;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isSpeedInLinear(nextIndex)) {
Shinya Kitaoka 120a6e
    m_controlPoints[nextIndex].m_speedIn =
Shinya Kitaoka 120a6e
        (stroke->getControlPoint(nextPointIndex) -
Shinya Kitaoka 120a6e
         stroke->getControlPoint(beforePointIndex)) *
Shinya Kitaoka 120a6e
        0.3;
Shinya Kitaoka 120a6e
    if (!isSpeedOutLinear(nextIndex))
Shinya Kitaoka 120a6e
      m_controlPoints[nextIndex].m_isCusp = true;
Shinya Kitaoka 120a6e
  } else if (!isSpeedInLinear(nextIndex) && !isSpeedOutLinear(nextIndex) &&
Shinya Kitaoka 120a6e
             !isCusp(nextIndex)) {
Shinya Kitaoka 120a6e
    s = 1 - abs(w4 - w) / abs(w4 - w0);
Shinya Kitaoka 120a6e
    moveSingleControlPoint(nextIndex, s * delta);
Shinya Kitaoka 120a6e
    s = 1 - s;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  moveSpeedOut(beforeIndex, delta * s, 0);
Shinya Kitaoka 120a6e
  // updateDependentPoint(beforeIndex);
Shinya Kitaoka 120a6e
  moveSpeedIn(nextIndex, delta * t, 0);
Shinya Kitaoka 120a6e
  // updateDependentPoint(nextIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  updatePoints();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ControlPointEditorStroke::PointType ControlPointEditorStroke::getPointTypeAt(
Shinya Kitaoka 120a6e
    const TPointD &pos, double &distance2, int &index) const {
Shinya Kitaoka 120a6e
  TStroke *stroke = getStroke();
Shinya Kitaoka 120a6e
  if (!stroke) return NONE;
Shinya Kitaoka 120a6e
  double w              = stroke->getW(pos);
Shinya Kitaoka 120a6e
  TPointD p             = stroke->getPoint(w);
Shinya Kitaoka 120a6e
  double strokeDistance = tdistance2(p, pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int precPointIndex     = -1;
Shinya Kitaoka 120a6e
  double minPrecDistance = 0;
Shinya Kitaoka 120a6e
  double minDistance2    = distance2;
Shinya Kitaoka 120a6e
  index                  = -1;
Shinya Kitaoka 120a6e
  PointType type         = NONE;
Shinya Kitaoka 120a6e
  int cpCount            = m_controlPoints.size();
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < cpCount; i++) {
Shinya Kitaoka 120a6e
    ControlPoint cPoint = m_controlPoints[i];
Shinya Kitaoka 120a6e
    TPointD point       = stroke->getControlPoint(cPoint.m_pointIndex);
Shinya Kitaoka 120a6e
    double cpDistance2  = tdistance2(pos, point);
Shinya Kitaoka 120a6e
    double distanceIn2  = !isSpeedInLinear(i)
Shinya Kitaoka 120a6e
                             ? tdistance2(pos, point - cPoint.m_speedIn)
Shinya Kitaoka 120a6e
                             : cpDistance2 + 1;
Shinya Kitaoka 120a6e
    double distanceOut2 = !isSpeedOutLinear(i)
Shinya Kitaoka 120a6e
                              ? tdistance2(pos, point + cPoint.m_speedOut)
Shinya Kitaoka 120a6e
                              : cpDistance2 + 1;
Shinya Kitaoka 120a6e
    if (i == 0 && !isSelfLoop())
Shinya Kitaoka 120a6e
      distanceIn2 = std::max(cpDistance2, distanceOut2) + 1;
Shinya Kitaoka 120a6e
    if (i == cpCount - 1 && !isSelfLoop())
Shinya Kitaoka 120a6e
      distanceOut2 = std::max(cpDistance2, distanceIn2) + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (cpDistance2 < distanceIn2 && cpDistance2 < distanceOut2 &&
Shinya Kitaoka 120a6e
        (cpDistance2 < minDistance2 || index < 0)) {
Shinya Kitaoka 120a6e
      minDistance2 = cpDistance2;
Shinya Kitaoka 120a6e
      index        = i;
Shinya Kitaoka 120a6e
      type         = CONTROL_POINT;
Shinya Kitaoka 120a6e
    } else if (distanceIn2 < cpDistance2 && distanceIn2 < distanceOut2 &&
Shinya Kitaoka 120a6e
               (distanceIn2 < minDistance2 || index < 0)) {
Shinya Kitaoka 120a6e
      minDistance2 = distanceIn2;
Shinya Kitaoka 120a6e
      index        = i;
Shinya Kitaoka 120a6e
      type         = SPEED_IN;
Shinya Kitaoka 120a6e
    } else if (distanceOut2 < cpDistance2 && distanceOut2 < distanceIn2 &&
Shinya Kitaoka 120a6e
               (distanceOut2 < minDistance2 || index < 0)) {
Shinya Kitaoka 120a6e
      minDistance2 = distanceOut2;
Shinya Kitaoka 120a6e
      index        = i;
Shinya Kitaoka 120a6e
      type         = SPEED_OUT;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double cpw =
Shinya Kitaoka 120a6e
        stroke->getParameterAtControlPoint(m_controlPoints[i].m_pointIndex);
Shinya Kitaoka 120a6e
    if (w <= cpw) continue;
Shinya Kitaoka 120a6e
    double precDistance = w - cpw;
Shinya Kitaoka 120a6e
    if (precPointIndex < 0 || precDistance < minPrecDistance) {
Shinya Kitaoka 120a6e
      precPointIndex  = i;
Shinya Kitaoka 120a6e
      minPrecDistance = precDistance;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (minDistance2 < distance2)
Shinya Kitaoka 120a6e
    distance2 = minDistance2;
Shinya Kitaoka 120a6e
  else if (strokeDistance > distance2) {
Shinya Kitaoka 120a6e
    distance2 = strokeDistance;
Shinya Kitaoka 120a6e
    index     = -1;
Shinya Kitaoka 120a6e
    type      = NONE;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    distance2 = minPrecDistance;
Shinya Kitaoka 120a6e
    index     = precPointIndex;
Shinya Kitaoka 120a6e
    type      = SEGMENT;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return type;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ControlPointSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ControlPointSelection::isSelected(int index) const {
Shinya Kitaoka 120a6e
  return m_selectedPoints.find(index) != m_selectedPoints.end();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::select(int index) {
Shinya Kitaoka 120a6e
  m_selectedPoints.insert(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::unselect(int index) {
Shinya Kitaoka 120a6e
  m_selectedPoints.erase(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::addMenuItems(QMenu *menu) {
Shinya Kitaoka 120a6e
  int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Shinya Kitaoka 120a6e
  if (isEmpty() || currentStrokeIndex == -1 ||
Shinya Kitaoka 120a6e
      (m_controlPointEditorStroke &&
Shinya Kitaoka 120a6e
       m_controlPointEditorStroke->getControlPointCount() <= 1))
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  QAction *linear   = menu->addAction(tr("Set Linear Control Point"));
Shinya Kitaoka 120a6e
  QAction *unlinear = menu->addAction(tr("Set Nonlinear Control Point"));
Shinya Kitaoka 120a6e
  menu->addSeparator();
Shinya Kitaoka 120a6e
  bool ret = connect(linear, SIGNAL(triggered()), this, SLOT(setLinear()));
Shinya Kitaoka 120a6e
  ret =
Shinya Kitaoka 120a6e
      ret && connect(unlinear, SIGNAL(triggered()), this, SLOT(setUnlinear()));
Shinya Kitaoka 120a6e
  assert(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::setLinear() {
Shinya Kitaoka 120a6e
  TTool *tool            = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Shinya Kitaoka 120a6e
  TVectorImageP vi(tool->getImage(false));
Shinya Kitaoka 120a6e
  if (!vi || isEmpty() || currentStrokeIndex == -1) return;
Shinya Kitaoka 120a6e
  TUndo *undo;
Shinya Kitaoka 120a6e
  if (tool->getApplication()->getCurrentObject()->isSpline())
Shinya Kitaoka 120a6e
    undo = new UndoPath(
Shinya Kitaoka 120a6e
        tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
        tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
    UndoControlPointEditor *cpEditorUndo =
Shinya Kitaoka 120a6e
        new UndoControlPointEditor(level, tool->getCurrentFid());
Shinya Kitaoka 120a6e
    cpEditorUndo->addOldStroke(currentStrokeIndex,
Shinya Kitaoka 120a6e
                               vi->getVIStroke(currentStrokeIndex));
Shinya Kitaoka 120a6e
    undo = cpEditorUndo;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_controlPointEditorStroke->getControlPointCount() == 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isChanged = m_controlPointEditorStroke->setControlPointsLinear(
Shinya Kitaoka 120a6e
      m_selectedPoints, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isChanged) return;
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Shinya Kitaoka 120a6e
  tool->notifyImageChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::setUnlinear() {
Shinya Kitaoka 120a6e
  TTool *tool            = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Shinya Kitaoka 120a6e
  TVectorImageP vi(tool->getImage(false));
Shinya Kitaoka 120a6e
  if (!vi || isEmpty() || currentStrokeIndex == -1) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TUndo *undo;
Shinya Kitaoka 120a6e
  if (tool->getApplication()->getCurrentObject()->isSpline())
Shinya Kitaoka 120a6e
    undo = new UndoPath(
Shinya Kitaoka 120a6e
        tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
        tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
    UndoControlPointEditor *cpEditorUndo =
Shinya Kitaoka 120a6e
        new UndoControlPointEditor(level, tool->getCurrentFid());
Shinya Kitaoka 120a6e
    cpEditorUndo->addOldStroke(currentStrokeIndex,
Shinya Kitaoka 120a6e
                               vi->getVIStroke(currentStrokeIndex));
Shinya Kitaoka 120a6e
    undo = cpEditorUndo;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_controlPointEditorStroke->getControlPointCount() == 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isChanged = m_controlPointEditorStroke->setControlPointsLinear(
Shinya Kitaoka 120a6e
      m_selectedPoints, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isChanged) return;
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Shinya Kitaoka 120a6e
  tool->notifyImageChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::deleteControlPoints() {
Shinya Kitaoka 120a6e
  TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  TVectorImageP vi(tool->getImage(false));
Shinya Kitaoka 120a6e
  int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Shinya Kitaoka 120a6e
  if (!vi || isEmpty() || currentStrokeIndex == -1) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Inizializzo l'UNDO
Shinya Kitaoka 120a6e
  TUndo *undo;
Shinya Kitaoka 120a6e
  bool isCurrentObjectSpline =
Shinya Kitaoka 120a6e
      tool->getApplication()->getCurrentObject()->isSpline();
Shinya Kitaoka 120a6e
  if (isCurrentObjectSpline)
Shinya Kitaoka 120a6e
    undo = new UndoPath(
Shinya Kitaoka 120a6e
        tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
        tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
    UndoControlPointEditor *cpEditorUndo =
Shinya Kitaoka 120a6e
        new UndoControlPointEditor(level, tool->getCurrentFid());
Shinya Kitaoka 120a6e
    cpEditorUndo->addOldStroke(currentStrokeIndex,
Shinya Kitaoka 120a6e
                               vi->getVIStroke(currentStrokeIndex));
Shinya Kitaoka 120a6e
    undo = cpEditorUndo;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = m_controlPointEditorStroke->getControlPointCount() - 1; i >= 0; i--)
Shinya Kitaoka 120a6e
    if (isSelected(i)) m_controlPointEditorStroke->deleteControlPoint(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_controlPointEditorStroke->getControlPointCount() == 0) {
Shinya Kitaoka 120a6e
    m_controlPointEditorStroke->setStroke((TVectorImage *)0, -1);
Shinya Kitaoka 120a6e
    if (!isCurrentObjectSpline) {
Shinya Kitaoka 120a6e
      UndoControlPointEditor *cpEditorUndo =
Shinya Kitaoka 120a6e
          dynamic_cast<undocontrolpointeditor *="">(undo);</undocontrolpointeditor>
Shinya Kitaoka 120a6e
      if (cpEditorUndo) cpEditorUndo->isStrokeDelete(true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // La spline non puo' essere cancellata completamente!!!
Shinya Kitaoka 120a6e
  if (vi->getStrokeCount() == 0) {
Shinya Kitaoka 120a6e
    if (TTool::getApplication()->getCurrentObject()->isSpline()) {
Shinya Kitaoka 120a6e
      std::vector<tpointd> points;</tpointd>
Shinya Kitaoka 120a6e
      double d = 10;
Shinya Kitaoka 120a6e
      points.push_back(TPointD(-d, 0));
Shinya Kitaoka 120a6e
      points.push_back(TPointD(0, 0));
Shinya Kitaoka 120a6e
      points.push_back(TPointD(d, 0));
Shinya Kitaoka 120a6e
      TStroke *stroke = new TStroke(points);
Shinya Kitaoka 120a6e
      vi->addStroke(stroke, false);
Shinya Kitaoka 120a6e
      m_controlPointEditorStroke->setStrokeIndex(0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  tool->notifyImageChanged();
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
  // Registro l'UNDO
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ControlPointSelection::enableCommands() {
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Clear", &ControlPointSelection::deleteControlPoints);
Toshihiro Shimizu 890ddd
}