Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/imageutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/strokegenerator.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage2.h"
manongjohn 75da26
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tenv.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "tproperty.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tinbetween.h"
Toshihiro Shimizu 890ddd
#include "drawutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Shinya Kitaoka 120a6e
#include <qcoreapplication>  // For Qt translation support</qcoreapplication>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TEnv::DoubleVar EraseVectorSize("InknpaintEraseVectorSize", 10);
Toshihiro Shimizu 890ddd
TEnv::StringVar EraseVectorType("InknpaintEraseVectorType", "Normal");
pojienie 4998cf
TEnv::StringVar EraseVectorInterpolation("InknpaintEraseVectorInterpolation",
pojienie 4998cf
                                         "Linear");
Toshihiro Shimizu 890ddd
TEnv::IntVar EraseVectorSelective("InknpaintEraseVectorSelective", 0);
Toshihiro Shimizu 890ddd
TEnv::IntVar EraseVectorInvert("InknpaintEraseVectorInvert", 0);
Toshihiro Shimizu 890ddd
TEnv::IntVar EraseVectorRange("InknpaintEraseVectorRange", 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Shinya Kitaoka 120a6e
// Eraser Tool
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NORMAL_ERASE L"Normal"
Toshihiro Shimizu 890ddd
#define RECT_ERASE L"Rectangular"
Toshihiro Shimizu 890ddd
#define FREEHAND_ERASE L"Freehand"
Toshihiro Shimizu 890ddd
#define POLYLINE_ERASE L"Polyline"
pojienie 31955e
#define SEGMENT_ERASE L"Segment"
Toshihiro Shimizu 890ddd
pojienie 4998cf
#define LINEAR_INTERPOLATION L"Linear"
pojienie 4998cf
#define EASE_IN_INTERPOLATION L"Ease In"
pojienie 4998cf
#define EASE_OUT_INTERPOLATION L"Ease Out"
pojienie 4998cf
#define EASE_IN_OUT_INTERPOLATION L"Ease In/Out"
pojienie 4998cf
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const double minDistance2 = 16.0;  // 4 pixel
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void mapToVector(const std::map<int, *="" vistroke=""> &theMap,</int,>
Shinya Kitaoka 120a6e
                 std::vector<int> &theVect) {</int>
Shinya Kitaoka 120a6e
  assert(theMap.size() == theVect.size());
Shinya Kitaoka 120a6e
  std::map<int, *="" vistroke="">::const_iterator it = theMap.begin();</int,>
shun-iwasawa 76d093
  UINT i                                       = 0;
Shinya Kitaoka 120a6e
  for (; it != theMap.end(); ++it) {
Shinya Kitaoka 120a6e
    theVect[i++] = it->first;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoEraser final : public ToolUtils::TToolUndo {
Shinya Kitaoka 120a6e
  std::vector<tfilledregioninf> m_oldFillInformation, m_newFillInformation;</tfilledregioninf>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m_row;
Shinya Kitaoka 120a6e
  int m_column;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  std::map<int, *="" vistroke=""> m_originalStrokes;</int,>
Shinya Kitaoka 120a6e
  std::map<int, *="" vistroke=""> m_newStrokes;</int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UndoEraser(TXshSimpleLevel *level, const TFrameId &frameId)
Shinya Kitaoka 120a6e
      : ToolUtils::TToolUndo(level, frameId) {
Shinya Kitaoka 120a6e
    TVectorImageP image = level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (app) {
Shinya Kitaoka 120a6e
      m_row    = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
      m_column = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    ImageUtils::getFillingInformationInArea(image, m_oldFillInformation,
Shinya Kitaoka 120a6e
                                            image->getBBox());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onAdd() override {
Shinya Kitaoka 120a6e
    TVectorImageP image = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    assert(!!image);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
    ImageUtils::getFillingInformationInArea(image, m_newFillInformation,
Shinya Kitaoka 120a6e
                                            image->getBBox());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~UndoEraser() {
Shinya Kitaoka 120a6e
    std::map<int, *="" vistroke="">::const_iterator it;</int,>
Shinya Kitaoka 120a6e
    for (it = m_originalStrokes.begin(); it != m_originalStrokes.end(); ++it)
Shinya Kitaoka 120a6e
      deleteVIStroke(it->second);
Shinya Kitaoka 120a6e
    for (it = m_newStrokes.begin(); it != m_newStrokes.end(); ++it)
Shinya Kitaoka 120a6e
      deleteVIStroke(it->second);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addOldStroke(int index, VIStroke *stroke) {
Shinya Kitaoka 120a6e
    VIStroke *s = cloneVIStroke(stroke);
Shinya Kitaoka 120a6e
    m_originalStrokes.insert(std::map<int, *="" vistroke="">::value_type(index, s));</int,>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addNewStroke(int index, VIStroke *stroke) {
Shinya Kitaoka 120a6e
    VIStroke *s = cloneVIStroke(stroke);
Shinya Kitaoka 120a6e
    m_newStrokes.insert(std::map<int, *="" vistroke="">::value_type(index, s));</int,>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (!app) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFrameId currentFid;
Shinya Kitaoka 120a6e
    if (app->getCurrentFrame()->isEditingScene()) {
Shinya Kitaoka 120a6e
      app->getCurrentColumn()->setColumnIndex(m_column);
Shinya Kitaoka 120a6e
      app->getCurrentFrame()->setFrame(m_row);
Shinya Kitaoka 120a6e
      currentFid = TFrameId(m_row + 1);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      app->getCurrentFrame()->setFid(m_frameId);
Shinya Kitaoka 120a6e
      currentFid = m_frameId;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TVectorImageP image = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    assert(image);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
    QMutexLocker lock(image->getMutex());
Shinya Kitaoka 120a6e
    std::vector<int> newStrokeIndex(m_newStrokes.size());</int>
Shinya Kitaoka 120a6e
    mapToVector(m_newStrokes, newStrokeIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    image->removeStrokes(newStrokeIndex, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::map<int, *="" vistroke="">::const_iterator it = m_originalStrokes.begin();</int,>
shun-iwasawa 76d093
    UINT i                                       = 0;
Shinya Kitaoka 120a6e
    VIStroke *s;
Shinya Kitaoka 120a6e
    for (; it != m_originalStrokes.end(); ++it) {
Shinya Kitaoka 120a6e
      s = cloneVIStroke(it->second);
Shinya Kitaoka 120a6e
      image->insertStrokeAt(s, it->first);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (image->isComputedRegionAlmostOnce())
Shinya Kitaoka 120a6e
      image->findRegions();  // in futuro togliere. Serve perche' la
Shinya Kitaoka 120a6e
                             // removeStrokes, se gli si dice
Shinya Kitaoka 120a6e
    // di non calcolare le regioni, e' piu' veloce ma poi chrash tutto
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT size = m_oldFillInformation.size();
Shinya Kitaoka 120a6e
    if (!size) {
Shinya Kitaoka 120a6e
      app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
      notifyImageChanged();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRegion *reg;
Shinya Kitaoka 120a6e
    i = 0;
Shinya Kitaoka 120a6e
    for (; i < size; i++) {
Shinya Kitaoka 120a6e
      reg = image->getRegion(m_oldFillInformation[i].m_regionId);
Shinya Kitaoka 120a6e
      assert(reg);
Shinya Kitaoka 120a6e
      if (reg) reg->setStyle(m_oldFillInformation[i].m_styleId);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (!app) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TFrameId currentFid;
Shinya Kitaoka 120a6e
    if (app->getCurrentFrame()->isEditingScene()) {
Shinya Kitaoka 120a6e
      app->getCurrentColumn()->setColumnIndex(m_column);
Shinya Kitaoka 120a6e
      app->getCurrentFrame()->setFrame(m_row);
Shinya Kitaoka 120a6e
      currentFid = TFrameId(m_row + 1);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      app->getCurrentFrame()->setFid(m_frameId);
Shinya Kitaoka 120a6e
      currentFid = m_frameId;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    TVectorImageP image = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    assert(image);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QMutexLocker lock(image->getMutex());
Shinya Kitaoka 120a6e
    std::vector<int> oldStrokeIndex(m_originalStrokes.size());</int>
Shinya Kitaoka 120a6e
    mapToVector(m_originalStrokes, oldStrokeIndex);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    image->removeStrokes(oldStrokeIndex, true, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::map<int, *="" vistroke="">::const_iterator it = m_newStrokes.begin();</int,>
shun-iwasawa 76d093
    UINT i                                       = 0;
Shinya Kitaoka 120a6e
    VIStroke *s;
Shinya Kitaoka 120a6e
    for (; it != m_newStrokes.end(); ++it) {
Shinya Kitaoka 120a6e
      s = cloneVIStroke(it->second);
Shinya Kitaoka 120a6e
      image->insertStrokeAt(s, it->first);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (image->isComputedRegionAlmostOnce())
Shinya Kitaoka 120a6e
      image->findRegions();  // in futuro togliere. Serve perche' la
Shinya Kitaoka 120a6e
                             // removeStrokes, se gli si dice
Shinya Kitaoka 120a6e
    // di non calcolare le regioni, e' piu' veloce ma poi chrash tutto
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT size = m_newFillInformation.size();
Shinya Kitaoka 120a6e
    if (!size) {
Shinya Kitaoka 120a6e
      app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
      notifyImageChanged();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRegion *reg;
Shinya Kitaoka 120a6e
    i = 0;
Shinya Kitaoka 120a6e
    for (; i < size; i++) {
Shinya Kitaoka 120a6e
      reg = image->getRegion(m_newFillInformation[i].m_regionId);
Shinya Kitaoka 120a6e
      assert(reg);
Shinya Kitaoka 120a6e
      if (reg) reg->setStyle(m_newFillInformation[i].m_styleId);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) +
Shinya Kitaoka 120a6e
           (m_oldFillInformation.capacity() + m_newFillInformation.capacity()) *
Shinya Kitaoka 120a6e
               sizeof(TFilledRegionInf) +
Shinya Kitaoka 120a6e
           500;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getToolName() override { return QString("Vector Eraser Tool"); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getHistoryType() override { return HistoryType::EraserTool; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//  EraserTool class declaration
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class EraserTool final : public TTool {
Shinya Kitaoka 120a6e
  Q_DECLARE_TR_FUNCTIONS(EraserTool)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  EraserTool();
Shinya Kitaoka 120a6e
  ~EraserTool();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  ToolType getToolType() const override { return TTool::LevelWriteTool; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void draw() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void startErase(
Shinya Kitaoka 120a6e
      TVectorImageP vi,
Shinya Kitaoka 120a6e
      const TPointD &pos);  //, const TImageLocation &imageLocation);
Shinya Kitaoka 120a6e
  void erase(TVectorImageP vi, const TPointD &pos);
Shinya Kitaoka 120a6e
  void erase(TVectorImageP vi,
Shinya Kitaoka 120a6e
             TRectD &rect);  //, const TImageLocation &imageLocation);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void stopErase(TVectorImageP vi);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override;
Shinya Kitaoka 473e70
  void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override;
Shinya Kitaoka 473e70
  void leftButtonUp(const TPointD &pos, const TMouseEvent &) override;
Shinya Kitaoka 473e70
  void leftButtonDoubleClick(const TPointD &pos, const TMouseEvent &e) override;
Shinya Kitaoka 473e70
  void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
Shinya Kitaoka 473e70
  bool onPropertyChanged(std::string propertyName) override;
Shinya Kitaoka 473e70
  void onEnter() override;
Shinya Kitaoka 473e70
  void onLeave() override;
Shinya Kitaoka 473e70
  void onActivate() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  int getCursorId() const override { return ToolCursor::EraserCursor; }
Shinya Kitaoka 473e70
  void onImageChanged() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*-- ドラッグ中にツールが切り替わった場合、Eraseの終了処理を行う --*/
Shinya Kitaoka 473e70
  void onDeactivate() override;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
pojienie 7933ab
  typedef void (EraserTool::*EraseFunction)(const TVectorImageP vi,
pojienie 7933ab
                                            TStroke *stroke);
pojienie 7933ab
Shinya Kitaoka 120a6e
  TPropertyGroup m_prop;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TEnumProperty m_eraseType;
pojienie 4998cf
  TEnumProperty m_interpolation;
Shinya Kitaoka 120a6e
  TDoubleProperty m_toolSize;
Shinya Kitaoka 120a6e
  TBoolProperty m_selective;
Shinya Kitaoka 120a6e
  TBoolProperty m_invertOption;
Shinya Kitaoka 120a6e
  TBoolProperty m_multi;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double m_pointSize, m_distance2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD m_mousePos,  //!< Current mouse position.
Shinya Kitaoka 120a6e
      m_oldMousePos,   //!< Previous mouse position.
Shinya Kitaoka 120a6e
      m_brushPos,      //!< Position the brush will be painted at.
Shinya Kitaoka 120a6e
      m_firstPos;      //!< Either The first point inserted either in m_track or
Shinya Kitaoka 38fd86
                       //! m_polyline
Shinya Kitaoka 38fd86
  //!  (depending on selected erase mode).
Shinya Kitaoka 120a6e
  UndoEraser *m_undo;
Shinya Kitaoka 120a6e
  std::vector<int> m_indexes;</int>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD m_selectingRect, m_firstRect;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TFrameId m_firstFrameId, m_veryFirstFrameId;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TXshSimpleLevelP m_level;
Shinya Kitaoka 120a6e
  std::pair<int, int=""> m_currCell;</int,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  StrokeGenerator m_track;  //!< Lazo selection generator.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<tpointd> m_polyline;  //!< Polyline points.</tpointd>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStroke *m_stroke;  //!< Stores the stroke generated by m_track.
Shinya Kitaoka 120a6e
  TStroke
Shinya Kitaoka 120a6e
      *m_firstStroke;  //!< Stores the first stroke in the "frame range" case.
Jeremy Bullock 60023a
  TImageP m_activeImage = NULL;  // needed if an frame is changed mid-erase
Shinya Kitaoka 120a6e
  double m_thick;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_firstTime, m_active, m_firstFrameSelected;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  void resetMulti();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void updateTranslation() override;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Metodi per disegnare la linea della modalita' Freehand
Shinya Kitaoka 120a6e
  void startFreehand(const TPointD &pos);
Shinya Kitaoka 120a6e
  void freehandDrag(const TPointD &pos);
Shinya Kitaoka 120a6e
  void closeFreehand(const TPointD &pos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Metodi per disegnare la linea della modalita' Polyline
Shinya Kitaoka 120a6e
  void addPointPolyline(const TPointD &pos);
Shinya Kitaoka 120a6e
  void closePolyline(const TPointD &pos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void eraseRegion(const TVectorImageP vi, TStroke *stroke);
Toshihiro Shimizu 890ddd
pojienie 7933ab
  void eraseSegments(const TVectorImageP vi, TStroke *eraseStroke);
pojienie 31955e
Shinya Kitaoka 120a6e
  void multiEraseRect(TFrameId firstFrameId, TFrameId lastFrameId,
Shinya Kitaoka 120a6e
                      TRectD firstRect, TRectD lastRect, bool invert);
Shinya Kitaoka 120a6e
  void doMultiErase(TFrameId &firstFrameId, TFrameId &lastFrameId,
pojienie 7933ab
                    const TStroke *firstStroke, const TStroke *lastStroke,
pojienie 7933ab
                    EraseFunction eraseFunction);
Shinya Kitaoka 120a6e
  void doErase(double t, const TXshSimpleLevelP &sl, const TFrameId &fid,
pojienie 7933ab
               const TVectorImageP &firstImage, const TVectorImageP &lastImage,
pojienie 7933ab
               EraseFunction eraseFunction);
pojienie 7933ab
  void multiErase(TStroke *stroke, const TMouseEvent &e,
pojienie 7933ab
                  EraseFunction eraseFunction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} eraserTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//  EraserTool implemention
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
EraserTool::EraserTool()
Shinya Kitaoka 120a6e
    : TTool("T_Eraser")
pojienie 4998cf
    , m_eraseType("Type:")  // "W_ToolOptions_Erasetype"
pojienie 4998cf
    , m_interpolation("interpolation:")
shun-iwasawa 76d093
    , m_toolSize("Size:", 1, 1000, 10)  // "W_ToolOptions_EraserToolSize"
shun-iwasawa 76d093
    , m_selective("Selective", false)   // "W_ToolOptions_Selective"
shun-iwasawa 76d093
    , m_invertOption("Invert", false)   // "W_ToolOptions_Invert"
shun-iwasawa 76d093
    , m_multi("Frame Range", false)     // "W_ToolOptions_FrameRange"
Shinya Kitaoka 120a6e
    , m_pointSize(-1)
Shinya Kitaoka 120a6e
    , m_undo(0)
Shinya Kitaoka 120a6e
    , m_currCell(-1, -1)
Shinya Kitaoka 120a6e
    , m_stroke(0)
Shinya Kitaoka 120a6e
    , m_thick(5)
Shinya Kitaoka 120a6e
    , m_active(false)
Shinya Kitaoka 120a6e
    , m_firstTime(true) {
Shinya Kitaoka 120a6e
  bind(TTool::VectorImage);
Shinya Kitaoka 120a6e
shun-iwasawa 76d093
  m_toolSize.setNonLinearSlider();
shun-iwasawa 76d093
Shinya Kitaoka 120a6e
  m_prop.bind(m_toolSize);
Shinya Kitaoka 120a6e
  m_prop.bind(m_eraseType);
Shinya Kitaoka 120a6e
  m_eraseType.addValue(NORMAL_ERASE);
Shinya Kitaoka 120a6e
  m_eraseType.addValue(RECT_ERASE);
Shinya Kitaoka 120a6e
  m_eraseType.addValue(FREEHAND_ERASE);
Shinya Kitaoka 120a6e
  m_eraseType.addValue(POLYLINE_ERASE);
pojienie 31955e
  m_eraseType.addValue(SEGMENT_ERASE);
Shinya Kitaoka 120a6e
  m_prop.bind(m_selective);
Shinya Kitaoka 120a6e
  m_prop.bind(m_invertOption);
Shinya Kitaoka 120a6e
  m_prop.bind(m_multi);
pojienie 4998cf
  m_prop.bind(m_interpolation);
pojienie 4998cf
  m_interpolation.addValue(LINEAR_INTERPOLATION);
pojienie 4998cf
  m_interpolation.addValue(EASE_IN_INTERPOLATION);
pojienie 4998cf
  m_interpolation.addValue(EASE_OUT_INTERPOLATION);
pojienie 4998cf
  m_interpolation.addValue(EASE_IN_OUT_INTERPOLATION);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_selective.setId("Selective");
Shinya Kitaoka 120a6e
  m_invertOption.setId("Invert");
Shinya Kitaoka 120a6e
  m_multi.setId("FrameRange");
Shinya Kitaoka 120a6e
  m_eraseType.setId("Type");
pojienie 4998cf
  m_interpolation.setId("Interpolation");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
EraserTool::~EraserTool() {
Shinya Kitaoka 120a6e
  if (m_stroke) delete m_stroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_firstStroke) delete m_firstStroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::updateTranslation() {
Shinya Kitaoka 120a6e
  m_toolSize.setQStringName(tr("Size:"));
Shinya Kitaoka 120a6e
  m_selective.setQStringName(tr("Selective"));
Shinya Kitaoka 120a6e
  m_invertOption.setQStringName(tr("Invert"));
Shinya Kitaoka 120a6e
  m_multi.setQStringName(tr("Frame Range"));
Shinya Kitaoka 120a6e
  m_eraseType.setQStringName(tr("Type:"));
shun-iwasawa df7bb0
  m_eraseType.setItemUIName(NORMAL_ERASE, tr("Normal"));
shun-iwasawa df7bb0
  m_eraseType.setItemUIName(RECT_ERASE, tr("Rectangular"));
shun-iwasawa df7bb0
  m_eraseType.setItemUIName(FREEHAND_ERASE, tr("Freehand"));
shun-iwasawa df7bb0
  m_eraseType.setItemUIName(POLYLINE_ERASE, tr("Polyline"));
pojienie 31955e
  m_eraseType.setItemUIName(SEGMENT_ERASE, tr("Segment"));
pojienie 4998cf
pojienie 4998cf
  m_interpolation.setQStringName(tr(""));
pojienie 4998cf
  m_interpolation.setItemUIName(LINEAR_INTERPOLATION, tr("Linear"));
pojienie 4998cf
  m_interpolation.setItemUIName(EASE_IN_INTERPOLATION, tr("Ease In"));
pojienie 4998cf
  m_interpolation.setItemUIName(EASE_OUT_INTERPOLATION, tr("Ease Out"));
pojienie 4998cf
  m_interpolation.setItemUIName(EASE_IN_OUT_INTERPOLATION, tr("Ease In/Out"));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::draw() {
Shinya Kitaoka 120a6e
  if (m_pointSize <= 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double pixelSize2 = getPixelSize() * getPixelSize();
Shinya Kitaoka 120a6e
  m_thick           = pixelSize2 / 2.0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageP image(getImage(false));
Shinya Kitaoka 120a6e
  TVectorImageP vi = image;
Shinya Kitaoka 120a6e
  if (vi) {
Shinya Kitaoka 120a6e
    bool blackBg = ToonzCheck::instance()->getChecks() & ToonzCheck::eBlackBg;
Shinya Kitaoka 120a6e
    if (m_eraseType.getValue() == RECT_ERASE) {
shun-iwasawa 93b2f8
      TPixel color = blackBg ? TPixel32::White : TPixel32::Red;
Shinya Kitaoka 120a6e
      if (m_multi.getValue() && m_firstFrameSelected)
Shinya Kitaoka 120a6e
        drawRect(m_firstRect, color, 0x3F33, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (m_active || (m_multi.getValue() && !m_firstFrameSelected))
shun-iwasawa 93b2f8
        drawRect(m_selectingRect, color, 0xFFFF, true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_eraseType.getValue() == NORMAL_ERASE) {
manongjohn 75da26
      // If toggled off, don't draw brush outline
manongjohn 75da26
      if (!Preferences::instance()->isCursorOutlineEnabled()) return;
manongjohn 75da26
Shinya Kitaoka 120a6e
      tglColor(TPixel32(255, 0, 255));
Shinya Kitaoka 120a6e
      tglDrawCircle(m_brushPos, m_pointSize);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if ((m_eraseType.getValue() == FREEHAND_ERASE ||
pojienie 31955e
         m_eraseType.getValue() == POLYLINE_ERASE ||
pojienie 31955e
         m_eraseType.getValue() == SEGMENT_ERASE) &&
shun-iwasawa 93b2f8
        m_multi.getValue() && m_firstStroke) {
shun-iwasawa 93b2f8
      TPixel color = blackBg ? TPixel32::White : TPixel32::Red;
Shinya Kitaoka 120a6e
      tglColor(color);
shun-iwasawa 93b2f8
      glPushAttrib(GL_ALL_ATTRIB_BITS);
shun-iwasawa 93b2f8
      glEnable(GL_BLEND);
shun-iwasawa 93b2f8
      glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
shun-iwasawa 93b2f8
      if (m_firstFrameSelected) {
shun-iwasawa 93b2f8
        glLineStipple(1, 0x3F33);
shun-iwasawa 93b2f8
        glEnable(GL_LINE_STIPPLE);
shun-iwasawa 93b2f8
      }
shun-iwasawa 93b2f8
      drawStrokeCenterline(*m_firstStroke, 1);
shun-iwasawa 93b2f8
      glPopAttrib();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_eraseType.getValue() == POLYLINE_ERASE && !m_polyline.empty()) {
Shinya Kitaoka 120a6e
      TPixel color = blackBg ? TPixel32::White : TPixel32::Black;
Shinya Kitaoka 120a6e
      tglColor(color);
Shinya Kitaoka 120a6e
      tglDrawCircle(m_polyline[0], 2);
Shinya Kitaoka 120a6e
      glBegin(GL_LINE_STRIP);
Shinya Kitaoka 120a6e
      for (UINT i = 0; i < m_polyline.size(); i++) tglVertex(m_polyline[i]);
Shinya Kitaoka 120a6e
      tglVertex(m_mousePos);
Shinya Kitaoka 120a6e
      glEnd();
pojienie 31955e
    } else if ((m_eraseType.getValue() == FREEHAND_ERASE ||
pojienie 31955e
                m_eraseType.getValue() == SEGMENT_ERASE) &&
pojienie 31955e
               !m_track.isEmpty()) {
shun-iwasawa c189d1
      TPixel color = blackBg ? TPixel32::White : TPixel32::Black;
shun-iwasawa c189d1
      tglColor(color);
shun-iwasawa c189d1
      glPushMatrix();
shun-iwasawa c189d1
      m_track.drawAllFragments();
shun-iwasawa c189d1
      glPopMatrix();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::resetMulti() {
Shinya Kitaoka 120a6e
  m_firstFrameSelected = false;
Shinya Kitaoka 120a6e
  m_firstRect.empty();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_selectingRect.empty();
Shinya Kitaoka 120a6e
  TTool::Application *application = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (!application) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_firstFrameId = m_veryFirstFrameId = getCurrentFid();
Shinya Kitaoka 120a6e
  m_level = application->getCurrentLevel()->getLevel()
Shinya Kitaoka 120a6e
                ? application->getCurrentLevel()->getLevel()->getSimpleLevel()
Shinya Kitaoka 120a6e
                : 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstStroke) {
Shinya Kitaoka 120a6e
    delete m_firstStroke;
Shinya Kitaoka 120a6e
    m_firstStroke = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::startErase(
Shinya Kitaoka 120a6e
    TVectorImageP vi,
Shinya Kitaoka 120a6e
    const TPointD &pos)  //, const TImageLocation &imageLocation)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  UINT size = vi->getStrokeCount();
Shinya Kitaoka 120a6e
  m_indexes.resize(size);
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < size; i++) m_indexes[i] = i;
Shinya Kitaoka 120a6e
shun-iwasawa 074b3e
  if (m_undo) delete m_undo;
Shinya Kitaoka 120a6e
  TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
  m_undo        = new UndoEraser(level, getCurrentFid());
Shinya Kitaoka 120a6e
  m_oldMousePos = pos;
Shinya Kitaoka 120a6e
  m_distance2   = minDistance2 * getPixelSize() * getPixelSize();
Shinya Kitaoka 120a6e
  erase(vi, pos);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::erase(TVectorImageP vi, const TPointD &pos) {
Shinya Kitaoka 120a6e
  std::vector<int>::iterator it = m_indexes.begin();</int>
Shinya Kitaoka 120a6e
  m_distance2 += tdistance2(m_oldMousePos, pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_distance2 < minDistance2 * getPixelSize() * getPixelSize()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_distance2   = 0;
Shinya Kitaoka 120a6e
  m_oldMousePos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // quadrato circoscritto alla circonferenza
Shinya Kitaoka 120a6e
  TRectD circumscribedSquare(pos.x - m_pointSize, pos.y - m_pointSize,
Shinya Kitaoka 120a6e
                             pos.x + m_pointSize, pos.y + m_pointSize);
Shinya Kitaoka 120a6e
  if (!circumscribedSquare.overlaps(vi->getBBox())) {
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> intersections;</double>
Shinya Kitaoka 120a6e
  std::vector<doublepair> sortedWRanges;</doublepair>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tstroke *=""> splitStrokes;</tstroke>
Shinya Kitaoka 120a6e
  double rectEdge_2 = m_pointSize * M_SQRT1_2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // quadrato iscritto nella circonferenza
Shinya Kitaoka 120a6e
  TRectD enrolledSquare(pos.x - rectEdge_2, pos.y - rectEdge_2,
Shinya Kitaoka 120a6e
                        pos.x + rectEdge_2, pos.y + rectEdge_2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT i            = 0;
Shinya Kitaoka 120a6e
  double pointSize2 = sq(m_pointSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<int> oneStrokeIndex(1);</int>
Shinya Kitaoka 120a6e
  int index = TTool::getApplication()->getCurrentLevelStyleIndex();
Shinya Kitaoka 120a6e
  QMutexLocker lock(vi->getMutex());
Shinya Kitaoka 120a6e
  while (i < vi->getStrokeCount()) {
Shinya Kitaoka 120a6e
    assert(it != m_indexes.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *oldStroke = vi->getStroke(i);
Shinya Kitaoka 120a6e
    if (!vi->inCurrentGroup(i) ||
Shinya Kitaoka 120a6e
        (m_selective.getValue() && oldStroke->getStyle() != index)) {
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      it++;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRectD strokeBBox = oldStroke->getBBox();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!circumscribedSquare.overlaps(strokeBBox)) {  // stroke all'esterno del
Shinya Kitaoka 120a6e
                                                      // quadrato circoscritto
Shinya Kitaoka 120a6e
                                                      // alla circonferenxa
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      it++;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (enrolledSquare.contains(strokeBBox)) {  // stroke tutta contenuta nel
Shinya Kitaoka 120a6e
                                                // quadrato iscritto nella
Shinya Kitaoka 120a6e
                                                // circonferenza
Shinya Kitaoka 120a6e
      if (*it != -1) m_undo->addOldStroke(*it, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
      oneStrokeIndex[0] = i;
Shinya Kitaoka 120a6e
      vi->removeStrokes(oneStrokeIndex, true, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      it = m_indexes.erase(it);
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    splitStrokes.clear();
Shinya Kitaoka 120a6e
    intersections.clear();
Shinya Kitaoka 120a6e
    /*int intersNum=*/intersect(*oldStroke, pos, m_pointSize, intersections);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /*
Shinya Kitaoka 120a6e
#ifdef _DEBUG
Shinya Kitaoka 120a6e
if(intersections.size()==2 && intersections[0]==intersections[1])
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
intersections.clear();
Shinya Kitaoka 120a6e
intersect( *oldStroke, pos, m_pointSize, intersections );
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
#endif
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (intersections.empty()) {
Shinya Kitaoka 120a6e
      // BASTEREBBE CONTROLLARE UN SOLO PUNTO PERCHE' SE LA
Shinya Kitaoka 120a6e
      // STROKE NON INTERSECA IL CERCHIO E CONTENTIENE ALMENO
Shinya Kitaoka 120a6e
      // UN PUNTO, LA CONTIENE TUTTA. MA SICCOME NON MI FIDO
Shinya Kitaoka 120a6e
      // DELLA INTERSECT, NE CONTROLLO UN PAIO E AVVANTAGGIO (CON L' AND)
Shinya Kitaoka 120a6e
      // IL NON CONTENIMENTO, DATO CHE E' MEGLIO CANCELLARE UNA COSA IN
Shinya Kitaoka 120a6e
      // MENO, CHE UNA IN PIU'
Shinya Kitaoka 120a6e
      if (tdistance2(oldStroke->getPoint(0), pos) < pointSize2 &&
Shinya Kitaoka 120a6e
          tdistance2(oldStroke->getPoint(1), pos) <
Shinya Kitaoka 120a6e
              pointSize2) {  // stroke tutta contenuta nella circonferenxa
Shinya Kitaoka 120a6e
        if (*it != -1) m_undo->addOldStroke(*it, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
        oneStrokeIndex[0] = i;
Shinya Kitaoka 120a6e
        vi->removeStrokes(oneStrokeIndex, true, true);
Shinya Kitaoka 120a6e
        it = m_indexes.erase(it);
Shinya Kitaoka 120a6e
      } else {  // non colpita
Shinya Kitaoka 120a6e
        i++;
Shinya Kitaoka 120a6e
        it++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //------------------------ almeno un'intersezione
Shinya Kitaoka 120a6e
    //---------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (intersections.size() == 1) {
Shinya Kitaoka 120a6e
      if (oldStroke->isSelfLoop()) {  // una sola intersezione di una stroke
Shinya Kitaoka 120a6e
                                      // chiusa con un cerchio dovrebbe accadere
Shinya Kitaoka 120a6e
        // solo in caso di sfioramento, quindi faccio finta di nulla
Shinya Kitaoka 120a6e
        i++;
Shinya Kitaoka 120a6e
        it++;
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (*it != -1) m_undo->addOldStroke(*it, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      double w0            = intersections[0];
Shinya Kitaoka 120a6e
      TThickPoint hitPoint = oldStroke->getThickPoint(w0);
Shinya Kitaoka 120a6e
      int chunck;
Shinya Kitaoka 120a6e
      double t;
Shinya Kitaoka 120a6e
      oldStroke->getChunkAndT(w0, chunck, t);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      int chunckIndex;
Shinya Kitaoka 120a6e
      double w1;
Shinya Kitaoka 120a6e
      if (tdistance2(oldStroke->getPoint(0), pos) < pointSize2) {
Shinya Kitaoka 120a6e
        chunckIndex = oldStroke->getChunkCount() - 1;
Shinya Kitaoka 120a6e
        w1          = 1;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        chunckIndex = 0;
Shinya Kitaoka 120a6e
        w1          = 0;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      UINT cI;
Shinya Kitaoka 120a6e
      std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
      if (w1 == 0) {
Shinya Kitaoka 120a6e
        for (cI = chunckIndex; cI < (UINT)chunck; cI++) {
Shinya Kitaoka 120a6e
          points.push_back(oldStroke->getChunk(cI)->getThickP0());
Shinya Kitaoka 120a6e
          points.push_back(oldStroke->getChunk(cI)->getThickP1());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        TThickQuadratic t1, t2;
Shinya Kitaoka 120a6e
        oldStroke->getChunk(chunck)->split(t, t1, t2);
Shinya Kitaoka 120a6e
        points.push_back(t1.getThickP0());
Shinya Kitaoka 120a6e
        points.push_back(t1.getThickP1());
Shinya Kitaoka 120a6e
        points.push_back(hitPoint);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        TThickQuadratic t1, t2;
Shinya Kitaoka 120a6e
        oldStroke->getChunk(chunck)->split(t, t1, t2);
Shinya Kitaoka 120a6e
        points.push_back(hitPoint);
Shinya Kitaoka 120a6e
        points.push_back(t2.getThickP1());
Shinya Kitaoka 120a6e
        points.push_back(t2.getThickP2());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (cI = chunck + 1; cI <= (UINT)chunckIndex; cI++) {
Shinya Kitaoka 120a6e
          points.push_back(oldStroke->getChunk(cI)->getThickP1());
Shinya Kitaoka 120a6e
          points.push_back(oldStroke->getChunk(cI)->getThickP2());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      oldStroke->reshape(&(points[0]), points.size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      vi->notifyChangedStrokes(i);  // per adesso cosi', pero' e' lento
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      *it = -1;
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      it++;
Shinya Kitaoka 120a6e
      continue;
Toshihiro Shimizu 890ddd
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //---------- piu'
Shinya Kitaoka 38fd86
    // intersezioni--------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (intersections.size() & 1 &&
Shinya Kitaoka 120a6e
        oldStroke->isSelfLoop()) {  // non dovrebbe mai accadere
Shinya Kitaoka 120a6e
      assert(0);
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      it++;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (intersections.size() == 2 &&
Shinya Kitaoka 120a6e
        intersections[0] == intersections[1]) {  // solo sfiorata
Shinya Kitaoka 120a6e
      i++;
Shinya Kitaoka 120a6e
      it++;
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UINT oldStrokeSize = vi->getStrokeCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (*it != -1) m_undo->addOldStroke(*it, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    sortedWRanges.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (tdistance2(vi->getStroke(i)->getPoint(0), pos) > pointSize2) {
Shinya Kitaoka 120a6e
      if (intersections[0] == 0.0)
Shinya Kitaoka 120a6e
        intersections.erase(intersections.begin());
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        intersections.insert(intersections.begin(), 0.0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (intersections[0] != 1.0) intersections.push_back(1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    sortedWRanges.reserve(intersections.size() / 2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (UINT j = 0; j < intersections.size() - 1; j += 2)
Shinya Kitaoka 120a6e
      sortedWRanges.push_back(
Shinya Kitaoka 120a6e
          std::make_pair(intersections[j], intersections[j + 1]));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (UINT kkk = 0; kkk < sortedWRanges.size() - 1; kkk++) {
Shinya Kitaoka 120a6e
      assert(sortedWRanges[kkk].first < sortedWRanges[kkk].second);
Shinya Kitaoka 120a6e
      assert(sortedWRanges[kkk].second <= sortedWRanges[kkk + 1].first);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    assert(sortedWRanges.back().first < sortedWRanges.back().second);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    vi->splitStroke(i, sortedWRanges);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    UINT addedStroke = vi->getStrokeCount() -
Shinya Kitaoka 120a6e
                       (oldStrokeSize - 1);  //-1 perche' e' quella tolta
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    i += addedStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    *it = -1;
Shinya Kitaoka 120a6e
    m_indexes.insert(it, addedStroke - 1, -1);
Shinya Kitaoka 120a6e
    it = m_indexes.begin() + i;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::erase(TVectorImageP vi, TRectD &rect) {
otakuto ed7dcd
  if (rect.x0 > rect.x1) std::swap(rect.x1, rect.x0);
otakuto ed7dcd
  if (rect.y0 > rect.y1) std::swap(rect.y1, rect.y0);
Shinya Kitaoka 120a6e
  int i     = 0;
Shinya Kitaoka 120a6e
  int index = TTool::getApplication()->getCurrentLevelStyleIndex();
Shinya Kitaoka 120a6e
  std::vector<int> eraseStrokes;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
  m_undo = new UndoEraser(level, getCurrentFid());
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)vi->getStrokeCount(); i++) {
Shinya Kitaoka 120a6e
    if (!vi->inCurrentGroup(i)) continue;
Shinya Kitaoka 120a6e
    TStroke *stroke = vi->getStroke(i);
Shinya Kitaoka 120a6e
    if (!m_invertOption.getValue()) {
Shinya Kitaoka 120a6e
      if ((!m_selective.getValue() || stroke->getStyle() == index) &&
Shinya Kitaoka 120a6e
          rect.contains(stroke->getBBox())) {
Shinya Kitaoka 120a6e
        m_undo->addOldStroke(i, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
        eraseStrokes.push_back(i);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if ((!m_selective.getValue() || stroke->getStyle() == index) &&
Shinya Kitaoka 120a6e
          !rect.contains(stroke->getBBox())) {
Shinya Kitaoka 120a6e
        m_undo->addOldStroke(i, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
        eraseStrokes.push_back(i);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  for (i = (int)eraseStrokes.size() - 1; i >= 0; i--)
Shinya Kitaoka 120a6e
    vi->deleteStroke(eraseStrokes[i]);
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
  m_undo = 0;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::stopErase(TVectorImageP vi) {
Shinya Kitaoka 120a6e
  assert(m_undo != 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT size = m_indexes.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(size == vi->getStrokeCount());
Shinya Kitaoka 120a6e
  UINT i = 0;
Shinya Kitaoka 120a6e
  for (; i < size; i++) {
Shinya Kitaoka 120a6e
    if (m_indexes[i] == -1) m_undo->addNewStroke(i, vi->getVIStroke(i));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(m_undo);
Jeremy Bullock 60023a
  m_undo   = 0;
Jeremy Bullock 60023a
  m_active = false;
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  notifyImageChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_brushPos = m_mousePos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_active = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageP image(getImage(true));
Jeremy Bullock 60023a
  m_activeImage = image;
Shinya Kitaoka 120a6e
  if (m_eraseType.getValue() == NORMAL_ERASE) {
Shinya Kitaoka 120a6e
    if (TVectorImageP vi = image) startErase(vi, pos /*,imageLocation*/);
Shinya Kitaoka 120a6e
  } else if (m_eraseType.getValue() == RECT_ERASE) {
Shinya Kitaoka 120a6e
    m_selectingRect.x0 = pos.x;
Shinya Kitaoka 120a6e
    m_selectingRect.y0 = pos.y;
Shinya Kitaoka 120a6e
    m_selectingRect.x1 = pos.x + 1;
Shinya Kitaoka 120a6e
    m_selectingRect.y1 = pos.y + 1;
Shinya Kitaoka 120a6e
    invalidate();
pojienie 31955e
  } else if (m_eraseType.getValue() == FREEHAND_ERASE ||
pojienie 31955e
             m_eraseType.getValue() == SEGMENT_ERASE) {
Shinya Kitaoka 120a6e
    startFreehand(pos);
Shinya Kitaoka 120a6e
  } else if (m_eraseType.getValue() == POLYLINE_ERASE) {
Shinya Kitaoka 120a6e
    addPointPolyline(pos);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_brushPos = m_mousePos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_active) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TImageP image(getImage(true));
Shinya Kitaoka 120a6e
  if (m_eraseType.getValue() == RECT_ERASE) {
Shinya Kitaoka 120a6e
    m_selectingRect.x1 = pos.x;
Shinya Kitaoka 120a6e
    m_selectingRect.y1 = pos.y;
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  } else if (m_eraseType.getValue() == NORMAL_ERASE) {
manongjohn 7b9543
    if (!m_undo) leftButtonDown(pos, e);
Shinya Kitaoka 120a6e
    if (TVectorImageP vi = image) erase(vi, pos);
pojienie 31955e
  } else if (m_eraseType.getValue() == FREEHAND_ERASE ||
pojienie 31955e
             m_eraseType.getValue() == SEGMENT_ERASE) {
Shinya Kitaoka 120a6e
    freehandDrag(pos);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void EraserTool::multiEraseRect(TFrameId firstFrameId, TFrameId lastFrameId,
Shinya Kitaoka 120a6e
                                TRectD firstRect, TRectD lastRect,
Shinya Kitaoka 120a6e
                                bool invert) {
Shinya Kitaoka 120a6e
  int r0 = firstFrameId.getNumber();
Shinya Kitaoka 120a6e
  int r1 = lastFrameId.getNumber();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (r0 > r1) {
otakuto ed7dcd
    std::swap(r0, r1);
otakuto ed7dcd
    std::swap(firstFrameId, lastFrameId);
otakuto ed7dcd
    std::swap(firstRect, lastRect);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if ((r1 - r0) < 1) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tframeid> allFids;</tframeid>
Shinya Kitaoka 120a6e
  m_level->getFids(allFids);
Shinya Kitaoka 120a6e
  std::vector<tframeid>::iterator i0 = allFids.begin();</tframeid>
Shinya Kitaoka 120a6e
  while (i0 != allFids.end() && *i0 < firstFrameId) i0++;
Shinya Kitaoka 120a6e
  if (i0 == allFids.end()) return;
Shinya Kitaoka 120a6e
  std::vector<tframeid>::iterator i1 = i0;</tframeid>
Shinya Kitaoka 120a6e
  while (i1 != allFids.end() && *i1 <= lastFrameId) i1++;
Shinya Kitaoka 120a6e
  assert(i0 < i1);
Shinya Kitaoka 120a6e
  std::vector<tframeid> fids(i0, i1);</tframeid>
Shinya Kitaoka 120a6e
  int m = fids.size();
Shinya Kitaoka 120a6e
  assert(m > 0);
Shinya Kitaoka 120a6e
pojienie 4998cf
  enum TInbetween::TweenAlgorithm algorithm = TInbetween::LinearInterpolation;
pojienie 4998cf
  if (m_interpolation.getValue() == EASE_IN_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseInInterpolation;
pojienie 4998cf
  } else if (m_interpolation.getValue() == EASE_OUT_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseOutInterpolation;
pojienie 4998cf
  } else if (m_interpolation.getValue() == EASE_IN_OUT_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseInOutInterpolation;
pojienie 4998cf
  }
pojienie 4998cf
Shinya Kitaoka 120a6e
  TUndoManager::manager()->beginBlock();
Shinya Kitaoka 120a6e
  for (int i = 0; i < m; ++i) {
Shinya Kitaoka 120a6e
    TFrameId fid = fids[i];
Shinya Kitaoka 120a6e
    assert(firstFrameId <= fid && fid <= lastFrameId);
Shinya Kitaoka 120a6e
    TVectorImageP img = (TVectorImageP)m_level->getFrame(fid, true);
Shinya Kitaoka 120a6e
    assert(img);
Shinya Kitaoka 120a6e
    double t    = m > 1 ? (double)i / (double)(m - 1) : 0.5;
pojienie 4998cf
    t           = TInbetween::interpolation(t, algorithm);
Shinya Kitaoka 120a6e
    TRectD rect = interpolateRect(firstRect, lastRect, t);
Shinya Kitaoka 120a6e
    // m_level->setFrame(fid, img); //necessario: se la getFrame ha scompattato
Shinya Kitaoka 120a6e
    // una img compressa, senza setFrame le modifiche sulla img fatte qui
Shinya Kitaoka 120a6e
    // andrebbero perse.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Setto fid come corrente per notificare il cambiamento dell'immagine
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    if (app) {
Shinya Kitaoka 120a6e
      if (app->getCurrentFrame()->isEditingScene())
Shinya Kitaoka 120a6e
        app->getCurrentFrame()->setFrame(fid.getNumber() - 1);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        app->getCurrentFrame()->setFid(fid);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    erase(img, rect);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TUndoManager::manager()->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::onImageChanged() {
Jeremy Bullock 60023a
  if (m_active) {
Jeremy Bullock 60023a
    stopErase(m_activeImage);
Jeremy Bullock 60023a
  }
Shinya Kitaoka 120a6e
  if (!m_multi.getValue()) return;
Shinya Kitaoka 120a6e
  TTool::Application *application = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (!application) return;
Shinya Kitaoka 120a6e
  TXshSimpleLevel *xshl = 0;
Shinya Kitaoka 120a6e
  if (application->getCurrentLevel()->getLevel())
Shinya Kitaoka 120a6e
    xshl = application->getCurrentLevel()->getLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!xshl || m_level.getPointer() != xshl ||
Shinya Kitaoka 120a6e
      (m_eraseType.getValue() == RECT_ERASE && m_selectingRect.isEmpty()) ||
Shinya Kitaoka 120a6e
      ((m_eraseType.getValue() == FREEHAND_ERASE ||
pojienie 31955e
        m_eraseType.getValue() == POLYLINE_ERASE ||
pojienie 31955e
        m_eraseType.getValue() == SEGMENT_ERASE) &&
Shinya Kitaoka 120a6e
       !m_firstStroke))
Shinya Kitaoka 120a6e
    resetMulti();
Shinya Kitaoka 120a6e
  else if (m_firstFrameId == getCurrentFid())
Shinya Kitaoka 120a6e
    m_firstFrameSelected = false;  // nel caso sono passato allo stato 1 e torno
Shinya Kitaoka 120a6e
                                   // all'immagine iniziale, torno allo stato
Shinya Kitaoka 120a6e
                                   // iniziale
Shinya Kitaoka 38fd86
  else {                           // cambio stato.
Shinya Kitaoka 120a6e
    m_firstFrameSelected = true;
Shinya Kitaoka 120a6e
    if (m_eraseType.getValue() == RECT_ERASE) {
Shinya Kitaoka 120a6e
      assert(!m_selectingRect.isEmpty());
Shinya Kitaoka 120a6e
      m_firstRect = m_selectingRect;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (!m_active) return;
shun-iwasawa 93b2f8
  m_active = false;
Shinya Kitaoka 120a6e
  TImageP image(getImage(true));
Shinya Kitaoka 120a6e
  TVectorImageP vi = image;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TTool::Application *application = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (!vi || !application) return;
manongjohn 7b9543
  if (m_eraseType.getValue() == NORMAL_ERASE) {
manongjohn 7b9543
    if (!m_undo) leftButtonDown(pos, e);
Shinya Kitaoka 120a6e
    stopErase(vi);
manongjohn 7b9543
  } else if (m_eraseType.getValue() == RECT_ERASE) {
Shinya Kitaoka 120a6e
    if (m_selectingRect.x0 > m_selectingRect.x1)
otakuto ed7dcd
      std::swap(m_selectingRect.x1, m_selectingRect.x0);
Shinya Kitaoka 120a6e
    if (m_selectingRect.y0 > m_selectingRect.y1)
otakuto ed7dcd
      std::swap(m_selectingRect.y1, m_selectingRect.y0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_multi.getValue()) {
Shinya Kitaoka 120a6e
      if (m_firstFrameSelected) {
Shinya Kitaoka 120a6e
        multiEraseRect(m_firstFrameId, getCurrentFid(), m_firstRect,
Shinya Kitaoka 120a6e
                       m_selectingRect, m_invertOption.getValue());
Shinya Kitaoka 120a6e
        if (e.isShiftPressed()) {
Shinya Kitaoka 120a6e
          m_firstRect    = m_selectingRect;
Shinya Kitaoka 120a6e
          m_firstFrameId = getCurrentFid();
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          if (application->getCurrentFrame()->isEditingScene()) {
Shinya Kitaoka 120a6e
            application->getCurrentColumn()->setColumnIndex(m_currCell.first);
Shinya Kitaoka 120a6e
            application->getCurrentFrame()->setFrame(m_currCell.second);
Shinya Kitaoka 120a6e
          } else
Shinya Kitaoka 120a6e
            application->getCurrentFrame()->setFid(m_veryFirstFrameId);
Shinya Kitaoka 120a6e
          resetMulti();
Shinya Kitaoka 120a6e
        }
shun-iwasawa 93b2f8
        invalidate();  // invalidate(m_selectingRect.enlarge(2));
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (application->getCurrentFrame()->isEditingScene())
Shinya Kitaoka 120a6e
          m_currCell = std::pair<int, int="">(</int,>
Shinya Kitaoka 120a6e
              application->getCurrentColumn()->getColumnIndex(),
Shinya Kitaoka 120a6e
              application->getCurrentFrame()->getFrame());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      erase(vi, m_selectingRect);
Shinya Kitaoka 120a6e
      notifyImageChanged();
Shinya Kitaoka 120a6e
      m_selectingRect.empty();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (m_eraseType.getValue() == FREEHAND_ERASE) {
Shinya Kitaoka 120a6e
    closeFreehand(pos);
Shinya Kitaoka 120a6e
    if (m_multi.getValue()) {
pojienie 7933ab
      multiErase(m_stroke, e, &EraserTool::eraseRegion);
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      eraseRegion(vi, m_stroke);
Shinya Kitaoka 120a6e
      invalidate();
Shinya Kitaoka 120a6e
      notifyImageChanged();
Shinya Kitaoka 120a6e
    }
shun-iwasawa c189d1
    m_track.clear();
pojienie 31955e
  } else if (m_eraseType.getValue() == SEGMENT_ERASE) {
pojienie 31955e
    double error = (30.0 / 11) * sqrt(getPixelSize() * getPixelSize());
pojienie 31955e
    m_stroke     = m_track.makeStroke(error);
pojienie 31955e
    m_stroke->setStyle(1);
pojienie 7933ab
    if (m_multi.getValue()) {
pojienie 7933ab
      multiErase(m_stroke, e, &EraserTool::eraseSegments);
pojienie 7933ab
      invalidate();
pojienie 7933ab
    } else {
pojienie 7933ab
      eraseSegments(vi, m_stroke);
pojienie 31955e
      invalidate();
pojienie 31955e
      notifyImageChanged();
pojienie 31955e
    }
pojienie 31955e
    m_track.clear();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene chiusa la polyline e si da il via alla cancellazione.
Shinya Kitaoka 120a6e
/*!Viene creato lo \b stroke rappresentante la polyline disegnata.
Shinya Kitaoka 120a6e
  Se e' selzionato il metodo di cancellazione "frame range" viene richiamato il
Shinya Kitaoka 120a6e
  metodo \b multiEreserRegion, altrimenti
Toshihiro Shimizu 890ddd
  viene richiamato il metodo \b eraseRegion*/
Shinya Kitaoka 120a6e
void EraserTool::leftButtonDoubleClick(const TPointD &pos,
Shinya Kitaoka 120a6e
                                       const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  TVectorImageP vi = getImage(true);
Shinya Kitaoka 120a6e
  if (m_eraseType.getValue() == POLYLINE_ERASE) {
Shinya Kitaoka 120a6e
    closePolyline(pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    std::vector<tthickpoint> strokePoints;</tthickpoint>
Shinya Kitaoka 120a6e
    for (UINT i = 0; i < m_polyline.size() - 1; i++) {
Shinya Kitaoka 120a6e
      strokePoints.push_back(TThickPoint(m_polyline[i], 1));
Shinya Kitaoka 120a6e
      strokePoints.push_back(
Shinya Kitaoka 120a6e
          TThickPoint(0.5 * (m_polyline[i] + m_polyline[i + 1]), 1));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    strokePoints.push_back(TThickPoint(m_polyline.back(), 1));
Shinya Kitaoka 120a6e
    m_polyline.clear();
Shinya Kitaoka 120a6e
    TStroke *stroke = new TStroke(strokePoints);
Shinya Kitaoka 120a6e
    assert(stroke->getPoint(0) == stroke->getPoint(1));
Shinya Kitaoka 120a6e
    if (m_multi.getValue())
pojienie 7933ab
      multiErase(stroke, e, &EraserTool::eraseRegion);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      eraseRegion(vi, stroke);
shun-iwasawa 93b2f8
      m_active = false;
Shinya Kitaoka 120a6e
      notifyImageChanged();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  struct Locals {
Shinya Kitaoka 120a6e
    EraserTool *m_this;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    void setValue(TDoubleProperty &prop, double value) {
Shinya Kitaoka 120a6e
      prop.setValue(value);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_this->onPropertyChanged(prop.getName());
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentTool()->notifyToolChanged();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    void addValue(TDoubleProperty &prop, double add) {
Shinya Kitaoka 120a6e
      const TDoubleProperty::Range &range = prop.getRange();
Shinya Kitaoka 120a6e
      setValue(prop, tcrop(prop.getValue() + add, range.first, range.second));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } locals = {this};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (e.getModifiersMask()) {
Shinya Kitaoka 120a6e
  case TMouseEvent::ALT_KEY: {
Shinya Kitaoka 120a6e
    // User wants to alter the maximum brush size
Shinya Kitaoka 120a6e
    const TPointD &diff = pos - m_mousePos;
Shinya Kitaoka 120a6e
    double add          = (fabs(diff.x) > fabs(diff.y)) ? diff.x : diff.y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    locals.addValue(m_toolSize, add);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    m_brushPos = pos;
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_oldMousePos = m_mousePos = pos;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool EraserTool::onPropertyChanged(std::string propertyName) {
pojienie 4998cf
  EraseVectorType          = ::to_string(m_eraseType.getValue());
pojienie 4998cf
  EraseVectorInterpolation = ::to_string(m_interpolation.getValue());
pojienie 4998cf
  EraseVectorSize          = m_toolSize.getValue();
pojienie 4998cf
  EraseVectorSelective     = m_selective.getValue();
pojienie 4998cf
  EraseVectorInvert        = m_invertOption.getValue();
pojienie 4998cf
  EraseVectorRange         = m_multi.getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double x = m_toolSize.getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double minRange = 1;
Shinya Kitaoka 120a6e
  double maxRange = 100;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double minSize = 2;
Shinya Kitaoka 120a6e
  double maxSize = 100;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_pointSize =
Shinya Kitaoka 120a6e
      ((x - minRange) / (maxRange - minRange) * (maxSize - minSize) + minSize) *
Shinya Kitaoka 120a6e
      0.5;
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::onEnter() {
Shinya Kitaoka 120a6e
  if (m_firstTime) {
Shinya Kitaoka 120a6e
    m_toolSize.setValue(EraseVectorSize);
Shinya Kitaoka 120a6e
    m_eraseType.setValue(::to_wstring(EraseVectorType.getValue()));
pojienie 4998cf
    m_interpolation.setValue(::to_wstring(EraseVectorInterpolation.getValue()));
Shinya Kitaoka 120a6e
    m_selective.setValue(EraseVectorSelective ? 1 : 0);
Shinya Kitaoka 120a6e
    m_invertOption.setValue(EraseVectorInvert ? 1 : 0);
Shinya Kitaoka 120a6e
    m_multi.setValue(EraseVectorRange ? 1 : 0);
Shinya Kitaoka 120a6e
    m_firstTime = false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double x = m_toolSize.getValue();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double minRange = 1;
Shinya Kitaoka 120a6e
  double maxRange = 100;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double minSize = 2;
Shinya Kitaoka 120a6e
  double maxSize = 100;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_pointSize =
Shinya Kitaoka 120a6e
      ((x - minRange) / (maxRange - minRange) * (maxSize - minSize) + minSize) *
Shinya Kitaoka 120a6e
      0.5;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //  getApplication()->editImage();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::onLeave() {
Shinya Kitaoka 120a6e
  draw();
Shinya Kitaoka 120a6e
  m_pointSize = -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void EraserTool::onActivate() {
Shinya Kitaoka 120a6e
  resetMulti();
shun-iwasawa 93b2f8
  m_polyline.clear();
Shinya Kitaoka 120a6e
  onEnter();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene aggiunto \b pos a \b m_track e disegnato il primo pezzetto del lazzo.
Shinya Kitaoka 120a6e
//! Viene inizializzato \b m_firstPos
Shinya Kitaoka 120a6e
void EraserTool::startFreehand(const TPointD &pos) {
Shinya Kitaoka 120a6e
  m_track.clear();
Shinya Kitaoka 120a6e
  m_firstPos = pos;
Shinya Kitaoka 120a6e
  m_track.add(TThickPoint(pos, m_thick), getPixelSize() * getPixelSize());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene aggiunto \b pos a \b m_track e disegnato un altro pezzetto del lazzo.
Shinya Kitaoka 120a6e
void EraserTool::freehandDrag(const TPointD &pos) {
Toshihiro Shimizu 890ddd
#if defined(MACOSX)
Toshihiro Shimizu 890ddd
//		m_viewer->enableRedraw(false);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  m_track.add(TThickPoint(pos, m_thick), getPixelSize() * getPixelSize());
shun-iwasawa c189d1
  invalidate(m_track.getModifiedRegion());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene chiuso il lazzo (si aggiunge l'ultimo punto ad m_track) e viene creato
Shinya Kitaoka 120a6e
//! lo stroke rappresentante il lazzo.
Shinya Kitaoka 120a6e
void EraserTool::closeFreehand(const TPointD &pos) {
Toshihiro Shimizu 890ddd
#if defined(MACOSX)
Toshihiro Shimizu 890ddd
//		m_viewer->enableRedraw(true);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  if (m_track.isEmpty()) return;
Shinya Kitaoka 120a6e
  m_track.add(TThickPoint(m_firstPos, m_thick),
Shinya Kitaoka 120a6e
              getPixelSize() * getPixelSize());
Shinya Kitaoka 120a6e
  m_track.filterPoints();
Shinya Kitaoka 120a6e
  double error = (30.0 / 11) * sqrt(getPixelSize() * getPixelSize());
Shinya Kitaoka 120a6e
  m_stroke     = m_track.makeStroke(error);
Shinya Kitaoka 120a6e
  m_stroke->setStyle(1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene aggiunto un punto al vettore m_polyline.
Shinya Kitaoka 120a6e
void EraserTool::addPointPolyline(const TPointD &pos) {
Shinya Kitaoka 120a6e
  m_firstPos = pos;
Shinya Kitaoka 120a6e
  m_polyline.push_back(pos);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Agginge l'ultimo pos a \b m_polyline e chiude la spezzata (aggiunge \b
Shinya Kitaoka 120a6e
//! m_polyline.front() alla fine del vettore)
Shinya Kitaoka 120a6e
void EraserTool::closePolyline(const TPointD &pos) {
Shinya Kitaoka 120a6e
  if (m_polyline.size() <= 1) return;
Shinya Kitaoka 120a6e
  if (m_polyline.back() != pos) m_polyline.push_back(pos);
Shinya Kitaoka 120a6e
  if (m_polyline.back() != m_polyline.front())
Shinya Kitaoka 120a6e
    m_polyline.push_back(m_polyline.front());
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
pojienie 31955e
static bool doublePairCompare(DoublePair p1, DoublePair p2) {
pojienie 31955e
  return p1.first < p2.first;
pojienie 31955e
}
pojienie 31955e
pojienie 7933ab
void EraserTool::eraseSegments(const TVectorImageP vi, TStroke *eraseStroke) {
pojienie 7933ab
  if (!vi || !eraseStroke) return;
pojienie 31955e
pojienie 31955e
  int strokeNumber = vi->getStrokeCount();
pojienie ef2030
  int colorStyle   = TTool::getApplication()->getCurrentLevelStyleIndex();
pojienie 31955e
  std::vector<int> touchedStrokeIndex;</int>
pojienie 31955e
  std::vector<std::vector<double>> touchedStrokeW;</std::vector<double>
pojienie 31955e
  std::vector<std::vector<doublepair>> touchedStrokeRanges;</std::vector<doublepair>
pojienie 31955e
pojienie 31955e
  // find all touched strokes and where it is touched
pojienie 31955e
  for (int i = 0; i < strokeNumber; ++i) {
pojienie 31955e
    std::vector<doublepair> intersections;</doublepair>
pojienie 31955e
    std::vector<double> ws;</double>
pojienie 31955e
    TStroke *stroke = vi->getStroke(i);
pojienie 31955e
    bool touched    = false;
pojienie 31955e
pojienie ef2030
    if (m_selective.getValue() && stroke->getStyle() != colorStyle) {
pojienie ef2030
      continue;
pojienie ef2030
    }
pojienie ef2030
pojienie 31955e
    intersect(eraseStroke, stroke, intersections, false);
pojienie 31955e
pojienie 31955e
    for (auto &intersection : intersections) {
pojienie 31955e
      touched = true;
pojienie 31955e
      ws.push_back(intersection.second);
pojienie 31955e
    }
pojienie 31955e
pojienie 31955e
    if (touched) {
pojienie 31955e
      touchedStrokeIndex.push_back(i);
pojienie 31955e
      touchedStrokeW.push_back(ws);
pojienie 31955e
    }
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // if the eraser did not touch any strokes, return
pojienie 31955e
  if (touchedStrokeIndex.size() == 0) {
pojienie 7933ab
    return;
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // find closest intersections of each end of the touched place of each stroke
pojienie 31955e
  for (int i = 0; i < touchedStrokeIndex.size(); ++i) {
pojienie 31955e
    std::vector<doublepair> range;</doublepair>
pojienie 31955e
    for (auto w : touchedStrokeW[i]) {
pojienie 31955e
      std::vector<doublepair> intersections;</doublepair>
pojienie 31955e
      double lowerW = 0.0, higherW = 1.0;
pojienie 31955e
      double higherW0 = 1.0,
pojienie 31955e
             lowerW1  = 0.0;  // these two value are used when the stroke is
pojienie 31955e
                              // self-loop-ed, it assumes touched W is 0 or 1 to
pojienie 31955e
                              // find closet intersection
pojienie 31955e
pojienie 31955e
      int strokeIndex = touchedStrokeIndex[i];
pojienie 31955e
      TStroke *stroke = vi->getStroke(strokeIndex);
pojienie 31955e
pojienie 31955e
      // check self intersection first
pojienie 31955e
      intersect(stroke, stroke, intersections, false);
pojienie 31955e
      for (auto &intersection : intersections) {
pojienie 31955e
        if (areAlmostEqual(intersection.first, 0, 1e-6)) {
pojienie 31955e
          continue;
pojienie 31955e
        }
pojienie 31955e
        if (areAlmostEqual(intersection.second, 1, 1e-6)) {
pojienie 31955e
          continue;
pojienie 31955e
        }
pojienie 31955e
pojienie 31955e
        if (intersection.first < w) {
pojienie 31955e
          lowerW = max(lowerW, intersection.first);
pojienie 31955e
        } else {
pojienie 31955e
          higherW = min(higherW, intersection.first);
pojienie 31955e
        }
pojienie 31955e
pojienie 31955e
        if (intersection.second < w) {
pojienie 31955e
          lowerW = max(lowerW, intersection.second);
pojienie 31955e
        } else {
pojienie 31955e
          higherW = min(higherW, intersection.second);
pojienie 31955e
        }
pojienie 31955e
pojienie 31955e
        lowerW1  = max(lowerW1, intersection.first);
pojienie 31955e
        higherW0 = min(higherW0, intersection.first);
pojienie 31955e
        lowerW1  = max(lowerW1, intersection.second);
pojienie 31955e
        higherW0 = min(higherW0, intersection.second);
pojienie 31955e
      }
pojienie 31955e
pojienie 31955e
      // then check intersection with other strokes
pojienie 31955e
      for (int j = 0; j < strokeNumber; ++j) {
pojienie 31955e
        if (j == strokeIndex) {
pojienie 31955e
          continue;
pojienie 31955e
        }
pojienie 31955e
pojienie 31955e
        TStroke *intersectedStroke = vi->getStroke(j);
pojienie 31955e
        intersect(stroke, intersectedStroke, intersections, false);
pojienie 31955e
        for (auto &intersection : intersections) {
pojienie 31955e
          if (intersection.first < w) {
pojienie 31955e
            lowerW = max(lowerW, intersection.first);
pojienie 31955e
          } else {
pojienie 31955e
            higherW = min(higherW, intersection.first);
pojienie 31955e
          }
pojienie 31955e
          lowerW1  = max(lowerW1, intersection.first);
pojienie 31955e
          higherW0 = min(higherW0, intersection.first);
pojienie 31955e
        }
pojienie 31955e
      }
pojienie 31955e
pojienie 31955e
      range.push_back(std::make_pair(lowerW, higherW));
pojienie 31955e
      if (stroke->isSelfLoop()) {
pojienie 31955e
        if (lowerW == 0.0) {
pojienie 31955e
          range.push_back(std::make_pair(lowerW1, 1.0));
pojienie 31955e
        } else if (higherW == 1.0) {
pojienie 31955e
          range.push_back(std::make_pair(0.0, higherW0));
pojienie 31955e
        }
pojienie 31955e
      }
pojienie 31955e
    }
pojienie 31955e
    touchedStrokeRanges.push_back(range);
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // merge all ranges of the same stroke by using interval merging algorithm
pojienie 31955e
  for (auto &ranges : touchedStrokeRanges) {
pojienie 31955e
    std::vector<doublepair> merged;</doublepair>
pojienie 31955e
pojienie 31955e
    std::sort(ranges.begin(), ranges.end(), doublePairCompare);
pojienie 31955e
pojienie 31955e
    merged.push_back(ranges[0]);
pojienie 31955e
    for (auto &range : ranges) {
pojienie 31955e
      if (merged.back().second < range.first &&
pojienie 31955e
          !areAlmostEqual(merged.back().second, range.first, 1e-3)) {
pojienie 31955e
        merged.push_back(range);
pojienie 31955e
      } else if (merged.back().second < range.second) {
pojienie 31955e
        merged.back().second = range.second;
pojienie 31955e
      }
pojienie 31955e
    }
pojienie 31955e
pojienie 31955e
    ranges = merged;
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // create complement range
pojienie 31955e
  for (auto &ranges : touchedStrokeRanges) {
pojienie 31955e
    std::vector<doublepair> complement;</doublepair>
pojienie 31955e
pojienie 31955e
    double last = 0.0;
pojienie 31955e
    for (auto &range : ranges) {
pojienie 31955e
      if (!areAlmostEqual(last, range.first, 1e-3)) {
pojienie 31955e
        complement.push_back(std::make_pair(last, range.first));
pojienie 31955e
      }
pojienie 31955e
      last = range.second;
pojienie 31955e
    }
pojienie 31955e
pojienie 31955e
    if (!areAlmostEqual(last, 1.0, 1e-3)) {
pojienie 31955e
      complement.push_back(std::make_pair(last, 1.0));
pojienie 31955e
    }
pojienie 31955e
    ranges = complement;
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // calculate how many lines are added for caculating the final index of added
pojienie 31955e
  // strokes
pojienie 31955e
  int added = 0;
pojienie 31955e
  for (int i = touchedStrokeIndex.size() - 1; i >= 0; --i) {
pojienie 31955e
    bool willbeJoined = vi->getStroke(touchedStrokeIndex[i])->isSelfLoop() &&
pojienie 31955e
                        touchedStrokeRanges[i][0].first == 0.0 &&
pojienie 31955e
                        touchedStrokeRanges[i].back().second == 1.0;
pojienie 31955e
pojienie 31955e
    added += touchedStrokeRanges[i].size();
pojienie 31955e
    if (willbeJoined) {
pojienie 31955e
      --added;
pojienie 31955e
    }
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  // do the erasing and construct the undo action
pojienie 31955e
  TXshSimpleLevel *level =
pojienie 31955e
      TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
pojienie 31955e
  UndoEraser *undo = new UndoEraser(level, getCurrentFid());
pojienie 31955e
  for (int i = touchedStrokeIndex.size() - 1; i >= 0; --i) {
pojienie 31955e
    undo->addOldStroke(touchedStrokeIndex[i],
pojienie 31955e
                       vi->getVIStroke(touchedStrokeIndex[i]));
pojienie 31955e
pojienie 31955e
    if (touchedStrokeRanges[i].size() == 0) {
pojienie 31955e
      vi->deleteStroke(touchedStrokeIndex[i]);
pojienie 31955e
    } else {
pojienie 31955e
      bool willbeJoined = vi->getStroke(touchedStrokeIndex[i])->isSelfLoop() &&
pojienie 31955e
                          touchedStrokeRanges[i][0].first == 0.0 &&
pojienie 31955e
                          touchedStrokeRanges[i].back().second == 1.0;
pojienie 31955e
pojienie 31955e
      vi->splitStroke(touchedStrokeIndex[i], touchedStrokeRanges[i]);
pojienie 31955e
pojienie 31955e
      int size = touchedStrokeRanges[i].size();
pojienie 31955e
      if (willbeJoined) {
pojienie 31955e
        --size;
pojienie 31955e
      }
pojienie 31955e
      added -= size;
pojienie 31955e
      for (int j = 0; j < size; ++j) {
pojienie 31955e
        int finalIndex   = touchedStrokeIndex[i] + j - i + added;
pojienie 31955e
        int currentIndex = touchedStrokeIndex[i] + j;
pojienie 31955e
        undo->addNewStroke(finalIndex, vi->getVIStroke(currentIndex));
pojienie 31955e
      }
pojienie 31955e
    }
pojienie 31955e
  }
pojienie 31955e
pojienie 31955e
  TUndoManager::manager()->add(undo);
pojienie 7933ab
  return;
pojienie 31955e
}
pojienie 31955e
pojienie 31955e
//-----------------------------------------------------------------------------
pojienie 31955e
Shinya Kitaoka 120a6e
//! Cancella stroke presenti in \b vi e contenuti nella regione delimitata da \b
Shinya Kitaoka 120a6e
//! stroke.
Shinya Kitaoka 120a6e
/*!Vengono cercati gli stroke da cancellare facendo i dovuti controlli sui
Shinya Kitaoka 120a6e
   parametri \b m_invertOption e \b m_selective.
Shinya Kitaoka 120a6e
        Se uno stroke deve essere cancellato viene inserito in \b eraseStrokes.
Shinya Kitaoka 120a6e
        Gli stroke vengono cancellati tutti alla fine.*/
Shinya Kitaoka 120a6e
void EraserTool::eraseRegion(
Shinya Kitaoka 120a6e
    const TVectorImageP vi,
Shinya Kitaoka 120a6e
    TStroke *stroke)  //, const TImageLocation &imageLocation)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  if (!vi || !stroke) return;
Shinya Kitaoka 120a6e
  TVectorImage eraseImg;
Shinya Kitaoka 120a6e
  TStroke *eraseStroke = new TStroke(*stroke);
Shinya Kitaoka 120a6e
  eraseImg.addStroke(eraseStroke);
Shinya Kitaoka 120a6e
  eraseImg.findRegions();
Shinya Kitaoka 120a6e
  int strokeIndex, regionIndex, colorStyle;
Shinya Kitaoka 120a6e
  colorStyle = TTool::getApplication()->getCurrentLevelStyleIndex();
Shinya Kitaoka 120a6e
  std::vector<int> eraseStrokes;</int>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshSimpleLevel *level =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
  m_undo = new UndoEraser(level, getCurrentFid());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_invertOption.getValue()) {
Shinya Kitaoka 120a6e
    for (strokeIndex = 0; strokeIndex < (int)vi->getStrokeCount();
Shinya Kitaoka 120a6e
         strokeIndex++) {
Shinya Kitaoka 120a6e
      if (!vi->inCurrentGroup(strokeIndex)) continue;
Shinya Kitaoka 120a6e
      TStroke *currentStroke = vi->getStroke(strokeIndex);
Shinya Kitaoka 120a6e
      for (regionIndex = 0; regionIndex < (int)eraseImg.getRegionCount();
Shinya Kitaoka 120a6e
           regionIndex++) {
Shinya Kitaoka 120a6e
        TRegion *region = eraseImg.getRegion(regionIndex);
Shinya Kitaoka 120a6e
        if ((!m_selective.getValue() ||
Shinya Kitaoka 120a6e
             (m_selective.getValue() &&
Shinya Kitaoka 120a6e
              currentStroke->getStyle() == colorStyle)) &&
Shinya Kitaoka 120a6e
            region->contains(*currentStroke, true)) {
Shinya Kitaoka 120a6e
          eraseStrokes.push_back(strokeIndex);
Shinya Kitaoka 120a6e
          m_undo->addOldStroke(strokeIndex, vi->getVIStroke(strokeIndex));
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    for (strokeIndex = 0; strokeIndex < (int)vi->getStrokeCount();
Shinya Kitaoka 120a6e
         strokeIndex++) {
Shinya Kitaoka 120a6e
      TStroke *currentStroke = vi->getStroke(strokeIndex);
Shinya Kitaoka 120a6e
      bool eraseIt           = false;
Shinya Kitaoka 120a6e
      for (regionIndex = 0; regionIndex < (int)eraseImg.getRegionCount();
Shinya Kitaoka 120a6e
           regionIndex++) {
Shinya Kitaoka 120a6e
        TRegion *region = eraseImg.getRegion(regionIndex);
Shinya Kitaoka 120a6e
        if (!m_selective.getValue() ||
Shinya Kitaoka 120a6e
            (m_selective.getValue() && currentStroke->getStyle() == colorStyle))
Shinya Kitaoka 120a6e
          eraseIt = true;
Shinya Kitaoka 120a6e
        if (region->contains(*currentStroke, true)) {
Shinya Kitaoka 120a6e
          eraseIt = false;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (eraseIt) {
Shinya Kitaoka 120a6e
        m_undo->addOldStroke(strokeIndex, vi->getVIStroke(strokeIndex));
Shinya Kitaoka 120a6e
        eraseStrokes.push_back(strokeIndex);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = (int)eraseStrokes.size() - 1; i >= 0; i--)
Shinya Kitaoka 120a6e
    vi->deleteStroke(eraseStrokes[i]);
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
  m_undo = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene richiamata la doErase sui frame compresi tra \b firstFrameId e \b
Shinya Kitaoka 120a6e
//! lastFrameId.
Shinya Kitaoka 120a6e
/*!Viene caricato il vettore \b fids con i TFrameId delle immagini sulle quali
Shinya Kitaoka 120a6e
 * si deve effettuare una cancellazione.*/
Toshihiro Shimizu 890ddd
void EraserTool::doMultiErase(TFrameId &firstFrameId, TFrameId &lastFrameId,
Shinya Kitaoka 120a6e
                              const TStroke *firstStroke,
pojienie 7933ab
                              const TStroke *lastStroke,
pojienie 7933ab
                              EraserTool::EraseFunction eraseFunction) {
Shinya Kitaoka 120a6e
  TXshSimpleLevel *sl =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentLevel()->getLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
  TStroke *first           = new TStroke();
Shinya Kitaoka 120a6e
  TStroke *last            = new TStroke();
Shinya Kitaoka 120a6e
  *first                   = *firstStroke;
Shinya Kitaoka 120a6e
  *last                    = *lastStroke;
Shinya Kitaoka 120a6e
  TVectorImageP firstImage = new TVectorImage();
Shinya Kitaoka 120a6e
  TVectorImageP lastImage  = new TVectorImage();
Shinya Kitaoka 120a6e
  firstImage->addStroke(first);
Shinya Kitaoka 120a6e
  lastImage->addStroke(last);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool backward = false;
Shinya Kitaoka 120a6e
  if (firstFrameId > lastFrameId) {
otakuto ed7dcd
    std::swap(firstFrameId, lastFrameId);
Shinya Kitaoka 120a6e
    backward = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  assert(firstFrameId <= lastFrameId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tframeid> allFids;</tframeid>
Shinya Kitaoka 120a6e
  sl->getFids(allFids);
Shinya Kitaoka 120a6e
  std::vector<tframeid>::iterator i0 = allFids.begin();</tframeid>
Shinya Kitaoka 120a6e
  while (i0 != allFids.end() && *i0 < firstFrameId) i0++;
Shinya Kitaoka 120a6e
  if (i0 == allFids.end()) return;
Shinya Kitaoka 120a6e
  std::vector<tframeid>::iterator i1 = i0;</tframeid>
Shinya Kitaoka 120a6e
  while (i1 != allFids.end() && *i1 <= lastFrameId) i1++;
Shinya Kitaoka 120a6e
  assert(i0 < i1);
Shinya Kitaoka 120a6e
  std::vector<tframeid> fids(i0, i1);</tframeid>
Shinya Kitaoka 120a6e
  int m = fids.size();
Shinya Kitaoka 120a6e
  assert(m > 0);
Shinya Kitaoka 120a6e
Martin van Zijl 18c2b4
  // Find the starting frame for the current level in the XSheet.
Martin van Zijl 18c2b4
  TTool::Application *app = TTool::getApplication();
Martin van Zijl 18c2b4
  int startRowInXSheet = 0, endRowInXSheet = 0;
Martin van Zijl 18c2b4
  if (app && app->getCurrentFrame()->isEditingScene()) {
pojienie 31955e
    int currentRow     = getFrame();
pojienie 31955e
    TXsheet *xSheet    = getXsheet();
Martin van Zijl 18c2b4
    TXshColumn *column = xSheet->getColumn(getColumnIndex());
Martin van Zijl 18c2b4
    column->getLevelRange(currentRow, startRowInXSheet, endRowInXSheet);
Martin van Zijl 18c2b4
  }
Martin van Zijl 18c2b4
pojienie 4998cf
  enum TInbetween::TweenAlgorithm algorithm = TInbetween::LinearInterpolation;
pojienie 4998cf
  if (m_interpolation.getValue() == EASE_IN_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseInInterpolation;
pojienie 4998cf
  } else if (m_interpolation.getValue() == EASE_OUT_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseOutInterpolation;
pojienie 4998cf
  } else if (m_interpolation.getValue() == EASE_IN_OUT_INTERPOLATION) {
pojienie 4998cf
    algorithm = TInbetween::EaseInOutInterpolation;
pojienie 4998cf
  }
pojienie 4998cf
Shinya Kitaoka 120a6e
  TUndoManager::manager()->beginBlock();
Shinya Kitaoka 120a6e
  for (int i = 0; i < m; ++i) {
Shinya Kitaoka 120a6e
    TFrameId fid = fids[i];
Shinya Kitaoka 120a6e
    assert(firstFrameId <= fid && fid <= lastFrameId);
Shinya Kitaoka 120a6e
    double t = m > 1 ? (double)i / (double)(m - 1) : 0.5;
pojienie 4998cf
    t        = TInbetween::interpolation(t, algorithm);
Shinya Kitaoka 120a6e
    // Setto il fid come corrente per notificare il cambiamento dell'immagine
Shinya Kitaoka 120a6e
    if (app) {
Shinya Kitaoka 120a6e
      if (app->getCurrentFrame()->isEditingScene())
pojienie 31955e
        app->getCurrentFrame()->setFrame(startRowInXSheet + fid.getNumber() -
pojienie 31955e
                                         1);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        app->getCurrentFrame()->setFid(fid);
Shinya Kitaoka 120a6e
    }
pojienie 7933ab
    doErase(backward ? 1 - t : t, sl, fid, firstImage, lastImage,
pojienie 7933ab
            eraseFunction);
Shinya Kitaoka 120a6e
    notifyImageChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TUndoManager::manager()->endBlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Viene richiamata la \b eraseRegion per il frame giusto nel caso della
Shinya Kitaoka 120a6e
//! modalita' "Frame Range".
Shinya Kitaoka 120a6e
/*!Nei casi in cui \b t e' diverso da zero e uno, viene generata una nuova \b
Shinya Kitaoka 120a6e
   TVectorImageP richiamando la \b TInbetween.
Shinya Kitaoka 120a6e
        La nuova immagine contiene lo stroke da dare alla eraseRegion. \b fid e'
Shinya Kitaoka 120a6e
   il TFrameId dell'immagine sulla quale
Shinya Kitaoka 120a6e
        bisogna effettuare la cancellazione.*/
Shinya Kitaoka 120a6e
void EraserTool::doErase(double t, const TXshSimpleLevelP &sl,
Shinya Kitaoka 120a6e
                         const TFrameId &fid, const TVectorImageP &firstImage,
pojienie 7933ab
                         const TVectorImageP &lastImage,
pojienie 7933ab
                         EraserTool::EraseFunction eraseFunction) {
Shinya Kitaoka 120a6e
  //	TImageLocation imageLocation(m_level->getName(),fid);
Shinya Kitaoka 120a6e
  TVectorImageP img = sl->getFrame(fid, true);
Shinya Kitaoka 120a6e
  if (t == 0)
pojienie 7933ab
    (this->*eraseFunction)(img, firstImage->getStroke(0));  //,imageLocation);
Shinya Kitaoka 120a6e
  else if (t == 1)
pojienie 7933ab
    (this->*eraseFunction)(img, lastImage->getStroke(0));  //,imageLocation);
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    assert(firstImage->getStrokeCount() == 1);
Shinya Kitaoka 120a6e
    assert(lastImage->getStrokeCount() == 1);
Shinya Kitaoka 120a6e
    TVectorImageP vi = TInbetween(firstImage, lastImage).tween(t);
Shinya Kitaoka 120a6e
    assert(vi->getStrokeCount() == 1);
pojienie 7933ab
    (this->*eraseFunction)(img, vi->getStroke(0));  //,imageLocation);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Effettua la cancellazione nella modalita' "Frame range".
Shinya Kitaoka 120a6e
/*! Se il primo frame e' gia stato selezionato richiama la \b doMultiErase;
Shinya Kitaoka 120a6e
 altrimenti viene inizializzato
Toshihiro Shimizu 890ddd
 \b m_firstStroke.*/
pojienie 7933ab
void EraserTool::multiErase(TStroke *stroke, const TMouseEvent &e,
pojienie 7933ab
                            EraserTool::EraseFunction eraseFunction) {
Shinya Kitaoka 120a6e
  TTool::Application *application = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (!application) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_firstFrameSelected) {
Shinya Kitaoka 120a6e
    if (m_firstStroke && stroke) {
Shinya Kitaoka 120a6e
      TFrameId tmpFrameId = getCurrentFid();
pojienie 7933ab
      doMultiErase(m_firstFrameId, tmpFrameId, m_firstStroke, stroke,
pojienie 7933ab
                   eraseFunction);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (e.isShiftPressed()) {
Shinya Kitaoka 120a6e
      m_firstStroke  = new TStroke(*stroke);
Shinya Kitaoka 120a6e
      m_firstFrameId = getCurrentFid();
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (application->getCurrentFrame()->isEditingScene()) {
Shinya Kitaoka 120a6e
        application->getCurrentColumn()->setColumnIndex(m_currCell.first);
Shinya Kitaoka 120a6e
        application->getCurrentFrame()->setFrame(m_currCell.second);
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        application->getCurrentFrame()->setFid(m_veryFirstFrameId);
Shinya Kitaoka 120a6e
      resetMulti();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    m_firstStroke = new TStroke(*stroke);
Shinya Kitaoka 120a6e
    if (application->getCurrentFrame()->isEditingScene())
Shinya Kitaoka 120a6e
      m_currCell =
Shinya Kitaoka 120a6e
          std::pair<int, int="">(application->getCurrentColumn()->getColumnIndex(),</int,>
Shinya Kitaoka 120a6e
                              application->getCurrentFrame()->getFrame());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Jeremy Bullock 60023a
/*! When the tool is switched during dragging, Erase end processing is performed
shun-iwasawa 76d093
 */
Shinya Kitaoka 120a6e
void EraserTool::onDeactivate() {
Shinya Kitaoka 120a6e
  if (!m_active) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_active = false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // TODO : finishing erase procedure is only available for normal type.
Shinya Kitaoka 120a6e
  // Supporting other types is needed. 2016/1/22 shun_iwasawa
Shinya Kitaoka 120a6e
  if (m_eraseType.getValue() != NORMAL_ERASE) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TImageP image(getImage(true));
Shinya Kitaoka 120a6e
  TVectorImageP vi                = image;
Shinya Kitaoka 120a6e
  TTool::Application *application = TTool::getApplication();
Shinya Kitaoka 120a6e
  if (!vi || !application) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  stopErase(vi);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TTool *getEraserTool() {return &eraserTool;}