diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index db7abdf..368aa99 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -145,6 +145,7 @@ set(SOURCES assistants/replicatoraffine.cpp assistants/replicatorgrid.cpp assistants/replicatormirror.cpp + assistants/replicatorstar.cpp editassistantstool.cpp ) diff --git a/toonz/sources/tnztools/assistants/replicatoraffine.cpp b/toonz/sources/tnztools/assistants/replicatoraffine.cpp index e5e06f1..1318070 100644 --- a/toonz/sources/tnztools/assistants/replicatoraffine.cpp +++ b/toonz/sources/tnztools/assistants/replicatoraffine.cpp @@ -280,6 +280,7 @@ public: void draw(TToolViewer*, bool enabled) const override { double alpha = getDrawingAlpha(enabled); + double gridAlpha = getDrawingGridAlpha(); double pixelSize = sqrt(tglGetPixelSize2()); TPointD c = m_center0.position; @@ -295,8 +296,8 @@ public: TAffine t; for(int i = getCount(); i > 0; --i) { t = aff * t; - drawSegment(t*c, t*a, pixelSize, alpha); - drawSegment(t*c, t*b, pixelSize, alpha); + drawSegment(t*c, t*a, pixelSize, gridAlpha); + drawSegment(t*c, t*b, pixelSize, gridAlpha); } // draw inverted clones @@ -304,8 +305,8 @@ public: aff = aff.inv(); for(int i = getCountInv(); i > 0; --i) { t = aff * t; - drawSegment(t*c, t*a, pixelSize, alpha); - drawSegment(t*c, t*b, pixelSize, alpha); + drawSegment(t*c, t*a, pixelSize, gridAlpha); + drawSegment(t*c, t*b, pixelSize, gridAlpha); } } }; diff --git a/toonz/sources/tnztools/assistants/replicatorgrid.cpp b/toonz/sources/tnztools/assistants/replicatorgrid.cpp index 7e731fb..ef26802 100644 --- a/toonz/sources/tnztools/assistants/replicatorgrid.cpp +++ b/toonz/sources/tnztools/assistants/replicatorgrid.cpp @@ -14,7 +14,7 @@ //***************************************************************************************** class TReplicatorGrid final : public TReplicator { - Q_DECLARE_TR_FUNCTIONS(TReplicatorAffine) + Q_DECLARE_TR_FUNCTIONS(TReplicatorGrid) public: const TStringId m_idFixAngle; const TStringId m_idFixSkew; @@ -232,6 +232,7 @@ public: void draw(TToolViewer*, bool enabled) const override { double alpha = getDrawingAlpha(enabled); + double gridAlpha = getDrawingGridAlpha(); double pixelSize = sqrt(tglGetPixelSize2()); TPointD c = m_center.position; @@ -257,13 +258,13 @@ public: for(int ia = a0; ia < a1; ++ia) { TPointD o = c + da*ia + db*ib; if (ia || ib) { - drawSegment(o, o + da*0.2, pixelSize, alpha); - drawSegment(o, o + db*0.2, pixelSize, alpha); + drawSegment(o, o + da*0.2, pixelSize, gridAlpha); + drawSegment(o, o + db*0.2, pixelSize, gridAlpha); } if (mirrorA && (ib || ia != 1)) - drawSegment(o - da*0.2, o, pixelSize, alpha); + drawSegment(o - da*0.2, o, pixelSize, gridAlpha); if (mirrorB && (ia || ib != 1)) - drawSegment(o - db*0.2, o, pixelSize, alpha); + drawSegment(o - db*0.2, o, pixelSize, gridAlpha); } } }; diff --git a/toonz/sources/tnztools/assistants/replicatormirror.cpp b/toonz/sources/tnztools/assistants/replicatormirror.cpp index 138f41c..3963377 100644 --- a/toonz/sources/tnztools/assistants/replicatormirror.cpp +++ b/toonz/sources/tnztools/assistants/replicatormirror.cpp @@ -15,7 +15,7 @@ //***************************************************************************************** class TReplicatorMirror final : public TReplicator { - Q_DECLARE_TR_FUNCTIONS(TReplicatorAffine) + Q_DECLARE_TR_FUNCTIONS(TReplicatorMirror) public: const TStringId m_idDiscreteAngle; const TStringId m_idPressure; @@ -72,6 +72,7 @@ protected: TPointD fixB() const { TPointD b = m_b.position; + if (getDiscreteAngle()) { TPointD d = b - m_a.position; double l = norm2(d); @@ -83,6 +84,10 @@ protected: b.y = sin(angle)*l + m_a.position.y; } } + + if (areAlmostEqual(b, m_a.position)) + b = m_a.position + TPointD(1, 0); + return b; } @@ -90,8 +95,6 @@ protected: TAffine getAffine(const TAffine &toTool = TAffine()) const { TPointD c = toTool*m_a.position; TPointD x = toTool*fixB() - c; - if (!(norm2(x) > TConsts::epsilon*TConsts::epsilon)) - x = TPointD(1, 0); TPointD y(-x.y, x.x); TAffine t0( x.x, y.x, c.x, diff --git a/toonz/sources/tnztools/assistants/replicatorstar.cpp b/toonz/sources/tnztools/assistants/replicatorstar.cpp new file mode 100644 index 0000000..b4aeb89 --- /dev/null +++ b/toonz/sources/tnztools/assistants/replicatorstar.cpp @@ -0,0 +1,199 @@ + + +// TnzTools includes +#include <tools/replicator.h> +#include <tools/modifiers/modifierclone.h> +#include <tools/assistants/guidelineline.h> + + +// TnzCore includes +#include <tgl.h> + + +//***************************************************************************************** +// TReplicatorStar implementation +//***************************************************************************************** + +class TReplicatorStar final : public TReplicator { + Q_DECLARE_TR_FUNCTIONS(TReplicatorStar) +public: + const TStringId m_idDiscreteAngle; + const TStringId m_idMirror; + const TStringId m_idCount; + +protected: + TAssistantPoint &m_center; + TAssistantPoint &m_a; + +public: + TReplicatorStar(TMetaObject &object): + TReplicator(object), + m_idDiscreteAngle("discreteAngle"), + m_idMirror("mirror"), + m_idCount("count"), + m_center( addPoint("center", TAssistantPoint::CircleCross) ), + m_a ( addPoint("a", TAssistantPoint::Circle, TPointD(80, 0)) ) + { + addProperty( new TBoolProperty(m_idDiscreteAngle.str(), getDiscreteAngle()) ); + addProperty( new TBoolProperty(m_idMirror.str(), getMirror()) ); + addProperty( createCountProperty(m_idCount, getCount(), 2) ); + } + + + static QString getLocalName() + { return tr("Replicator Star"); } + + + void updateTranslation() const override { + TReplicator::updateTranslation(); + setTranslation(m_idDiscreteAngle, tr("Discrete Angle")); + setTranslation(m_idMirror, tr("Mirror")); + setTranslation(m_idCount, tr("Count")); + } + + + inline bool getDiscreteAngle() const + { return data()[m_idDiscreteAngle].getBool(); } + inline bool getMirror() const + { return data()[m_idMirror].getBool(); } + inline int getCount() const + { return (int)data()[m_idCount].getDouble(); } + +protected: + inline void setCount(int x) + { if (getCount() != (double)x) data()[m_idCount].setDouble((double)x); } + + + void onSetDefaults() override { + setCount(6); + TReplicator::onSetDefaults(); + } + + + void onFixData() override { + TReplicator::onFixData(); + setCount( std::max(1, std::min(multiplierSoftLimit - 1, getCount())) ); + } + + + TPointD fixA() const { + TPointD a = m_a.position; + + if (getDiscreteAngle()) { + TPointD d = a - m_center.position; + double l = norm2(d); + if (l > TConsts::epsilon*TConsts::epsilon) { + l = sqrt(l); + int count = getCount(); + if (count > 0) { + double angle = atan2(d.y, d.x); + angle = round(angle*2*count/M_PI)*M_PI/(2*count); + a.x = cos(angle)*l + m_center.position.x; + a.y = sin(angle)*l + m_center.position.y; + } + } + } + + if (areAlmostEqual(a, m_center.position)) + a = m_center.position + TPointD(1, 0); + + return a; + } + + + void onMovePoint(TAssistantPoint &point, const TPointD &position) override { + if (&point == &m_center) + m_a.position += position - m_center.position; + point.position = position; + } + + +public: + int getMultipler() const override + { return getCount() + 1; } + + + void getModifiers( + const TAffine &toTool, + TInputModifier::List &outModifiers ) const override + { + int count = getCount(); + bool mirror = getMirror(); + + TPointD c = toTool*m_center.position; + TPointD x = toTool*fixA() - c; + TPointD y(-x.y, x.x); + + TAffine t1( x.x, y.x, c.x, + x.y, y.y, c.y ); + TAffine t2( x.x, -y.x, c.x, + x.y, -y.y, c.y ); + + TAffine t0 = t1.inv(); + TRotation r(360.0/getCount()); + + TModifierClone *modifier = new TModifierClone(); + for(int i = 0; i < count; ++i) { + if (i) + modifier->transforms.push_back(TTrackTransform(t1*t0)); + if (mirror) { + modifier->transforms.push_back(TTrackTransform(t2*t0)); + t2 *= r; + } + t1 *= r; + } + + outModifiers.push_back(modifier); + } + + + void draw(TToolViewer*, bool enabled) const override { + double alpha = getDrawingAlpha(enabled); + double gridAlpha = getDrawingGridAlpha(); + double pixelSize = sqrt(tglGetPixelSize2()); + + int count = getCount(); + bool mirror = getMirror(); + + TPointD c = m_center.position; + TPointD a = fixA(); + TPointD d = normalize(a - c); + + double spacing = 10*pixelSize; + double l = spacing*count/M_2PI; + + TPointD p0 = c + d*l; + TPointD p1 = p0 + d; + TRotation r(360.0/count); + + TAffine4 modelview, projection; + glGetDoublev(GL_MODELVIEW_MATRIX, modelview.a); + glGetDoublev(GL_PROJECTION_MATRIX, projection.a); + + TAffine matrix = (projection*modelview).get2d(); + TAffine matrixInv = matrix.inv(); + const TRectD oneBox(-1.0, -1.0, 1.0, 1.0); + + for(int i = 0; i < count; ++i) { + TPointD pp0 = matrix*p0; + TPointD pp1 = matrix*p1; + if (TGuidelineLine::truncateRay(oneBox, pp0, pp1)) + drawSegment(matrixInv*pp0, matrixInv*pp1, pixelSize, i ? gridAlpha : alpha); + p0 = r*(p0 - c) + c; + p1 = r*(p1 - c) + c; + } + + TPointD p = TPointD(-d.y, d.x); + drawSegment( (mirror ? a+p*15 : a), a-p*15, pixelSize, alpha ); + + drawSegment(c - d*10, c + d*10, pixelSize, alpha); + drawSegment(c - p*10, c + p*10, pixelSize, alpha); + } +}; + + +//***************************************************************************************** +// Registration +//***************************************************************************************** + +static TAssistantTypeT<TReplicatorStar> replicatorStar("replicatorStar");