Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
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 "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "drawutil.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
//=============================================================================
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const UINT MAX_SAMPLE = 2;
Shinya Kitaoka 120a6e
const int MY_ERROR    = -1;
Toshihiro Shimizu 890ddd
MCCCS a0ce32
const double c_LengthOfBenderRegion = 10.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int IS_BEGIN = 0;
Shinya Kitaoka 120a6e
const int IS_END   = 1;
Shinya Kitaoka 120a6e
const int IS_ALL   = 2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double _extractFirst(DoublePair val) { return val.first; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double _extractSecond(DoublePair val) { return val.second; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool strokeIsConnected(const TStroke &s, double toll = TConsts::epsilon) {
Shinya Kitaoka 120a6e
  bool out          = true;
Shinya Kitaoka 120a6e
  int count         = s.getChunkCount();
Shinya Kitaoka 120a6e
  long double toll2 = sq(TConsts::epsilon);
Shinya Kitaoka 120a6e
  if (count > 0) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *refTQ = s.getChunk(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int i = 1; i < count; ++i) {
Shinya Kitaoka 120a6e
      if (out && tdistance2(refTQ->getP2(), s.getChunk(i)->getP0()) > toll2)
Shinya Kitaoka 120a6e
        out = false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool strokeIsConnected(const TStroke *s,
Shinya Kitaoka 120a6e
                              double toll = TConsts::epsilon) {
Shinya Kitaoka 120a6e
  assert(s);
Shinya Kitaoka 120a6e
  return strokeIsConnected(*s, toll);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
Extract an value of a pair.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void extract(const std::vector<doublepair> &s, ArrayOfDouble &d,</doublepair>
Shinya Kitaoka 120a6e
             bool isFirstOrSecond = true) {
Shinya Kitaoka 120a6e
  if (isFirstOrSecond)
Shinya Kitaoka 120a6e
    std::transform(s.begin(), s.end(), back_inserter(d), _extractFirst);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    std::transform(s.begin(), s.end(), back_inserter(d), _extractSecond);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double retrieveInitLength(double strokeLength, int beginEndOrAll) {
Shinya Kitaoka 120a6e
  double initLength = MY_ERROR;
Shinya Kitaoka 120a6e
  switch (beginEndOrAll) {
Shinya Kitaoka 120a6e
  case IS_BEGIN:
Shinya Kitaoka 120a6e
    initLength = 0.0;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case IS_END:
Shinya Kitaoka 120a6e
    initLength = strokeLength;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case IS_ALL:
Shinya Kitaoka 120a6e
    initLength = strokeLength * 0.5;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return initLength;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isOdd(UINT val) { return val & 1 ? true : false; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isEven(UINT val) { return !isOdd(val); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void clearPointerMap(std::map<tstroke *,="" std::vector<int=""> *> &corners) {</tstroke>
Shinya Kitaoka 120a6e
  std::map<tstroke *,="" std::vector<int=""> *>::iterator it = corners.begin();</tstroke>
Shinya Kitaoka 120a6e
  for (; it != corners.end(); ++it) {
Shinya Kitaoka 120a6e
    delete it->second;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// Bender Tool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class BenderTool final : public TTool {
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  TUndo *m_undo;
Shinya Kitaoka 120a6e
  bool m_atLeastOneIsChanged;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<bool> m_directionIsChanged;</bool>
Shinya Kitaoka 120a6e
  std::vector<tpointd> m_accumulator;</tpointd>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void increaseCP(TStroke *, int);
Shinya Kitaoka 120a6e
  bool m_active;
Shinya Kitaoka 120a6e
  int m_cursor;
Shinya Kitaoka 120a6e
  enum PNT_SELECTED { BNDR_NULL = 0, BNDR_P0 = 1, BNDR_P1 = 2 };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  struct benderStrokeInfo {
Shinya Kitaoka 120a6e
    TStroke *m_stroke;
Shinya Kitaoka 120a6e
    DoublePair m_extremes;
Shinya Kitaoka 120a6e
    int m_isBeginEndOrAll;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    benderStrokeInfo(TStroke *stroke, DoublePair &info, int isBeginEndOrAll) {
Shinya Kitaoka 120a6e
      m_stroke          = stroke;
Shinya Kitaoka 120a6e
      m_extremes        = info;
Shinya Kitaoka 120a6e
      m_isBeginEndOrAll = isBeginEndOrAll;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  std::vector<benderstrokeinfo> m_info;</benderstrokeinfo>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // contains information about stroke which have
Shinya Kitaoka 120a6e
  //  intersection with benderSegment
Shinya Kitaoka 120a6e
  std::map<tstroke *,="" arrayofstroke=""> m_metaStroke;</tstroke>
Shinya Kitaoka 120a6e
  std::map<tstroke *,="" std::vector<int=""> *> m_hitStrokeCorners;</tstroke>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_showTangents;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // value selected
Shinya Kitaoka 120a6e
  int m_buttonDownCounter;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TSegment m_benderSegment;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD m_prevPoint;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double m_rotationVersus;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //!
Shinya Kitaoka 120a6e
  ArrayOfStroke m_strokesToRotate;
Shinya Kitaoka 120a6e
  //!
Shinya Kitaoka 120a6e
  ArrayOfStroke m_strokesToBend;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<int> m_changedStrokes;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_enableDragSelection;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void findCurves(TVectorImageP &);
Shinya Kitaoka 120a6e
  void findVersus(const TPointD &p);
Shinya Kitaoka 120a6e
  double computeRotationVersus(const TPointD &, const TPointD &);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  void initBenderAction(TVectorImageP &, const TPointD &);
Shinya Kitaoka 120a6e
  // BenderTool(TVectorImageP  vimage, GLTestWidget* ref );
Shinya Kitaoka 120a6e
  BenderTool();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  virtual ~BenderTool();
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  ToolType getToolType() const override { return TTool::LevelWriteTool; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void draw() override;
Shinya Kitaoka 473e70
  void leftButtonDown(const TPointD &, const TMouseEvent &) override;
Shinya Kitaoka 473e70
  void leftButtonDrag(const TPointD &, const TMouseEvent &) override;
Shinya Kitaoka 473e70
  void leftButtonUp(const TPointD &, const TMouseEvent &) override;
Shinya Kitaoka 473e70
  void onEnter() override;
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onActivate() override {
Shinya Kitaoka 120a6e
    m_buttonDownCounter = 1;
Shinya Kitaoka 120a6e
    m_prevPoint         = TConsts::napd;
Shinya Kitaoka 120a6e
    m_benderSegment.setP0(TConsts::napd);
Shinya Kitaoka 120a6e
    m_benderSegment.setP1(TConsts::napd);
Shinya Kitaoka 120a6e
    m_metaStroke.clear();
Shinya Kitaoka 120a6e
    clearPointerMap(m_hitStrokeCorners);
Shinya Kitaoka 120a6e
    m_hitStrokeCorners.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getCursorId() const override { return m_cursor; }
Toshihiro Shimizu 890ddd
} BenderTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
BenderTool::BenderTool()
Shinya Kitaoka 120a6e
    : TTool("T_Bender")
Shinya Kitaoka 120a6e
    , m_showTangents(false)
Shinya Kitaoka 120a6e
    , m_buttonDownCounter(1)
Shinya Kitaoka 120a6e
    , m_rotationVersus(0.0)
Shinya Kitaoka 120a6e
    , m_enableDragSelection(false)
Shinya Kitaoka 120a6e
    , m_undo(0)
Shinya Kitaoka 120a6e
    , m_cursor(ToolCursor::BenderCursor) {
Shinya Kitaoka 120a6e
  bind(TTool::Vectors);
Shinya Kitaoka 120a6e
  m_prevPoint = TConsts::napd;
Shinya Kitaoka 120a6e
  m_benderSegment.setP0(TConsts::napd);
Shinya Kitaoka 120a6e
  m_benderSegment.setP1(TConsts::napd);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
BenderTool::~BenderTool() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::onEnter() {
Shinya Kitaoka 120a6e
  if ((TVectorImageP)getImage(false))
Shinya Kitaoka 120a6e
    m_cursor = ToolCursor::BenderCursor;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_cursor = ToolCursor::CURSOR_NO;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) {
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
Shinya Kitaoka 120a6e
  m_active = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tstroke *=""> oldStrokesArray(m_changedStrokes.size());</tstroke>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i               = 0; i < (int)m_changedStrokes.size(); i++)
Shinya Kitaoka 120a6e
    oldStrokesArray[i] = new TStroke(*(vi->getStroke(m_changedStrokes[i])));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (3 == m_buttonDownCounter) {
Shinya Kitaoka 120a6e
    m_rotationVersus = 0.0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // hide bender tool
Shinya Kitaoka 120a6e
    m_prevPoint = TConsts::napd;
Shinya Kitaoka 120a6e
    m_benderSegment.setP0(TConsts::napd);
Shinya Kitaoka 120a6e
    m_benderSegment.setP1(TConsts::napd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    typedef std::map<tstroke *,="" arrayofstroke="">::iterator itAATS;</tstroke>
Shinya Kitaoka 120a6e
    // UINT count=0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (itAATS it1 = m_metaStroke.begin(); it1 != m_metaStroke.end(); ++it1) {
Shinya Kitaoka 120a6e
      UINT i;
Shinya Kitaoka 120a6e
      // copy vector and...
Shinya Kitaoka 120a6e
      ArrayOfStroke &refA = it1->second;
Shinya Kitaoka 120a6e
      TStroke *s          = it1->first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TStroke *out = merge(refA);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      out->reduceControlPoints(getPixelSize(), *(m_hitStrokeCorners[s]));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (it1->first->isSelfLoop()) {
Shinya Kitaoka 120a6e
        int cpCount      = out->getControlPointCount();
Shinya Kitaoka 120a6e
        TThickPoint p1   = out->getControlPoint(0);
Shinya Kitaoka 120a6e
        TThickPoint p2   = out->getControlPoint(cpCount - 1);
Shinya Kitaoka 120a6e
        TThickPoint midP = (p1 + p2) * 0.5;
Shinya Kitaoka 120a6e
        out->setControlPoint(0, midP);
Shinya Kitaoka 120a6e
        out->setControlPoint(cpCount - 1, midP);
Shinya Kitaoka 120a6e
        out->setSelfLoop(true);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      it1->first->swap(*out);
Shinya Kitaoka 120a6e
      it1->first->setStyle(out->getStyle());
Shinya Kitaoka 120a6e
      it1->first->outlineOptions() = out->outlineOptions();
Shinya Kitaoka 120a6e
      it1->first->invalidate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (i = 0; i < refA.size(); ++i) delete refA[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      delete out;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_metaStroke.clear();
Shinya Kitaoka 120a6e
    clearPointerMap(m_hitStrokeCorners);
Shinya Kitaoka 120a6e
    m_hitStrokeCorners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_buttonDownCounter = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT lastCpIndex, i, size = m_changedStrokes.size();
Shinya Kitaoka 120a6e
    TStroke *stroke;
Shinya Kitaoka 120a6e
    TThickPoint p1, p2, middleP;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double loopError = 0.5 * getPixelSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < size; i++) {
Shinya Kitaoka 120a6e
      stroke = vi->getStroke(m_changedStrokes[i]);
Shinya Kitaoka 120a6e
      if (m_directionIsChanged[i]) stroke->changeDirection();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      lastCpIndex = stroke->getControlPointCount() - 1;
Shinya Kitaoka 120a6e
      p1          = stroke->getControlPoint(0);
Shinya Kitaoka 120a6e
      p2          = stroke->getControlPoint(lastCpIndex);
Shinya Kitaoka 120a6e
      if (isAlmostZero(p1.x - p2.x, loopError) &&
Shinya Kitaoka 120a6e
          isAlmostZero(p1.y - p2.y, loopError)) {
Shinya Kitaoka 120a6e
        middleP = (p1 + p2) * 0.5;
Shinya Kitaoka 120a6e
        stroke->setControlPoint(0, middleP);
Shinya Kitaoka 120a6e
        stroke->setControlPoint(lastCpIndex, middleP);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        stroke->setSelfLoop(false);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    vi->notifyChangedStrokes(m_changedStrokes, oldStrokesArray);
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_undo) TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
    m_undo = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  clearPointerContainer(oldStrokesArray);
Shinya Kitaoka 120a6e
  m_active = false;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  if (!m_active) return;
Shinya Kitaoka 120a6e
  TVectorImageP vi = TImageP(getImage(true));
Shinya Kitaoka 120a6e
  if (!vi) return;
Shinya Kitaoka 120a6e
  QMutexLocker lock(vi->getMutex());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
  if (tdistance2(pos, m_prevPoint) < 9.0 * pixelSize * pixelSize) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_buttonDownCounter < 3) return;
Shinya Kitaoka 120a6e
  if (m_enableDragSelection) {
Shinya Kitaoka 120a6e
    m_accumulator.push_back(pos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_accumulator.size() < 3) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TPointD middlePnt;
Shinya Kitaoka 120a6e
    accumulate(m_accumulator.begin(), m_accumulator.end(), middlePnt);
Shinya Kitaoka 120a6e
    static const double inv_of_3 = 1.0 / 2.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    middlePnt = inv_of_3 * middlePnt;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_accumulator.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    initBenderAction(vi, pos + middlePnt);
Shinya Kitaoka 120a6e
    m_enableDragSelection = false;
Shinya Kitaoka 120a6e
    m_buttonDownCounter   = 3;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD p = pos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD vc(p - m_benderSegment.getP0()),        // current vector
Shinya Kitaoka 120a6e
      vp(m_prevPoint - m_benderSegment.getP0());  // previous vector
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD s2v = m_benderSegment.getSpeed();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // some check to jump invalid case
Shinya Kitaoka 120a6e
  double norm2BenderSeg    = norm2(s2v);
Shinya Kitaoka 120a6e
  double norm2CurrentVect  = norm2(vc);
Shinya Kitaoka 120a6e
  double norm2PreviousVect = norm2(vp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // invalid segments
Shinya Kitaoka 120a6e
  if (0.0 == norm2BenderSeg || 0.0 == norm2PreviousVect ||
Shinya Kitaoka 120a6e
      0.0 == norm2CurrentVect)
Shinya Kitaoka 120a6e
    return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // invalid rotation versus
Shinya Kitaoka 120a6e
  if (tsign(cross(s2v, vc)) != m_rotationVersus) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // compute delta of rotation angle
Shinya Kitaoka 120a6e
  double diff = asin(cross(normalize(vp), normalize(vc)));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // make a rototranslation matrix
Shinya Kitaoka 120a6e
  TRotation rot(m_benderSegment.getP0(), rad2degree(diff));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // rotate references
Shinya Kitaoka 120a6e
  for (itAS its = m_strokesToRotate.begin(); its != m_strokesToRotate.end();
Shinya Kitaoka 120a6e
       ++its)
Shinya Kitaoka 120a6e
    (*its)->transform(rot);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // deform strokes
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_info.size(); ++i) {
Shinya Kitaoka 120a6e
    TStroke &ref = *m_info[i].m_stroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // DoublePair  &extr   = m_info[i].m_extremes;
Shinya Kitaoka 120a6e
    double strokeLength = ref.getLength();
Shinya Kitaoka 120a6e
    double initLength   = retrieveInitLength(
Shinya Kitaoka 120a6e
        strokeLength, m_info[i].m_isBeginEndOrAll);  // ? 0.0 : strokeLength;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (MY_ERROR == initLength) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int innerOrOuter = m_info[i].m_isBeginEndOrAll == IS_ALL
Shinya Kitaoka 120a6e
                           ? TStrokeBenderDeformation::OUTER
Shinya Kitaoka 120a6e
                           : TStrokeBenderDeformation::INNER;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TStrokeBenderDeformation def(&ref, m_benderSegment.getP0(), diff,
Shinya Kitaoka 120a6e
                                 initLength, innerOrOuter, strokeLength);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    modifyControlPoints(ref, def);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // fix previous point
Shinya Kitaoka 120a6e
  m_prevPoint = p;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::leftButtonDown(const TPointD &p, const TMouseEvent &) {
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
  switch (m_buttonDownCounter) {
Shinya Kitaoka 120a6e
  case 1:
Shinya Kitaoka 120a6e
    findCurves(vi);
Shinya Kitaoka 120a6e
    m_strokesToRotate.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // le curve puntate sono state eliminate dalla clear precedente
Shinya Kitaoka 120a6e
    m_info.clear();
Shinya Kitaoka 120a6e
    m_benderSegment.setP0(p);
Shinya Kitaoka 120a6e
    m_benderSegment.setP1(p);
Toshihiro Shimizu 890ddd
    break;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  case 2:  // second buttonDown
Shinya Kitaoka 120a6e
    m_prevPoint = p;
Shinya Kitaoka 120a6e
    m_benderSegment.setP1(p);
Shinya Kitaoka 120a6e
    m_enableDragSelection = true;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
case 3: // third buttonDown
Shinya Kitaoka 120a6e
// initBenderAction( vi, p );
Shinya Kitaoka 120a6e
break;
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ++m_buttonDownCounter;
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  // vi->validateRegionEdges(vi->getStroke( m_strokeIndex ), true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::findVersus(const TPointD &p) {
Shinya Kitaoka 120a6e
  TPointD v1 = m_benderSegment.getSpeed(), v2 = p - m_benderSegment.getP0();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // fix rotation versus
Shinya Kitaoka 120a6e
  m_rotationVersus = tsign(cross(v1, v2));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isAlmostZero(m_rotationVersus)) m_rotationVersus = 1.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void one_minus_x(double &x) { x = 1.0 - x; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::findCurves(TVectorImageP &vi) {
Shinya Kitaoka 120a6e
  ArrayOfStroke strokeToModify;
Shinya Kitaoka 120a6e
  m_changedStrokes.clear();
Shinya Kitaoka 120a6e
  m_directionIsChanged.clear();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT j;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < vi->getStrokeCount(); ++i)  // for all stroke in image
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    if (!vi->inCurrentGroup(i)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *s = vi->getStroke(i);  // a useful reference
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    std::vector<doublepair> pair_intersection;  // informations about extremes</doublepair>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // if there is interesection between stroke and bender tool
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (intersect(*s, m_benderSegment, pair_intersection)) {
Shinya Kitaoka 120a6e
      if (s->isSelfLoop()) {
Shinya Kitaoka 120a6e
        // make the semgnet longer
Shinya Kitaoka 120a6e
        // such as the points are just a littleBit
Shinya Kitaoka 120a6e
        // outside the stroke bbox
Shinya Kitaoka 120a6e
        const double littleBit = 0.1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TRectD bbox = s->getBBox();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TPointD bboxP0 = bbox.getP00();
Shinya Kitaoka 120a6e
        TPointD bboxP1 = bbox.getP11();
Shinya Kitaoka 120a6e
        double bboxX0  = std::min(bboxP0.x, bboxP1.x);
Shinya Kitaoka 120a6e
        double bboxX1  = std::max(bboxP0.x, bboxP1.x);
Shinya Kitaoka 120a6e
        double bboxY0  = std::min(bboxP0.y, bboxP1.y);
Shinya Kitaoka 120a6e
        double bboxY1  = std::max(bboxP0.y, bboxP1.y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TSegment segment;
Shinya Kitaoka 120a6e
        TPointD pp0 = m_benderSegment.getP0();
Shinya Kitaoka 120a6e
        TPointD pp1 = m_benderSegment.getP1();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TPointD newP0;
Shinya Kitaoka 120a6e
        TPointD newP1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (bbox.contains(pp1)) {
Shinya Kitaoka 120a6e
          double x = (pp0.x < pp1.x) ? bboxX1 : bboxX0;
Shinya Kitaoka 120a6e
          double y = (pp0.y < pp1.y) ? bboxY1 : bboxY0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          double t;
Shinya Kitaoka 120a6e
          if (pp1.x == pp0.x && pp1.y == pp0.y) {
Shinya Kitaoka 120a6e
            assert(!"segmento del bender puntiforme");
Shinya Kitaoka 120a6e
            return;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (pp1.x == pp0.x)
Shinya Kitaoka 120a6e
            t = (y - pp0.y) / (pp1.y - pp0.y);
Shinya Kitaoka 120a6e
          else if (pp1.y == pp0.y)
Shinya Kitaoka 120a6e
            t = (x - pp0.x) / (pp1.x - pp0.x);
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            t = std::min((x - pp0.x) / (pp1.x - pp0.x),
Shinya Kitaoka 120a6e
                         (y - pp0.y) / (pp1.y - pp0.y));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          newP1 = (t > 1) ? m_benderSegment.getPoint(t + littleBit) : pp1;
Shinya Kitaoka 120a6e
        } else
Shinya Kitaoka 120a6e
          newP1 = pp1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (bbox.contains(pp0)) {
Shinya Kitaoka 120a6e
          double x = (pp0.x > pp1.x) ? bboxX1 : bboxX0;
Shinya Kitaoka 120a6e
          double y = (pp0.y > pp1.y) ? bboxY1 : bboxY0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          double t;
Shinya Kitaoka 120a6e
          if (pp1.x == pp0.x && pp1.y == pp0.y) {
Shinya Kitaoka 120a6e
            assert(!"segmento del bender puntiforme");
Shinya Kitaoka 120a6e
            return;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (pp1.x == pp0.x)
Shinya Kitaoka 120a6e
            t = (y - pp0.y) / (pp1.y - pp0.y);
Shinya Kitaoka 120a6e
          else if (pp1.y == pp0.y)
Shinya Kitaoka 120a6e
            t = (x - pp0.x) / (pp1.x - pp0.x);
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            t = std::max((x - pp0.x) / (pp1.x - pp0.x),
Shinya Kitaoka 120a6e
                         (y - pp0.y) / (pp1.y - pp0.y));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          newP0 = (t < 0) ? m_benderSegment.getPoint(t - littleBit) : pp0;
Shinya Kitaoka 120a6e
        } else
Shinya Kitaoka 120a6e
          newP0 = pp0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        segment = TSegment(newP0, newP1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        pair_intersection.clear();
Shinya Kitaoka 120a6e
        intersect(*s, segment, pair_intersection);
Shinya Kitaoka 120a6e
        assert(isEven(pair_intersection.size()));
Shinya Kitaoka 120a6e
        assert(!pair_intersection.empty());
Shinya Kitaoka 120a6e
        if (pair_intersection.empty())  // non dovrebbe accadere
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      //-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      strokeToModify.push_back(s);
Shinya Kitaoka 120a6e
      m_changedStrokes.push_back(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      //-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_metaStroke[s] = ArrayOfStroke();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      ArrayOfStroke &tempAS = m_metaStroke[s];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // extract information about intersection parameter
Shinya Kitaoka 120a6e
      ArrayOfDouble intersection;
Shinya Kitaoka 120a6e
      extract(pair_intersection, intersection);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // now add stroke to rotate in m_info struct
Shinya Kitaoka 120a6e
      TPointD v = s->getSpeed(intersection[0]);
Shinya Kitaoka 120a6e
      TPointD normalToBenderSeg;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      normalToBenderSeg =
Shinya Kitaoka 120a6e
          m_rotationVersus * rotate90(m_benderSegment.getSpeed());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_atLeastOneIsChanged = false;
Shinya Kitaoka 120a6e
      // m_directionIsChanged = false;
Shinya Kitaoka 120a6e
      if (tsign(v * normalToBenderSeg) < 0) {
Shinya Kitaoka 120a6e
        m_atLeastOneIsChanged = true;
Shinya Kitaoka 120a6e
        m_directionIsChanged.push_back(true);
Shinya Kitaoka 120a6e
        std::for_each(intersection.begin(), intersection.end(), one_minus_x);
Shinya Kitaoka 120a6e
        std::reverse(intersection.begin(), intersection.end());
Shinya Kitaoka 120a6e
        s->changeDirection();
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        m_directionIsChanged.push_back(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      splitStroke(*s, intersection, tempAS);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // number of curves is number of intersection plus one
Shinya Kitaoka 120a6e
      UINT numberOfCurves = intersection.size() + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // and begin increase of control point
Shinya Kitaoka 120a6e
      if (isEven(intersection.size()) &&
Shinya Kitaoka 120a6e
          m_atLeastOneIsChanged)  // if solution are even
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        for (j = 0; j < numberOfCurves; ++j) {
Shinya Kitaoka 120a6e
          if (isOdd(j))
Shinya Kitaoka 120a6e
            increaseCP(tempAS[j], IS_ALL);
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            m_strokesToRotate.push_back(tempAS[j]);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        increaseCP(tempAS[0], IS_END);
Shinya Kitaoka 120a6e
        for (j = 1; j < numberOfCurves - 1; ++j) {
Shinya Kitaoka 120a6e
          if (isEven(j))
Shinya Kitaoka 120a6e
            increaseCP(tempAS[j], IS_ALL);
Shinya Kitaoka 120a6e
          else
Shinya Kitaoka 120a6e
            m_strokesToRotate.push_back(tempAS[j]);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (isOdd(numberOfCurves))
Shinya Kitaoka 120a6e
          increaseCP(tempAS.back(), IS_BEGIN);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          m_strokesToRotate.push_back(tempAS.back());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TStroke *tempForCorners   = merge(tempAS);
Shinya Kitaoka 120a6e
      std::vector<int> *corners = new std::vector<int>;</int></int>
Shinya Kitaoka 120a6e
      corners->push_back(0);
Shinya Kitaoka 120a6e
      detectCorners(tempForCorners, 20, *corners);
Shinya Kitaoka 120a6e
      corners->push_back(tempForCorners->getChunkCount());
Shinya Kitaoka 120a6e
      m_hitStrokeCorners[s] = corners;
Shinya Kitaoka 120a6e
      delete tempForCorners;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!strokeToModify.empty()) {
Shinya Kitaoka 120a6e
    UINT i, size = strokeToModify.size();
Shinya Kitaoka 120a6e
    for (i = 0; i < size; i++)
Shinya Kitaoka 120a6e
      if (m_directionIsChanged[i]) strokeToModify[i]->changeDirection();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (TTool::getApplication()->getCurrentObject()->isSpline())
Shinya Kitaoka 120a6e
      m_undo =
Shinya Kitaoka 120a6e
          new UndoPath(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, strokeToModify);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < size; i++)
Shinya Kitaoka 120a6e
      if (m_directionIsChanged[i]) strokeToModify[i]->changeDirection();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::increaseCP(TStroke *tmpStroke, int beginEndOrAll) {
Shinya Kitaoka 120a6e
  DoublePair extremes;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double strokeLength = tmpStroke->getLength();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double initLength = retrieveInitLength(strokeLength, beginEndOrAll);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (MY_ERROR == initLength) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStrokeBenderDeformation deformer(tmpStroke, initLength, strokeLength * 0.5);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  increaseControlPoints(*tmpStroke, deformer, getPixelSize());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tmpStroke->disableComputeOfCaches();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_info.push_back(benderStrokeInfo(tmpStroke, extremes, beginEndOrAll));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::draw() {
Shinya Kitaoka 120a6e
  // TAffine viewMatrix = getViewer()->getViewMatrix();
Shinya Kitaoka 120a6e
  // glPushMatrix();
Shinya Kitaoka 120a6e
  // tglMultMatrix(viewMatrix);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double pixelSize = getPixelSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  typedef std::map<tstroke *,="" arrayofstroke="">::const_iterator mapTACit;</tstroke>
Shinya Kitaoka 120a6e
  for (mapTACit cit1 = m_metaStroke.begin(); cit1 != m_metaStroke.end();
Shinya Kitaoka 120a6e
       ++cit1) {
Shinya Kitaoka 120a6e
    const ArrayOfStroke &tmp = (*cit1).second;
Shinya Kitaoka 120a6e
    tglColor(TPixel32::Red);
Shinya Kitaoka 120a6e
    for (citAS cit2 = tmp.begin(); cit2 != tmp.end(); ++cit2)
Shinya Kitaoka 120a6e
      drawStrokeCenterline(**cit2, pixelSize);
Shinya Kitaoka 120a6e
    // drawStroke(**cit2, TRect(0,0,1000,1000), TAffine() );
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double length = m_benderSegment.getLength();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // pnt to draw rotation vector
Shinya Kitaoka 120a6e
  TPointD pnt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (length != 0.0) {
Shinya Kitaoka 120a6e
    TPointD v  = m_prevPoint - m_benderSegment.getP0();
Shinya Kitaoka 120a6e
    double tmp = norm2(v);
Shinya Kitaoka 120a6e
    if (tmp != 0.0) {
Shinya Kitaoka 120a6e
      pnt = v * (length / sqrt(tmp));
Shinya Kitaoka 120a6e
      pnt += m_benderSegment.getP0();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    pnt = m_prevPoint;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // rotation vector
Shinya Kitaoka 120a6e
  if (m_buttonDownCounter == 3) {
Shinya Kitaoka 120a6e
    tglColor(TPixel::Black);
Shinya Kitaoka 120a6e
    tglDrawSegment(m_benderSegment.getP0(), pnt);
Shinya Kitaoka 120a6e
    drawPoint(pnt, pixelSize);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // bender vector
Shinya Kitaoka 120a6e
  tglColor(TPixel::Red);
Shinya Kitaoka 120a6e
  tglDrawSegment(m_benderSegment.getP0(), m_benderSegment.getP1());
Shinya Kitaoka 120a6e
  drawPoint(m_benderSegment.getP0(), pixelSize);
Shinya Kitaoka 120a6e
  drawPoint(m_benderSegment.getP1(), pixelSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // point where is mouse pointer
Shinya Kitaoka 120a6e
  drawPoint(m_prevPoint, pixelSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // arrow in up direction
Shinya Kitaoka 120a6e
  TPointD vDir   = m_benderSegment.getSpeed();
Shinya Kitaoka 120a6e
  double length2 = norm2(vDir);
Shinya Kitaoka 120a6e
  if (length2 == 0.0) {
Shinya Kitaoka 120a6e
    // glPopMatrix();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TPointD vUp = 15.0 * normalize(rotate90(vDir));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tglColor(TPixel::Magenta);
Shinya Kitaoka 120a6e
  TPointD middlePnt = 0.5 * (m_benderSegment.getP0() + m_benderSegment.getP1());
Shinya Kitaoka 120a6e
  drawArrow(TSegment(middlePnt, m_rotationVersus * vUp + middlePnt), pixelSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // glPopMatrix();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void BenderTool::initBenderAction(TVectorImageP &vi, const TPointD &p) {
Shinya Kitaoka 120a6e
  // reset counter
Shinya Kitaoka 120a6e
  // m_buttonDownCounter = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Versus of bender segment depends from
Shinya Kitaoka 120a6e
  //  point selected to do rotation
Shinya Kitaoka 120a6e
  // P0 is always center of rotation
Shinya Kitaoka 120a6e
  if (tdistance2(p, m_benderSegment.getP0()) <
Shinya Kitaoka 120a6e
      tdistance2(p, m_benderSegment.getP1())) {
Shinya Kitaoka 120a6e
    TPointD tmpPnt = m_benderSegment.getP1();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_benderSegment.setP1(m_benderSegment.getP0());
Shinya Kitaoka 120a6e
    m_benderSegment.setP0(tmpPnt);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // fix information about versus
Shinya Kitaoka 120a6e
  findVersus(p);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // find curves to bender and init data structures
Shinya Kitaoka 120a6e
  findCurves(vi);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // now it's possible set first position of rotation
Shinya Kitaoka 120a6e
  // in the same position of extremes
Shinya Kitaoka 120a6e
  m_benderSegment.setP1(p);
Shinya Kitaoka 120a6e
  m_prevPoint = p;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// TTool *getBenderTool() {return &BenderTool;}