diff --git a/toonz/sources/tnztools/modifiers/modifiersimplify.cpp b/toonz/sources/tnztools/modifiers/modifiersimplify.cpp index 85b66b3..df889c0 100644 --- a/toonz/sources/tnztools/modifiers/modifiersimplify.cpp +++ b/toonz/sources/tnztools/modifiers/modifiersimplify.cpp @@ -55,6 +55,7 @@ TModifierSimplify::modifyTrack( const TTrackPoint &p1 = track[i]; if (!subTrack.empty() && tdistance2(p1.position, p0.position) < step2) { if (p0.pressure < p1.pressure) p0.pressure = p1.pressure; + if (i == track.size() - 1) p0.position = p1.position; p0.tilt = p1.tilt; p0.time = p1.time; p0.final = p1.final; @@ -71,8 +72,9 @@ TModifierSimplify::modifyTrack( if (track.fixedFinished()) subTrack.fix_all(); else + if (track.fixedSize()) subTrack.fix_to( - subTrack.floorIndex( subTrack.indexByOriginalIndex(track.fixedSize()) )); + subTrack.floorIndex( subTrack.indexByOriginalIndex(track.fixedSize()-1) )); track.resetChanges(); } diff --git a/toonz/sources/tnztools/modifiers/modifiersmooth.cpp b/toonz/sources/tnztools/modifiers/modifiersmooth.cpp index 449623f..953ea68 100644 --- a/toonz/sources/tnztools/modifiers/modifiersmooth.cpp +++ b/toonz/sources/tnztools/modifiers/modifiersmooth.cpp @@ -19,7 +19,7 @@ TModifierSmooth::Modifier::Modifier(TTrackHandler &handler, int radius): TTrackPoint TModifierSmooth::Modifier::calcPoint(double originalIndex) { return smoothedTrack - ? smoothedTrack->interpolateLinear(originalIndex) + ? smoothedTrack->interpolateLinear(originalIndex + radius) : TTrackModifier::calcPoint(originalIndex); } diff --git a/toonz/sources/tnztools/modifiers/modifiertangents.cpp b/toonz/sources/tnztools/modifiers/modifiertangents.cpp index c7f11e0..60a8704 100644 --- a/toonz/sources/tnztools/modifiers/modifiertangents.cpp +++ b/toonz/sources/tnztools/modifiers/modifiertangents.cpp @@ -100,8 +100,11 @@ TModifierTangents::modifyTrack( if (start > 1) --start; if (start < 0) start = 0; subTrack.truncate(start); - for(int i = start; i < track.size(); ++i) - subTrack.push_back(track[i], false); + for(int i = start; i < track.size(); ++i) { + TTrackPoint p = track[i]; + p.originalIndex = i; + subTrack.push_back(p, false); + } // update tangents modifier->tangents.resize(start); diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.cpp b/toonz/sources/tnztools/toonzvectorbrushtool.cpp index bb58efc..cc70f9c 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.cpp +++ b/toonz/sources/tnztools/toonzvectorbrushtool.cpp @@ -509,6 +509,8 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType) , m_rasterTrack(0) , m_styleId(0) , m_targetType(targetType) + , m_snapped() + , m_snappedSelf() , m_modifiedRegion() , m_bluredBrush(0) , m_active(false) @@ -963,6 +965,12 @@ void ToonzVectorBrushTool::inputPaintTracks(const TTrackList &tracks) { --track.pointsAdded; } + bool loop = m_snappedSelf + && track.fixedFinished() + && !track.empty() + && areAlmostEqual(track.front().position, track.back().position); + m_track.setLoop(loop); + invalidateRect += m_track.getLastModifiedRegion(); TPointD halfThick(m_maxThick * 0.5, m_maxThick * 0.5); @@ -1040,15 +1048,24 @@ void ToonzVectorBrushTool::handleMouseEvent(MouseEventType type, if (control != m_inputmanager.state.isKeyPressed(TKey::control)) m_inputmanager.keyEvent(control, TKey::control, t, nullptr); + TPointD snappedPos = pos; + bool pickerMode = getViewer() && getViewer()->getGuidedStrokePickerMode(); + bool snapEnabled = !pickerMode && (alt != m_snap.getValue()); + snap(pos, snapEnabled, m_active); + if (m_snapped) + snappedPos = m_snapPoint; + if (m_snappedSelf && type == ME_UP) + snappedPos = m_snapPointSelf; + if (type == ME_MOVE) { qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - THoverList hovers(1, pos); + THoverList hovers(1, snappedPos); m_inputmanager.hoverEvent(hovers); } else - if (getViewer() && getViewer()->getGuidedStrokePickerMode()) { - if (type == ME_DOWN) getViewer()->doPickGuideStroke(pos); + if (pickerMode) { + if (type == ME_DOWN) getViewer()->doPickGuideStroke(snappedPos); } else { - m_inputmanager.trackEvent(e.isTablet(), 0, pos, + m_inputmanager.trackEvent(e.isTablet(), 0, snappedPos, &e.m_pressure, nullptr, type == ME_UP, t); m_inputmanager.processTracks(); @@ -1305,117 +1322,108 @@ void ToonzVectorBrushTool::flushTrackPoint() { //------------------------------------------------------------------------------------------------------------- -void ToonzVectorBrushTool::checkStrokeSnapping(bool beforeMousePress, - bool invertCheck) { - if (Preferences::instance()->getVectorSnappingTarget() == 1) - return; // 0 - strokes, 1 - guides, 2 - all +void ToonzVectorBrushTool::snap(const TPointD &pos, bool snapEnabled, bool withSelfSnap) { + bool oldSnapped = m_snapped; + bool oldSnappedSelf = m_snappedSelf; + TPointD oldPoint = m_snapPoint; + TPointD oldPointSelf = m_snapPointSelf; - m_dragDraw = true; + m_snapped = m_snappedSelf = false; - if (invertCheck == m_snap.getValue()) - return; + if (snapEnabled) { // snapping is active + double minDistance2 = m_minDistance2; - TVectorImageP vi(getImage(false)); - if (!vi) - return; - - TPointD point; - bool found = false; - double minDistance2 = m_minDistance2; - int count = vi->getStrokeCount(); - for(int i = 0; i < count; ++i) { - double w, d2; - TStroke *stroke = vi->getStroke(i); - if (!stroke->getNearestW(m_mousePos, w, d2) || d2 >= minDistance2) - continue; - minDistance2 = d2; - w = w > 0.001 ? (w < 0.999 ? w : 1.0) : 0.0; - point = stroke->getPoint(w); - found = true; - } - - if (beforeMousePress) { - if (found) { - m_firstSnapPoint = point; - m_foundFirstSnap = true; - } - return; - } - - if (!found) { - // compare to first point of current stroke - TPointD p = m_track.getFirstPoint(); - double d2 = tdistance2(m_mousePos, p); - if (!(d2 < m_minDistance2)) - return; - point = p; - minDistance2 = d2; - m_snapSelf = true; - } - - m_lastSnapPoint = point; - m_foundLastSnap = true; - if (minDistance2 < 2.0) - m_dragDraw = false; -} - -//------------------------------------------------------------------------------------------------------------- + // 0 - strokes, 1 - guides, 2 - all + int target = Preferences::instance()->getVectorSnappingTarget(); + + // snap to guides + if (target != 0) { + if (TToolViewer *viewer = getViewer()) { + // find nearest vertical guide + int cnt = viewer->getVGuideCount(); + for(int i = 0; i < cnt; ++i) { + double guide = viewer->getVGuide(i); + double d2 = guide - pos.y; + d2 *= d2; // we work with square of the distance + if (d2 < minDistance2) { + m_snapped = true; + m_snapPoint.x = pos.x; + m_snapPoint.y = guide; + minDistance2 = d2; + } + } -void ToonzVectorBrushTool::checkGuideSnapping(bool beforeMousePress, - bool invertCheck) { - if (Preferences::instance()->getVectorSnappingTarget() == 0) - return; // 0 - strokes, 1 - guides, 2 - all - if (invertCheck == m_snap.getValue()) - return; - TToolViewer *viewer = getViewer(); - if (!viewer) - return; + // find nearest horizontal guide + cnt = viewer->getHGuideCount(); + for(int i = 0; i < cnt; ++i) { + double guide = viewer->getHGuide(i); + double d2 = guide - pos.x; + d2 *= d2; // we work with square of the distance + if (d2 < minDistance2) { + m_snapped = true; + m_snapPoint.x = guide; + m_snapPoint.y = pos.y; + minDistance2 = d2; + } + } + } + } - // choose snaping fields to work - bool &m_foundSnap = beforeMousePress ? m_foundFirstSnap : m_foundLastSnap; - TPointD &m_snapPoint = beforeMousePress ? m_firstSnapPoint : m_lastSnapPoint; + // snap to strokes + if (target != 1) { + if (TVectorImageP vi = getImage(false)) { + int count = vi->getStrokeCount(); + for(int i = 0; i < count; ++i) { + double w, d2; + TStroke *stroke = vi->getStroke(i); + if (!stroke->getNearestW(pos, w, d2) || d2 >= minDistance2) + continue; + minDistance2 = d2; + w = w > 0.001 ? (w < 0.999 ? w : 1.0) : 0.0; + m_snapped = true; + m_snapPoint = stroke->getPoint(w); + } + } + + // finally snap to first point of track (self snap) + if (withSelfSnap && !m_track.isEmpty()) { + TPointD p = m_track.getFirstPoint(); + double d2 = tdistance2(pos, p); + if (d2 < m_minDistance2) { + m_snappedSelf = true; + m_snapPointSelf = p; + } + } + } + } // snapping is active - // init min distance, with using snapPoint found by checkStrokeSnapping - double minDistance2 = m_minDistance2; - if (m_foundSnap) { - double d2 = tdistance2(m_snapPoint, m_mousePos); - if (d2 < minDistance2) minDistance2 = d2; + // invalidate rect + TRectD invalidateRect; + double radius = 8.0*m_pixelSize; + TPointD halfSize(radius, radius); + + if ( oldSnapped != m_snapped + || !areAlmostEqual(oldPoint, m_snapPoint) ) + { + if (oldSnapped) invalidateRect += TRectD(oldPoint - halfSize, oldPoint + halfSize); + if (m_snapped) invalidateRect += TRectD(m_snapPoint - halfSize, m_snapPoint + halfSize); } - // find nearest vertical guide - int cnt = viewer->getVGuideCount(); - for(int i = 0; i < cnt; ++i) { - double guide = viewer->getVGuide(i); - double d2 = guide - m_mousePos.y; - d2 *= d2; // we work with square of the distance - if (d2 < minDistance2) { - m_foundSnap = true; - m_snapPoint.x = m_mousePos.x; - m_snapPoint.y = guide; - m_snapSelf = false; - minDistance2 = d2; - } - } - - // find nearest horizontal guide - cnt = viewer->getHGuideCount(); - for(int i = 0; i < cnt; ++i) { - double guide = viewer->getHGuide(i); - double d2 = guide - m_mousePos.x; - d2 *= d2; // we work with square of the distance - if (d2 < minDistance2) { - m_foundSnap = true; - m_snapPoint.x = guide; - m_snapPoint.y = m_mousePos.y; - m_snapSelf = false; - minDistance2 = d2; - } + if ( oldSnappedSelf != m_snappedSelf + || !areAlmostEqual(oldPointSelf, m_snapPointSelf) ) + { + if (oldSnappedSelf) invalidateRect += TRectD(oldPointSelf - halfSize, oldPointSelf + halfSize); + if (m_snappedSelf) invalidateRect += TRectD(m_snapPointSelf - halfSize, m_snapPointSelf + halfSize); } + + if (!invalidateRect.isEmpty()) + invalidate(invalidateRect); } //------------------------------------------------------------------------------------------------------------- void ToonzVectorBrushTool::draw() { + m_pixelSize = getPixelSize(); m_inputmanager.draw(); /*--ショートカットでのツール切り替え時に赤点が描かれるのを防止する--*/ @@ -1423,29 +1431,19 @@ void ToonzVectorBrushTool::draw() { !Preferences::instance()->getShow0ThickLines()) return; - TImageP img = getImage(false, 1); - - // Draw track + // draw track tglColor(m_isPrompting ? TPixel32::Green : m_currentColor); m_track.drawAllFragments(); - - m_pixelSize = getPixelSize(); - // snapping - TVectorImageP vi = img; - if (m_snap.getValue() != m_altPressed) { - double thick = 6.0 * m_pixelSize; - if (m_foundFirstSnap) { - tglColor(TPixelD(0.1, 0.9, 0.1)); - tglDrawCircle(m_firstSnapPoint, thick); - } - - TThickPoint point2; - - if (m_foundLastSnap) { - tglColor(TPixelD(0.1, 0.9, 0.1)); - tglDrawCircle(m_lastSnapPoint, thick); - } + // draw snapping + double snapMarkRadius = 6.0 * m_pixelSize; + if (m_snapped) { + tglColor(TPixelD(0.1, 0.9, 0.1)); + tglDrawCircle(m_snapPoint, snapMarkRadius); + } + if (m_snappedSelf) { + tglColor(TPixelD(0.9, 0.9, 0.1)); + tglDrawCircle(m_snapPointSelf, snapMarkRadius); } // frame range diff --git a/toonz/sources/tnztools/toonzvectorbrushtool.h b/toonz/sources/tnztools/toonzvectorbrushtool.h index b43d5b1..6b64f7a 100644 --- a/toonz/sources/tnztools/toonzvectorbrushtool.h +++ b/toonz/sources/tnztools/toonzvectorbrushtool.h @@ -156,14 +156,14 @@ public: bool autoGroup = false, bool autoFill = false, bool drawFirstStroke = true, bool drawLastStroke = true, bool withUndo = true); - void checkGuideSnapping(bool beforeMousePress, bool invertCheck); - void checkStrokeSnapping(bool beforeMousePress, bool invertCheck); bool doGuidedAutoInbetween(TFrameId cFid, const TVectorImageP &cvi, TStroke *cStroke, bool breakAngles, bool autoGroup = false, bool autoFill = false, bool drawStroke = true); -private: +protected: + void snap(const TPointD &pos, bool snapEnabled, bool withSelfSnap = false); + enum MouseEventType { ME_DOWN, ME_DRAG, ME_UP, ME_MOVE }; void handleMouseEvent(MouseEventType type, const TPointD &pos, const TMouseEvent &e); @@ -211,6 +211,12 @@ protected: int m_col, m_firstFrame, m_veryFirstFrame, m_veryFirstCol, m_targetType; double m_pixelSize, m_currThickness, m_minDistance2; + + bool m_snapped; // bwtodo: init + bool m_snappedSelf; + TPointD m_snapPoint; + TPointD m_snapPointSelf; + bool m_foundFirstSnap = false, m_foundLastSnap = false, m_dragDraw = true, m_altPressed = false, m_snapSelf = false; TRectD m_modifiedRegion;