From ab0188ea0fb754b36acbcafff515020b8310cf94 Mon Sep 17 00:00:00 2001 From: pojienie Date: Tue, 7 Apr 2020 11:15:00 +0000 Subject: [PATCH 1/2] move interpolation calculation to TInbetween --- toonz/sources/common/tvrender/tinbetween.cpp | 32 +++++++++++++++----- toonz/sources/include/tinbetween.h | 9 ++++++ toonz/sources/toonz/filmstripcommand.cpp | 32 +++++++++++--------- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/toonz/sources/common/tvrender/tinbetween.cpp b/toonz/sources/common/tvrender/tinbetween.cpp index fce82be1..2318b100 100644 --- a/toonz/sources/common/tvrender/tinbetween.cpp +++ b/toonz/sources/common/tvrender/tinbetween.cpp @@ -229,8 +229,8 @@ static void detectCorners(const TStroke *stroke, double minDegree, } } - const double ratioLen = 2.5; - const double ratioAngle = 0.2; + const double ratioLen = 2.5; + const double ratioAngle = 0.2; std::vector>::iterator it = corners.begin(); for (j = 1; j < (int)quadCount1; @@ -241,8 +241,9 @@ static void detectCorners(const TStroke *stroke, double minDegree, continue; } - if (j - 2 >= 0 && (corners.empty() || it == corners.begin() || - j - 1 != (*(it - 1)).first) && + if (j - 2 >= 0 && + (corners.empty() || it == corners.begin() || + j - 1 != (*(it - 1)).first) && j + 1 < (int)quadCount1 && (corners.empty() || it == corners.end() || j + 1 != (*it).first)) { speed1 = stroke->getChunk(j - 2)->getSpeed(1); @@ -255,7 +256,7 @@ static void detectCorners(const TStroke *stroke, double minDegree, if (tan1 * tan2 < 0) { angle = 180 - asin(tcrop(vectorialProduct, -1.0, 1.0)) * M_180_PI; - metaCornerLen = ratioLen * (stroke->getChunk(j - 1)->getLength() + + metaCornerLen = ratioLen * (stroke->getChunk(j - 1)->getLength() + stroke->getChunk(j)->getLength()); partialLen = 0; bool goodAngle = false; @@ -1480,8 +1481,8 @@ TVectorImageP TInbetween::Imp::tween(double t) const { len1 += step1; len2 += step2; } - point2 = subStroke2->getThickPointAtLength(totalLen2); - point2 = TThickPoint(m_transformation[i].m_inverse * + point2 = subStroke2->getThickPointAtLength(totalLen2); + point2 = TThickPoint(m_transformation[i].m_inverse * subStroke2->getThickPointAtLength(totalLen2), point2.thick); finalPoint = subStroke1->getThickPointAtLength(totalLen1) * (1 - t) + @@ -1554,3 +1555,20 @@ void TInbetween::Imp::transferColor(const TVectorImageP &destination) const { TVectorImageP TInbetween::tween(double t) const { return m_imp->tween(t); } //------------------------------------------------------------------- + +double TInbetween::interpolation(double t, enum TweenAlgorithm algorithm) { + // in tutte le interpolazioni : s(0) = 0, s(1) = 1 + switch (algorithm) { + case EaseInInterpolation: // s'(1) = 0 + return t * (2 - t); + case EaseOutInterpolation: // s'(0) = 0 + return t * t; + case EaseInOutInterpolation: // s'(0) = s'(1) = 0 + return t * t * (3 - 2 * t); + case LinearInterpolation: + default: + return t; + } +} + +//------------------------------------------------------------------- diff --git a/toonz/sources/include/tinbetween.h b/toonz/sources/include/tinbetween.h index 123ca7b7..ce89e10d 100644 --- a/toonz/sources/include/tinbetween.h +++ b/toonz/sources/include/tinbetween.h @@ -24,6 +24,15 @@ class DVAPI TInbetween { std::unique_ptr m_imp; public: + enum TweenAlgorithm { + LinearInterpolation, + EaseInInterpolation, + EaseOutInterpolation, + EaseInOutInterpolation + }; + + static double interpolation(double t, enum TweenAlgorithm); + TInbetween(const TVectorImageP firstImage, const TVectorImageP lastImage); virtual ~TInbetween(); diff --git a/toonz/sources/toonz/filmstripcommand.cpp b/toonz/sources/toonz/filmstripcommand.cpp index dc79ceff..c768bab8 100644 --- a/toonz/sources/toonz/filmstripcommand.cpp +++ b/toonz/sources/toonz/filmstripcommand.cpp @@ -2499,25 +2499,27 @@ void FilmstripCmd::inbetweenWithoutUndo( TVectorImageP img1 = sl->getFrame(fid1, false); if (!img0 || !img1) return; + enum TInbetween::TweenAlgorithm algorithm; + switch (interpolation) { + case II_Linear: + algorithm = TInbetween::LinearInterpolation; + break; + case II_EaseIn: + algorithm = TInbetween::EaseInInterpolation; + break; + case II_EaseOut: + algorithm = TInbetween::EaseOutInterpolation; + break; + case II_EaseInOut: + algorithm = TInbetween::EaseInOutInterpolation; + break; + } + TInbetween inbetween(img0, img1); int i; for (i = ia + 1; i < ib; i++) { double t = (double)(i - ia) / (double)(ib - ia); - double s = t; - // in tutte le interpolazioni : s(0) = 0, s(1) = 1 - switch (interpolation) { - case II_Linear: - break; - case II_EaseIn: - s = t * (2 - t); - break; // s'(1) = 0 - case II_EaseOut: - s = t * t; - break; // s'(0) = 0 - case II_EaseInOut: - s = t * t * (3 - 2 * t); - break; // s'(0) = s'(1) = 0 - } + double s = TInbetween::interpolation(t, algorithm); TVectorImageP vi = inbetween.tween(s); sl->setFrame(fids[i], vi); From 4998cfd782f5882e6c9ed9e43843d3d26c5f6245 Mon Sep 17 00:00:00 2001 From: pojienie Date: Tue, 7 Apr 2020 11:25:45 +0000 Subject: [PATCH 2/2] add interpolation in eraser tool --- toonz/sources/tnztools/vectorerasertool.cpp | 55 ++++++++++++++++++--- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/toonz/sources/tnztools/vectorerasertool.cpp b/toonz/sources/tnztools/vectorerasertool.cpp index 738004a5..2155597a 100644 --- a/toonz/sources/tnztools/vectorerasertool.cpp +++ b/toonz/sources/tnztools/vectorerasertool.cpp @@ -40,6 +40,8 @@ using namespace ToolUtils; TEnv::DoubleVar EraseVectorSize("InknpaintEraseVectorSize", 10); TEnv::StringVar EraseVectorType("InknpaintEraseVectorType", "Normal"); +TEnv::StringVar EraseVectorInterpolation("InknpaintEraseVectorInterpolation", + "Linear"); TEnv::IntVar EraseVectorSelective("InknpaintEraseVectorSelective", 0); TEnv::IntVar EraseVectorInvert("InknpaintEraseVectorInvert", 0); TEnv::IntVar EraseVectorRange("InknpaintEraseVectorRange", 0); @@ -56,6 +58,11 @@ namespace { #define POLYLINE_ERASE L"Polyline" #define SEGMENT_ERASE L"Segment" +#define LINEAR_INTERPOLATION L"Linear" +#define EASE_IN_INTERPOLATION L"Ease In" +#define EASE_OUT_INTERPOLATION L"Ease Out" +#define EASE_IN_OUT_INTERPOLATION L"Ease In/Out" + //----------------------------------------------------------------------------- const double minDistance2 = 16.0; // 4 pixel @@ -294,6 +301,7 @@ private: TPropertyGroup m_prop; TEnumProperty m_eraseType; + TEnumProperty m_interpolation; TDoubleProperty m_toolSize; TBoolProperty m_selective; TBoolProperty m_invertOption; @@ -366,7 +374,8 @@ private: EraserTool::EraserTool() : TTool("T_Eraser") - , m_eraseType("Type:") // "W_ToolOptions_Erasetype" + , m_eraseType("Type:") // "W_ToolOptions_Erasetype" + , m_interpolation("interpolation:") , m_toolSize("Size:", 1, 1000, 10) // "W_ToolOptions_EraserToolSize" , m_selective("Selective", false) // "W_ToolOptions_Selective" , m_invertOption("Invert", false) // "W_ToolOptions_Invert" @@ -392,11 +401,17 @@ EraserTool::EraserTool() m_prop.bind(m_selective); m_prop.bind(m_invertOption); m_prop.bind(m_multi); + m_prop.bind(m_interpolation); + m_interpolation.addValue(LINEAR_INTERPOLATION); + m_interpolation.addValue(EASE_IN_INTERPOLATION); + m_interpolation.addValue(EASE_OUT_INTERPOLATION); + m_interpolation.addValue(EASE_IN_OUT_INTERPOLATION); m_selective.setId("Selective"); m_invertOption.setId("Invert"); m_multi.setId("FrameRange"); m_eraseType.setId("Type"); + m_interpolation.setId("Interpolation"); } //----------------------------------------------------------------------------- @@ -420,6 +435,12 @@ void EraserTool::updateTranslation() { m_eraseType.setItemUIName(FREEHAND_ERASE, tr("Freehand")); m_eraseType.setItemUIName(POLYLINE_ERASE, tr("Polyline")); m_eraseType.setItemUIName(SEGMENT_ERASE, tr("Segment")); + + m_interpolation.setQStringName(tr("")); + m_interpolation.setItemUIName(LINEAR_INTERPOLATION, tr("Linear")); + m_interpolation.setItemUIName(EASE_IN_INTERPOLATION, tr("Ease In")); + m_interpolation.setItemUIName(EASE_OUT_INTERPOLATION, tr("Ease Out")); + m_interpolation.setItemUIName(EASE_IN_OUT_INTERPOLATION, tr("Ease In/Out")); } //----------------------------------------------------------------------------- @@ -886,6 +907,15 @@ void EraserTool::multiEraseRect(TFrameId firstFrameId, TFrameId lastFrameId, int m = fids.size(); assert(m > 0); + enum TInbetween::TweenAlgorithm algorithm = TInbetween::LinearInterpolation; + if (m_interpolation.getValue() == EASE_IN_INTERPOLATION) { + algorithm = TInbetween::EaseInInterpolation; + } else if (m_interpolation.getValue() == EASE_OUT_INTERPOLATION) { + algorithm = TInbetween::EaseOutInterpolation; + } else if (m_interpolation.getValue() == EASE_IN_OUT_INTERPOLATION) { + algorithm = TInbetween::EaseInOutInterpolation; + } + TUndoManager::manager()->beginBlock(); for (int i = 0; i < m; ++i) { TFrameId fid = fids[i]; @@ -893,6 +923,7 @@ void EraserTool::multiEraseRect(TFrameId firstFrameId, TFrameId lastFrameId, TVectorImageP img = (TVectorImageP)m_level->getFrame(fid, true); assert(img); double t = m > 1 ? (double)i / (double)(m - 1) : 0.5; + t = TInbetween::interpolation(t, algorithm); TRectD rect = interpolateRect(firstRect, lastRect, t); // m_level->setFrame(fid, img); //necessario: se la getFrame ha scompattato // una img compressa, senza setFrame le modifiche sulla img fatte qui @@ -1097,11 +1128,12 @@ void EraserTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { //---------------------------------------------------------------------- bool EraserTool::onPropertyChanged(std::string propertyName) { - EraseVectorType = ::to_string(m_eraseType.getValue()); - EraseVectorSize = m_toolSize.getValue(); - EraseVectorSelective = m_selective.getValue(); - EraseVectorInvert = m_invertOption.getValue(); - EraseVectorRange = m_multi.getValue(); + EraseVectorType = ::to_string(m_eraseType.getValue()); + EraseVectorInterpolation = ::to_string(m_interpolation.getValue()); + EraseVectorSize = m_toolSize.getValue(); + EraseVectorSelective = m_selective.getValue(); + EraseVectorInvert = m_invertOption.getValue(); + EraseVectorRange = m_multi.getValue(); double x = m_toolSize.getValue(); @@ -1125,6 +1157,7 @@ void EraserTool::onEnter() { if (m_firstTime) { m_toolSize.setValue(EraseVectorSize); m_eraseType.setValue(::to_wstring(EraseVectorType.getValue())); + m_interpolation.setValue(::to_wstring(EraseVectorInterpolation.getValue())); m_selective.setValue(EraseVectorSelective ? 1 : 0); m_invertOption.setValue(EraseVectorInvert ? 1 : 0); m_multi.setValue(EraseVectorRange ? 1 : 0); @@ -1537,11 +1570,21 @@ void EraserTool::doMultiErase(TFrameId &firstFrameId, TFrameId &lastFrameId, column->getLevelRange(currentRow, startRowInXSheet, endRowInXSheet); } + enum TInbetween::TweenAlgorithm algorithm = TInbetween::LinearInterpolation; + if (m_interpolation.getValue() == EASE_IN_INTERPOLATION) { + algorithm = TInbetween::EaseInInterpolation; + } else if (m_interpolation.getValue() == EASE_OUT_INTERPOLATION) { + algorithm = TInbetween::EaseOutInterpolation; + } else if (m_interpolation.getValue() == EASE_IN_OUT_INTERPOLATION) { + algorithm = TInbetween::EaseInOutInterpolation; + } + TUndoManager::manager()->beginBlock(); for (int i = 0; i < m; ++i) { TFrameId fid = fids[i]; assert(firstFrameId <= fid && fid <= lastFrameId); double t = m > 1 ? (double)i / (double)(m - 1) : 0.5; + t = TInbetween::interpolation(t, algorithm); // Setto il fid come corrente per notificare il cambiamento dell'immagine if (app) { if (app->getCurrentFrame()->isEditingScene())