|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorgl.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tgl.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tpalette.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tproperty.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tthreadmessage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorimage.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "drawutil.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tcurveutil.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstroke.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstrokeutil.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tvectorrenderdata.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tstrokedeformations.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tmathutil.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Toonz includes
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/tobjecthandle.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "toonz/txshlevelhandle.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// TnzTools includes
|
|
Toshihiro Shimizu |
890ddd |
#include "tools/tool.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tools/toolutils.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tools/cursors.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// 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 |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// PumpTool declaration
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
d1f6c4 |
class PumpTool final : public TTool {
|
|
Shinya Kitaoka |
120a6e |
Q_DECLARE_TR_FUNCTIONS(PumpTool)
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int m_strokeStyleId, m_strokeIndex; //!< Edited stroke indices
|
|
Shinya Kitaoka |
120a6e |
TStroke *m_inStroke, *m_outStroke; //!< Input/Output strokes
|
|
Shinya Kitaoka |
120a6e |
std::vector<tstroke *=""></tstroke>
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes; //!< Merging these, m_inStroke is reformed
|
|
Shinya Kitaoka |
120a6e |
int m_stroke1Idx,
|
|
Shinya Kitaoka |
120a6e |
m_stroke2Idx; //!< Indices of deformed strokes among split ones
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TUndo *m_undo; //!< Undo to be added upon non-trivial button up
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double m_actionW; //!< The action center stroke parameter
|
|
Shinya Kitaoka |
120a6e |
double m_actionS1, m_actionS2; //!< Action center length in m_stroke
|
|
Shinya Kitaoka |
120a6e |
double m_actionRadius; //!< Tool action radius in curve length
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
std::vector<double></double>
|
|
Shinya Kitaoka |
120a6e |
m_splitPars; //!< Split parameters for action localization
|
|
Shinya Kitaoka |
120a6e |
std::vector<double> m_cpLenDiff1,</double>
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff2; //!< Distorted CPs' length distances from action center
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool m_active; //!< Whether a stroke is currently being edited
|
|
Shinya Kitaoka |
120a6e |
bool m_enabled; //!< Tells whether the image allows editing
|
|
Shinya Kitaoka |
120a6e |
bool m_cursorEnabled; //!< Whether the 'pump preview cursor' can be seen
|
|
Shinya Kitaoka |
120a6e |
bool m_draw; //!< Should be removed...?
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
bool m_isCtrlPressed; //!< Whether control key is held down or not
|
|
pojienie |
74b1dd |
int m_lockedStrokeIndex;
|
|
pojienie |
74b1dd |
|
|
Shinya Kitaoka |
120a6e |
TPointD m_oldPoint, m_downPoint; //!< Mouse positions upon editing
|
|
Shinya Kitaoka |
120a6e |
TThickPoint m_cursor; //!< Pump preview cursor data
|
|
Shinya Kitaoka |
120a6e |
int m_cursorId;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double m_errorTol; //!< Allowed approximation error during edit
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TDoubleProperty m_toolSize;
|
|
Shinya Kitaoka |
120a6e |
TIntProperty m_accuracy;
|
|
Shinya Kitaoka |
120a6e |
TPropertyGroup m_prop;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Shinya Kitaoka |
120a6e |
PumpTool()
|
|
Shinya Kitaoka |
120a6e |
: TTool("T_Pump")
|
|
Shinya Kitaoka |
120a6e |
, m_active(false)
|
|
Shinya Kitaoka |
120a6e |
, m_actionW(0)
|
|
Shinya Kitaoka |
120a6e |
, m_strokeIndex((std::numeric_limits<uint>::max)())</uint>
|
|
Shinya Kitaoka |
120a6e |
, m_inStroke(0)
|
|
Shinya Kitaoka |
120a6e |
, m_outStroke(0)
|
|
Shinya Kitaoka |
120a6e |
, m_stroke1Idx(-1)
|
|
Shinya Kitaoka |
120a6e |
, m_stroke2Idx(-1)
|
|
Shinya Kitaoka |
120a6e |
, m_cursorEnabled(false)
|
|
Shinya Kitaoka |
120a6e |
, m_cursorId(ToolCursor::PumpCursor)
|
|
Shinya Kitaoka |
120a6e |
, m_actionRadius(1)
|
|
Shinya Kitaoka |
120a6e |
, m_draw(false)
|
|
Shinya Kitaoka |
120a6e |
, m_undo(0)
|
|
Shinya Kitaoka |
120a6e |
, m_toolSize("Size:", 1, 100, 20)
|
|
Shinya Kitaoka |
120a6e |
, m_accuracy("Accuracy:", 0, 100, 40)
|
|
Shinya Kitaoka |
120a6e |
, m_enabled(false) {
|
|
Shinya Kitaoka |
120a6e |
bind(TTool::VectorImage);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitPars.resize(2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_prop.bind(m_toolSize);
|
|
Shinya Kitaoka |
120a6e |
m_prop.bind(m_accuracy);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
ToolType getToolType() const override { return TTool::LevelWriteTool; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
void updateTranslation() override {
|
|
Shinya Kitaoka |
120a6e |
m_toolSize.setQStringName(tr("Size:"));
|
|
Shinya Kitaoka |
120a6e |
m_accuracy.setQStringName(tr("Accuracy:"));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
void onEnter() override;
|
|
Shinya Kitaoka |
473e70 |
void onLeave() override;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
void draw() override;
|
|
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 &e) override;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
|
|
Shinya Kitaoka |
120a6e |
bool moveCursor(const TPointD &pos);
|
|
Toshihiro Shimizu |
890ddd |
|
|
manongjohn |
40a40e |
int getCursorId() const override {
|
|
manongjohn |
40a40e |
if (m_viewer && m_viewer->getGuidedStrokePickerMode())
|
|
manongjohn |
40a40e |
return m_viewer->getGuidedStrokePickerCursor();
|
|
manongjohn |
40a40e |
return m_cursorId;
|
|
manongjohn |
40a40e |
}
|
|
Shinya Kitaoka |
120a6e |
void invalidateCursorArea();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
473e70 |
void onDeactivate() override;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
private:
|
|
Shinya Kitaoka |
120a6e |
double actionRadius(double strokeLength);
|
|
Shinya Kitaoka |
120a6e |
void splitStroke(TStroke *s);
|
|
Shinya Kitaoka |
120a6e |
TStroke *mergeStrokes(const std::vector<tstroke *=""> &strokes);</tstroke>
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
bool getNearestStrokeWithLock(const TPointD &p, double &outW,
|
|
pojienie |
74b1dd |
UINT &strokeIndex, double &dist2,
|
|
pojienie |
74b1dd |
bool onlyInCurrentGroup = false);
|
|
pojienie |
74b1dd |
|
|
Toshihiro Shimizu |
890ddd |
} PumpToolInstance;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// PumpTool implementation
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::onEnter() {
|
|
Shinya Kitaoka |
120a6e |
m_draw = true;
|
|
Shinya Kitaoka |
120a6e |
if (TTool::getApplication()->getCurrentObject()->isSpline() ||
|
|
Shinya Kitaoka |
120a6e |
!(TVectorImageP)getImage(false)) {
|
|
Shinya Kitaoka |
120a6e |
m_enabled = false;
|
|
Shinya Kitaoka |
120a6e |
m_cursorId = ToolCursor::CURSOR_NO;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
m_enabled = true;
|
|
Shinya Kitaoka |
120a6e |
m_cursorId = ToolCursor::PumpCursor;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::draw() {
|
|
Shinya Kitaoka |
120a6e |
if (!m_draw || !m_enabled) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi = TImageP(getImage(false));
|
|
Shinya Kitaoka |
120a6e |
if (!vi) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
QMutexLocker lock(vi->getMutex());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TPalette *palette = vi->getPalette();
|
|
Shinya Kitaoka |
120a6e |
assert(palette);
|
|
Shinya Kitaoka |
120a6e |
if (m_active) {
|
|
Shinya Kitaoka |
120a6e |
// Editing with the tool
|
|
Shinya Kitaoka |
120a6e |
assert(m_outStroke);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TRectD bboxD(m_outStroke->getBBox());
|
|
Shinya Kitaoka |
120a6e |
TRect bbox(tfloor(bboxD.x0), tfloor(bboxD.y0), tceil(bboxD.x1) - 1,
|
|
Shinya Kitaoka |
120a6e |
tceil(bboxD.y1) - 1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
tglDraw(TVectorRenderData(TAffine(), bbox, palette, 0, true), m_outStroke);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Hovering
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double w, dist;
|
|
Shinya Kitaoka |
120a6e |
UINT index;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_cursorEnabled) {
|
|
Shinya Kitaoka |
120a6e |
// Draw cursor
|
|
Shinya Kitaoka |
120a6e |
glColor3d(1.0, 0.0, 1.0);
|
|
Shinya Kitaoka |
120a6e |
if (m_cursor.thick > 0) tglDrawCircle(m_cursor, m_cursor.thick);
|
|
Shinya Kitaoka |
120a6e |
tglDrawCircle(m_cursor, m_cursor.thick + 4 * getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
if (getNearestStrokeWithLock(m_cursor, w, index, dist, true)) {
|
|
Shinya Kitaoka |
120a6e |
TStroke *stroke = vi->getStroke(index);
|
|
Shinya Kitaoka |
120a6e |
double totalLen = stroke->getLength();
|
|
Shinya Kitaoka |
120a6e |
double actionLen = actionRadius(totalLen);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
tglColor(TPixel32::Red);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (totalLen < actionLen ||
|
|
Shinya Kitaoka |
120a6e |
(stroke->isSelfLoop() && totalLen < actionLen + actionLen))
|
|
Shinya Kitaoka |
120a6e |
drawStrokeCenterline(*stroke, getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
int i, chunckIndex1, chunckIndex2;
|
|
Shinya Kitaoka |
120a6e |
double t, t1, t2, w1, w2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double len = stroke->getLength(w);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double len1 = len - actionLen;
|
|
Rozhuk Ivan |
823a31 |
if (len1 < 0) {
|
|
Rozhuk Ivan |
823a31 |
if (stroke->isSelfLoop()) {
|
|
Shinya Kitaoka |
120a6e |
len1 += totalLen;
|
|
Rozhuk Ivan |
823a31 |
} else {
|
|
Shinya Kitaoka |
120a6e |
len1 = 0;
|
|
pojienie |
74b1dd |
}
|
|
pojienie |
74b1dd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double len2 = len + actionLen;
|
|
Rozhuk Ivan |
823a31 |
if (len2 > totalLen) {
|
|
Rozhuk Ivan |
823a31 |
if (stroke->isSelfLoop()) {
|
|
Shinya Kitaoka |
120a6e |
len2 -= totalLen;
|
|
Rozhuk Ivan |
823a31 |
} else {
|
|
Shinya Kitaoka |
120a6e |
len2 = totalLen;
|
|
pojienie |
74b1dd |
}
|
|
pojienie |
74b1dd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
w1 = stroke->getParameterAtLength(len1);
|
|
Shinya Kitaoka |
120a6e |
w2 = stroke->getParameterAtLength(len2);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int chunkCount = stroke->getChunkCount();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stroke->getChunkAndT(w1, chunckIndex1, t1);
|
|
Shinya Kitaoka |
120a6e |
stroke->getChunkAndT(w2, chunckIndex2, t2);
|
|
Shinya Kitaoka |
120a6e |
double step;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
const TThickQuadratic *q = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
glBegin(GL_LINE_STRIP);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
q = stroke->getChunk(chunckIndex1);
|
|
Shinya Kitaoka |
120a6e |
step = computeStep(*q, getPixelSize());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (chunckIndex1 == chunckIndex2 && t1 < t2) {
|
|
Shinya Kitaoka |
120a6e |
for (t = t1; t < t2; t += step) tglVertex(q->getPoint(t));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
tglVertex(stroke->getPoint(w2));
|
|
Shinya Kitaoka |
120a6e |
glEnd();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (t = t1; t < 1; t += step) tglVertex(q->getPoint(t));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (i = chunckIndex1 + 1; i != chunckIndex2; i++) {
|
|
Shinya Kitaoka |
120a6e |
if (i == chunkCount) i = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (i == chunckIndex2) break;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
q = stroke->getChunk(i);
|
|
Shinya Kitaoka |
120a6e |
step = computeStep(*q, getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
for (t = 0; t < 1; t += step) tglVertex(q->getPoint(t));
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
q = stroke->getChunk(chunckIndex2);
|
|
Shinya Kitaoka |
120a6e |
step = computeStep(*q, getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
for (t = 0; t < t2; t += step) tglVertex(q->getPoint(t));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
tglVertex(stroke->getPoint(w2));
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
glEnd();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
void PumpTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
|
|
manongjohn |
40a40e |
if (getViewer() && getViewer()->getGuidedStrokePickerMode()) {
|
|
manongjohn |
40a40e |
getViewer()->doPickGuideStroke(pos);
|
|
manongjohn |
40a40e |
return;
|
|
manongjohn |
40a40e |
}
|
|
manongjohn |
40a40e |
|
|
Shinya Kitaoka |
120a6e |
if (m_active || !m_enabled) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
m_isCtrlPressed = e.isCtrlPressed();
|
|
pojienie |
74b1dd |
|
|
Shinya Kitaoka |
120a6e |
assert(m_undo == 0);
|
|
Shinya Kitaoka |
120a6e |
m_active = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi(getImage(true));
|
|
Shinya Kitaoka |
120a6e |
if (!vi) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
QMutexLocker lock(vi->getMutex());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// set current point and init parameters
|
|
Shinya Kitaoka |
120a6e |
m_oldPoint = pos;
|
|
Shinya Kitaoka |
120a6e |
m_downPoint = pos;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_inStroke = m_outStroke = 0;
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = m_stroke2Idx = -1;
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[0] = m_splitPars[1] = -2;
|
|
Shinya Kitaoka |
120a6e |
m_actionW = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_errorTol = (1.0 - 0.01 * m_accuracy.getValue()) * getPixelSize();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double dist2 = 0.0;
|
|
Shinya Kitaoka |
120a6e |
int cpCount;
|
|
Shinya Kitaoka |
120a6e |
int i;
|
|
Shinya Kitaoka |
120a6e |
UINT index;
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
if (getNearestStrokeWithLock(pos, m_actionW, index, dist2)) {
|
|
Shinya Kitaoka |
120a6e |
// A stroke near the pressed point was found - modify it
|
|
Shinya Kitaoka |
120a6e |
m_active = true;
|
|
Shinya Kitaoka |
120a6e |
m_strokeIndex = index;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_inStroke = vi->getStroke(m_strokeIndex);
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = new TStroke(*m_inStroke);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double totalLength = m_inStroke->getLength();
|
|
Shinya Kitaoka |
120a6e |
TXshSimpleLevel *sl =
|
|
Shinya Kitaoka |
120a6e |
TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
|
|
Shinya Kitaoka |
120a6e |
assert(sl);
|
|
Shinya Kitaoka |
120a6e |
TFrameId id = getCurrentFid();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Allocate the modification undo - will be assigned to the undo manager on
|
|
Shinya Kitaoka |
120a6e |
// mouse release
|
|
Shinya Kitaoka |
120a6e |
m_undo = new UndoModifyStrokeAndPaint(sl, id, m_strokeIndex);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Set the stroke's style to 'none'. This is needed to make the original
|
|
Shinya Kitaoka |
120a6e |
// stroke transparent,
|
|
Shinya Kitaoka |
120a6e |
// while the deformed one is shown at its place.
|
|
Shinya Kitaoka |
120a6e |
m_strokeStyleId = m_inStroke->getStyle();
|
|
Shinya Kitaoka |
120a6e |
m_inStroke->setStyle(0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (totalLength <= 0.0) {
|
|
Shinya Kitaoka |
120a6e |
// Single point case
|
|
Shinya Kitaoka |
120a6e |
cpCount = m_inStroke->getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff1.resize(cpCount);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < cpCount; i++) m_cpLenDiff1[i] = 0.0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes.resize(1);
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[0] = new TStroke(*m_inStroke);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = 0;
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
// Common strokes - split the stroke according to deformation requirements
|
|
Shinya Kitaoka |
120a6e |
splitStroke(m_inStroke);
|
|
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 PumpTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) {
|
|
Shinya Kitaoka |
120a6e |
if (!m_active || !m_enabled) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi(getImage(true));
|
|
Shinya Kitaoka |
120a6e |
if (!vi || !m_outStroke) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
m_isCtrlPressed = e.isCtrlPressed();
|
|
pojienie |
74b1dd |
|
|
Shinya Kitaoka |
120a6e |
QMutexLocker lock(vi->getMutex());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Revert current deformation, recovering the one from button press
|
|
Shinya Kitaoka |
120a6e |
delete m_outStroke;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Retrieve cursor's vertical displacement
|
|
Shinya Kitaoka |
120a6e |
TPointD delta = TPointD(0, (pos - m_downPoint).y);
|
|
Shinya Kitaoka |
120a6e |
int deltaSign = tsign(delta.y);
|
|
Shinya Kitaoka |
120a6e |
if (deltaSign == 0) {
|
|
Shinya Kitaoka |
120a6e |
// Use a copy of the original stroke
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = new TStroke(*m_inStroke);
|
|
Shinya Kitaoka |
120a6e |
m_outStroke->setStyle(m_strokeStyleId);
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Build deformation upon the original stroke pieces
|
|
Shinya Kitaoka |
120a6e |
TStroke *stroke1 = 0, *stroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stroke1 = new TStroke(*m_splitStrokes[m_stroke1Idx]);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Deform stroke1
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer(stroke1, delta, m_actionS1,
|
|
Shinya Kitaoka |
120a6e |
m_actionRadius, deltaSign);
|
|
Shinya Kitaoka |
120a6e |
modifyThickness(*stroke1, deformer, m_cpLenDiff1, deltaSign < 0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_stroke2Idx >= 0) {
|
|
Shinya Kitaoka |
120a6e |
// Deform stroke2
|
|
Shinya Kitaoka |
120a6e |
stroke2 = new TStroke(*m_splitStrokes[m_stroke2Idx]);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer2(stroke2, delta, m_actionS2,
|
|
Shinya Kitaoka |
120a6e |
m_actionRadius, deltaSign);
|
|
Shinya Kitaoka |
120a6e |
modifyThickness(*stroke2, deformer2, m_cpLenDiff2, deltaSign < 0);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Apply deformation
|
|
Shinya Kitaoka |
120a6e |
std::vector<tstroke *=""> splitStrokesCopy(m_splitStrokes);</tstroke>
|
|
pojienie |
74b1dd |
splitStrokesCopy[m_stroke1Idx] = stroke1;
|
|
Shinya Kitaoka |
120a6e |
if (stroke2) splitStrokesCopy[m_stroke2Idx] = stroke2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = mergeStrokes(splitStrokesCopy);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete stroke1;
|
|
Shinya Kitaoka |
120a6e |
delete stroke2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
void PumpTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (!m_active || !m_enabled) goto cleanup;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
vi = TVectorImageP(getImage(true));
|
|
Shinya Kitaoka |
120a6e |
if (!vi) goto cleanup;
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
m_isCtrlPressed = e.isCtrlPressed();
|
|
pojienie |
74b1dd |
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
m_active = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
QMutexLocker lock(vi->getMutex());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Reset cursor data
|
|
Shinya Kitaoka |
120a6e |
double t;
|
|
Shinya Kitaoka |
120a6e |
UINT index;
|
|
Shinya Kitaoka |
120a6e |
double dist2;
|
|
pojienie |
74b1dd |
if (getNearestStrokeWithLock(pos, t, index, dist2)) {
|
|
pojienie |
74b1dd |
TStroke *nearestStroke = vi->getStroke(index);
|
|
Shinya Kitaoka |
120a6e |
if (nearestStroke) m_cursor = nearestStroke->getThickPoint(t);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_outStroke &&
|
|
Shinya Kitaoka |
120a6e |
!areAlmostEqual(m_downPoint, pos, PickRadius * getPixelSize())) {
|
|
Shinya Kitaoka |
120a6e |
// Accept action
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Clone input stroke - it is someway needed by the stroke change
|
|
Shinya Kitaoka |
120a6e |
// notifier... I wonder why...
|
|
Shinya Kitaoka |
120a6e |
TStroke *oldStroke = new TStroke(*m_inStroke);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_outStroke->swap(*m_inStroke);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_inStroke->invalidate();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete m_outStroke;
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
assert(m_undo);
|
|
Shinya Kitaoka |
120a6e |
TUndoManager::manager()->add(m_undo);
|
|
Shinya Kitaoka |
120a6e |
m_undo = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
vi->notifyChangedStrokes(m_strokeIndex, oldStroke);
|
|
Shinya Kitaoka |
120a6e |
notifyImageChanged();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete oldStroke;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
cleanup:
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_inStroke)
|
|
Shinya Kitaoka |
120a6e |
m_inStroke->setStyle(
|
|
Shinya Kitaoka |
120a6e |
m_strokeStyleId); // Make the image stroke visible again
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_strokeIndex = m_strokeStyleId = -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
clearPointerContainer(m_splitStrokes);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete m_outStroke;
|
|
Shinya Kitaoka |
120a6e |
m_inStroke = m_outStroke = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
delete m_undo;
|
|
Shinya Kitaoka |
120a6e |
m_undo = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::invalidateCursorArea() {
|
|
Shinya Kitaoka |
120a6e |
double r = m_cursor.thick + 6;
|
|
Shinya Kitaoka |
120a6e |
TPointD d(r, r);
|
|
Shinya Kitaoka |
120a6e |
invalidate(TRectD(m_cursor - d, m_cursor + d));
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
|
|
Shinya Kitaoka |
120a6e |
if (m_active || !m_enabled) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
pojienie |
74b1dd |
m_isCtrlPressed = e.isCtrlPressed();
|
|
pojienie |
74b1dd |
|
|
Shinya Kitaoka |
120a6e |
// Cursor preview updates on 3-pixel steps
|
|
Shinya Kitaoka |
120a6e |
if (tdistance2(pos, m_oldPoint) < 9.0 * sq(getPixelSize())) return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (!m_draw) m_draw = true;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_oldPoint = pos;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (moveCursor(pos)) {
|
|
Shinya Kitaoka |
120a6e |
m_cursorEnabled = true;
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
m_cursorEnabled = false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
bool PumpTool::moveCursor(const TPointD &pos) {
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi(getImage(false));
|
|
Shinya Kitaoka |
120a6e |
if (vi) {
|
|
Shinya Kitaoka |
120a6e |
double t;
|
|
Shinya Kitaoka |
120a6e |
UINT index;
|
|
Shinya Kitaoka |
120a6e |
double dist2;
|
|
pojienie |
74b1dd |
if (getNearestStrokeWithLock(pos, t, index, dist2)) {
|
|
Shinya Kitaoka |
120a6e |
TStroke *stroke = vi->getStroke(index);
|
|
Shinya Kitaoka |
120a6e |
if (stroke) {
|
|
Shinya Kitaoka |
120a6e |
m_cursor = stroke->getThickPoint(t);
|
|
Shinya Kitaoka |
120a6e |
return true;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::onDeactivate() {
|
|
Shinya Kitaoka |
120a6e |
m_draw = false;
|
|
Shinya Kitaoka |
120a6e |
if (m_active) {
|
|
Shinya Kitaoka |
120a6e |
m_active = false;
|
|
Shinya Kitaoka |
120a6e |
TVectorImageP vi(getImage(true));
|
|
Shinya Kitaoka |
120a6e |
assert(!!vi && m_outStroke);
|
|
Shinya Kitaoka |
120a6e |
if (!vi || !m_outStroke) return;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
clearPointerContainer(m_splitStrokes);
|
|
Shinya Kitaoka |
120a6e |
if (m_splitPars[0] == -1) {
|
|
Shinya Kitaoka |
120a6e |
delete m_outStroke;
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// restore previous style
|
|
Shinya Kitaoka |
120a6e |
assert(m_strokeIndex >= 0);
|
|
Shinya Kitaoka |
120a6e |
if (m_strokeIndex >= 0) {
|
|
Shinya Kitaoka |
120a6e |
TStroke *stroke = vi->getStroke(m_strokeIndex);
|
|
Shinya Kitaoka |
120a6e |
stroke->setStyle(m_strokeStyleId);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
assert(m_undo);
|
|
Shinya Kitaoka |
120a6e |
delete m_undo;
|
|
Shinya Kitaoka |
120a6e |
m_undo = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
invalidate();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
m_strokeIndex = -1;
|
|
Shinya Kitaoka |
120a6e |
m_outStroke = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::onLeave() {
|
|
Shinya Kitaoka |
120a6e |
if (!m_active) m_draw = false;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
// PumpTool privates
|
|
Toshihiro Shimizu |
890ddd |
//*****************************************************************************
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double PumpTool::actionRadius(double strokeLength) {
|
|
Jeremy Bullock |
0aebf8 |
double toolSize = m_toolSize.getValue();
|
|
Shinya Kitaoka |
120a6e |
double toolPercent = toolSize * 0.01;
|
|
Shinya Kitaoka |
120a6e |
double interpolationVal = pow(toolPercent, 5);
|
|
Shinya Kitaoka |
120a6e |
double indipendentValue = 7.0 * toolSize;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
double actionRadius = (indipendentValue) * (1.0 - interpolationVal) +
|
|
Shinya Kitaoka |
120a6e |
(strokeLength * toolPercent) * interpolationVal;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return std::max(actionRadius, indipendentValue);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
Edited strokes are split near the corresponding editing position, in order
|
|
Toshihiro Shimizu |
890ddd |
to localize stroke manipulation.
|
|
Toshihiro Shimizu |
890ddd |
Only the localized part of the stroke will receive CP increase and thickness
|
|
Toshihiro Shimizu |
890ddd |
tuning needed for the tool action.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Shinya Kitaoka |
120a6e |
void PumpTool::splitStroke(TStroke *s) {
|
|
Shinya Kitaoka |
120a6e |
assert(m_splitStrokes.empty());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TStroke *stroke1 = 0, *stroke2 = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Build the action radius
|
|
Shinya Kitaoka |
120a6e |
double totalLength = s->getLength();
|
|
Shinya Kitaoka |
120a6e |
m_actionRadius = actionRadius(totalLength);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Get the length at selected point and build the split (length) positions
|
|
Shinya Kitaoka |
120a6e |
m_actionS1 = s->getLength(m_actionW);
|
|
Shinya Kitaoka |
120a6e |
double startLen = m_actionS1 - m_actionRadius;
|
|
Shinya Kitaoka |
120a6e |
double endLen = m_actionS1 + m_actionRadius;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Now, perform splitting
|
|
Shinya Kitaoka |
120a6e |
int i, cpCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if ((startLen <= 0 && endLen >= totalLength) ||
|
|
Shinya Kitaoka |
120a6e |
(s->isSelfLoop() && totalLength < (m_actionRadius + m_actionRadius))) {
|
|
Shinya Kitaoka |
120a6e |
// The whole stroke is included in the action - no split
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes.resize(1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[0] = -1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[0] = new TStroke(*s);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = 0;
|
|
Shinya Kitaoka |
120a6e |
stroke1 = m_splitStrokes[m_stroke1Idx];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer(s, m_actionS1, m_actionRadius);
|
|
Shinya Kitaoka |
120a6e |
increaseControlPoints(*stroke1, deformer, getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
if (!s->isSelfLoop() || (startLen >= 0.0 && endLen <= totalLength)) {
|
|
Shinya Kitaoka |
120a6e |
// Regular split positions, in the [0.0, totalLength] range.
|
|
Shinya Kitaoka |
120a6e |
// Split points at extremities are dealt.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[0] = s->getParameterAtLength(
|
|
Shinya Kitaoka |
120a6e |
std::max(startLen, 0.0)); // Crop in the open case
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[1] = s->getParameterAtLength(std::min(endLen, totalLength));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (m_splitPars[0] ==
|
|
Shinya Kitaoka |
120a6e |
0.0) // the "&& m_splitPars[0] == totalLength" was dealt outside
|
|
Shinya Kitaoka |
120a6e |
{
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes.resize(2);
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[0] = new TStroke;
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[1] = new TStroke;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
s->split(m_splitPars[1], *(m_splitStrokes[0]), *(m_splitStrokes[1]));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = 0;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
if (m_splitPars[1] == 1.0) {
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes.resize(2);
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[0] = new TStroke;
|
|
Shinya Kitaoka |
120a6e |
m_splitStrokes[1] = new TStroke;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
s->split(m_splitPars[0], *(m_splitStrokes[0]), *(m_splitStrokes[1]));
|
|
Shinya Kitaoka |
120a6e |
} else
|
|
Shinya Kitaoka |
120a6e |
::splitStroke(*s, m_splitPars, m_splitStrokes);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = 1;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Update the edit point to refer to the central stroke piece
|
|
Shinya Kitaoka |
120a6e |
m_actionS1 -= m_splitStrokes[0]->getLength();
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stroke1 = m_splitStrokes[m_stroke1Idx];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Apply deformation to the middle piece
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer(stroke1, m_actionS1, m_actionRadius);
|
|
Shinya Kitaoka |
120a6e |
increaseControlPoints(*stroke1, deformer, getPixelSize());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_actionS2 = 0;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
// Circular 'overflow' case - (exactly) one split point is outside the
|
|
Shinya Kitaoka |
120a6e |
// regular scope.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// Since the action diameter is < totalLength, these cases are mutually
|
|
Shinya Kitaoka |
120a6e |
// exclusive.
|
|
Shinya Kitaoka |
120a6e |
if (startLen < 0)
|
|
Shinya Kitaoka |
120a6e |
startLen += totalLength;
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
endLen -= totalLength;
|
|
Shinya Kitaoka |
120a6e |
m_actionS1 -= totalLength;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
// The deformation must be applied in two distinct strokes, since its
|
|
Shinya Kitaoka |
120a6e |
// action interval crosses the junction point
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[0] = s->getParameterAtLength(endLen);
|
|
Shinya Kitaoka |
120a6e |
m_splitPars[1] = s->getParameterAtLength(startLen);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
::splitStroke(*s, m_splitPars, m_splitStrokes);
|
|
Shinya Kitaoka |
120a6e |
assert(m_splitStrokes.size() >= 3);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_stroke1Idx = 0;
|
|
Shinya Kitaoka |
120a6e |
m_stroke2Idx = 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stroke1 = m_splitStrokes[m_stroke1Idx];
|
|
Shinya Kitaoka |
120a6e |
stroke2 = m_splitStrokes[m_stroke2Idx];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
m_actionS2 = m_actionS1 + stroke2->getLength();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer(stroke1, m_actionS1, m_actionRadius);
|
|
Shinya Kitaoka |
120a6e |
increaseControlPoints(*stroke1, deformer, getPixelSize());
|
|
Shinya Kitaoka |
120a6e |
TStrokeThicknessDeformation deformer2(stroke2, m_actionS2,
|
|
Shinya Kitaoka |
120a6e |
m_actionRadius);
|
|
Shinya Kitaoka |
120a6e |
increaseControlPoints(*stroke2, deformer2, getPixelSize());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
cpCount = stroke2->getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff2.resize(cpCount);
|
|
Shinya Kitaoka |
120a6e |
|
|
pojienie |
74b1dd |
for (i = 0; i < cpCount; ++i)
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff2[i] = stroke2->getLengthAtControlPoint(i) - m_actionS2;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
cpCount = stroke1->getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff1.resize(cpCount);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
double diff;
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; i < cpCount; i++) {
|
|
Shinya Kitaoka |
120a6e |
diff = stroke1->getLengthAtControlPoint(i) - m_actionS1;
|
|
Shinya Kitaoka |
120a6e |
m_cpLenDiff1[i] = (s->isSelfLoop() && stroke2 && totalLength - diff < diff)
|
|
Shinya Kitaoka |
120a6e |
? totalLength - diff
|
|
Shinya Kitaoka |
120a6e |
: diff;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//----------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
A split stroke must be reassembled before it is output.
|
|
Toshihiro Shimizu |
890ddd |
In particular, it must be ensured that the merge does not add additional CPS
|
|
Toshihiro Shimizu |
890ddd |
at split points, leaving the output seamless.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Shinya Kitaoka |
120a6e |
TStroke *PumpTool::mergeStrokes(const std::vector<tstroke *=""> &strokes) {</tstroke>
|
|
Shinya Kitaoka |
120a6e |
assert(strokes.size() > 0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TStroke *mergedStroke;
|
|
Shinya Kitaoka |
120a6e |
if (strokes.size() > 1) {
|
|
Shinya Kitaoka |
120a6e |
if (m_errorTol > 0.0) {
|
|
Shinya Kitaoka |
120a6e |
strokes[m_stroke1Idx]->reduceControlPoints(m_errorTol);
|
|
Shinya Kitaoka |
120a6e |
if (m_stroke2Idx >= 0)
|
|
Shinya Kitaoka |
120a6e |
strokes[m_stroke2Idx]->reduceControlPoints(m_errorTol);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// Merge split strokes
|
|
Shinya Kitaoka |
120a6e |
mergedStroke = merge(strokes);
|
|
Shinya Kitaoka |
120a6e |
// mergedStroke->reduceControlPoints(0.4*getPixelSize()); //Originally on
|
|
Shinya Kitaoka |
120a6e |
// the whole result...
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (m_inStroke->isSelfLoop()) {
|
|
Shinya Kitaoka |
120a6e |
int cpCount = mergedStroke->getControlPointCount();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
TThickPoint p1 = mergedStroke->getControlPoint(0);
|
|
Shinya Kitaoka |
120a6e |
TThickPoint p2 = mergedStroke->getControlPoint(cpCount - 1);
|
|
Shinya Kitaoka |
120a6e |
TThickPoint midP = 0.5 * (p1 + p2);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->setControlPoint(0, midP);
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->setControlPoint(cpCount - 1, midP);
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->setSelfLoop(true);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->outlineOptions() = strokes[0]->outlineOptions();
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
mergedStroke = new TStroke(*strokes[0]);
|
|
Shinya Kitaoka |
120a6e |
if (m_errorTol > 0.0) mergedStroke->reduceControlPoints(m_errorTol);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->setStyle(m_strokeStyleId);
|
|
Shinya Kitaoka |
120a6e |
mergedStroke->invalidate();
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return mergedStroke;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
pojienie |
74b1dd |
|
|
pojienie |
74b1dd |
bool PumpTool::getNearestStrokeWithLock(const TPointD &p, double &outW,
|
|
pojienie |
74b1dd |
UINT &strokeIndex, double &dist2,
|
|
pojienie |
74b1dd |
bool onlyInCurrentGroup) {
|
|
pojienie |
74b1dd |
TVectorImageP vi = TImageP(getImage(false));
|
|
pojienie |
74b1dd |
if (!vi) return false;
|
|
pojienie |
74b1dd |
|
|
pojienie |
74b1dd |
if (m_lockedStrokeIndex >= vi->getStrokeCount()) {
|
|
pojienie |
74b1dd |
m_lockedStrokeIndex = -1;
|
|
pojienie |
74b1dd |
}
|
|
pojienie |
74b1dd |
|
|
pojienie |
74b1dd |
if (m_isCtrlPressed && m_lockedStrokeIndex >= 0) {
|
|
pojienie |
74b1dd |
TStroke *stroke = vi->getStroke(m_lockedStrokeIndex);
|
|
pojienie |
74b1dd |
strokeIndex = m_lockedStrokeIndex;
|
|
pojienie |
74b1dd |
return stroke->getNearestW(p, outW, dist2);
|
|
pojienie |
74b1dd |
}
|
|
pojienie |
74b1dd |
|
|
pojienie |
74b1dd |
UINT index;
|
|
pojienie |
74b1dd |
if (vi->getNearestStroke(p, outW, index, dist2, onlyInCurrentGroup)) {
|
|
pojienie |
74b1dd |
m_lockedStrokeIndex = index;
|
|
pojienie |
74b1dd |
strokeIndex = index;
|
|
pojienie |
74b1dd |
return true;
|
|
pojienie |
74b1dd |
}
|
|
pojienie |
74b1dd |
|
|
pojienie |
74b1dd |
return false;
|
|
pojienie |
74b1dd |
}
|