diff --git a/toonz/sources/include/tassistantsimage.h b/toonz/sources/include/tassistantsimage.h index 6848556..2b1c8cc 100644 --- a/toonz/sources/include/tassistantsimage.h +++ b/toonz/sources/include/tassistantsimage.h @@ -34,6 +34,16 @@ public: std::string type; std::vector<TPointD> points; TSmartObjectP handler; + + TPointD& operator[] (int index) { + if (index <= (int)points.size()) points.resize(index + 1); + return points[index]; + } + + const TPointD& operator[] (int index) const { + static const TPointD blank; + return index <= (int)points.size() ? blank : points[index]; + } }; //------------------------------------------------------------------- diff --git a/toonz/sources/include/tgeometry.h b/toonz/sources/include/tgeometry.h index bbcd801..1a16872 100644 --- a/toonz/sources/include/tgeometry.h +++ b/toonz/sources/include/tgeometry.h @@ -17,6 +17,14 @@ #endif //============================================================================= + +inline double logNormalDistribuitionUnscaled(double x, double x0, double w) + { return exp(-0.5*pow(log(x/x0)/w, 2.0))/x; } + +inline double logNormalDistribuition(double x, double x0, double w) + { return logNormalDistribuitionUnscaled(x, x0, w)/(w*sqrt(2.0*M_PI)); } + +//============================================================================= /* * This is an example of how to use the TPointT, the TRectT and the TAffine * classes. diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h new file mode 100644 index 0000000..cf09983 --- /dev/null +++ b/toonz/sources/include/tools/assistant.h @@ -0,0 +1,109 @@ +#pragma once + +#ifndef ASSISTANT_INCLUDED +#define ASSISTANT_INCLUDED + +// TnzTools includes +#include <tools/track.h> + +// TnzLib includes + +// TnzCore includes +#include <tassistantsimage.h> +#include <tsmartpointer.h> +#include <tgeometry.h> + +// std includes +#include <vector> +#include <string> +#include <map> + + +#undef DVAPI +#undef DVVAR +#ifdef TNZTOOLS_EXPORTS +#define DVAPI DV_EXPORT_API +#define DVVAR DV_EXPORT_VAR +#else +#define DVAPI DV_IMPORT_API +#define DVVAR DV_IMPORT_VAR +#endif + + +//============================================================== + +// Forward declarations + +class TToolViewer; +class TAssistant; +class TGuideline; + +typedef TSmartPointerT<TGuideline> TGuidelineP; +typedef TSmartPointerT<TAssistant> TAssistantP; +typedef std::vector<TGuidelineP> TGuidelineList; + +//=================================================================== + +//***************************************************************************************** +// TGuideline definition +//***************************************************************************************** + +class DVAPI TGuideline final : public TSmartObject { +public: + virtual TTrackPoint transformPoint(const TTrackPoint &point) const + { return point; } + + virtual void draw(TToolViewer *viewer, bool active) const + { } + + void draw(TToolViewer *viewer) const + { draw(viewer, false); } + + double calcTrackWeight(const TTrack &track, const TAffine &affine) const; + + static TGuidelineP findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &affine); +}; + + +//***************************************************************************************** +// TAssistant definition +//***************************************************************************************** + +class DVAPI TAssistant final : public TSmartObject { +public: + typedef TAssistant* (*Fabric)(); + typedef std::map<std::string, Fabric> Registry; + + template<typename T> + class Registrator { + public: + typedef T Type; + static TAssistant* fabric() { return new Type(); } + Registrator(const std::string &name) { getRegistry()[name] = fabric; } + }; + + static Registry& getRegistry(); + static TAssistant* create(const std::string &name); + static TAssistantP wrap(TAssistantDesc &desc); + + virtual void assign(TAssistantDesc &desc) + { } + virtual void onMovePoint( + TAssistantDesc &desc, + int index, + const TPointD &position ) { desc[index] = position; } + virtual void getGuidelines( + const TAssistantDesc &desc, + const TPointD &position, + TGuidelineList &outGuidelines ) { } + virtual void draw( + const TAssistantDesc &desc, + TToolViewer *viewer ) { } + virtual void drawEdit( + const TAssistantDesc &desc, + TToolViewer *viewer, + int currentPointIndex ) { } +}; + + +#endif diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index b1c8939..d06bc2d 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -51,6 +51,7 @@ set(HEADERS ../include/tools/modifiers/modifiertest.h ../include/tools/modifiers/modifiertangents.h ../include/tools/modifiers/modifiersegmentation.h + ../include/tools/assistant.h ) set(SOURCES @@ -121,6 +122,7 @@ set(SOURCES modifiertest.cpp modifiertangents.cpp modifiersegmentation.cpp + assistant.cpp ) set(RESOURCES tnztools.qrc) diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp new file mode 100644 index 0000000..44077b7 --- /dev/null +++ b/toonz/sources/tnztools/assistant.cpp @@ -0,0 +1,90 @@ + +#include <tools/assistant.h> + +#include <limits> + + +//************************************************************************ +// TGuideline implementation +//************************************************************************ + +double +TGuideline::calcTrackWeight(const TTrack &track, const TAffine &affine) const { + if (track.empty() < 1) + return std::numeric_limits<double>::infinity(); + + const double snapLenght = 20.0; + const double snapScale = 1.0; + const double maxLenght = 20.0*snapLenght*snapScale; + + double sumWeight = 0.0; + double sumLength = 0.0; + double sumDeviation = 0.0; + + TPointD prev = affine*track[0].position; + for(int i = 0; i < track.size(); ++i) { + const TTrackPoint &tp = track[i]; + TPointD p = affine*tp.position; + double length = tdistance(p, prev); + sumLength += length; + + double midStepLength = sumLength - 0.5*length; + if (midStepLength > TTrack::epsilon) { + double weight = length*logNormalDistribuitionUnscaled(midStepLength, snapLenght, snapScale); + sumWeight += weight; + + TTrackPoint ntp = transformPoint(tp); + double deviation = tdistance(affine*ntp.position, p); + sumDeviation += weight*deviation; + } + prev = p; + } + if (sumWeight < TTrack::epsilon) + return std::numeric_limits<double>::infinity(); + return sumDeviation/sumWeight; +} + +//--------------------------------------------------------------------------------------------------- + +TGuidelineP +TGuideline::findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &affine) { + double bestWeight = 0.0; + TGuidelineP best; + for(TGuidelineList::const_iterator i = guidelines.begin(); i != guidelines.end(); ++i) { + double weight = (*i)->calcTrackWeight(track, affine); + if (!best || weight < bestWeight) + { bestWeight = weight; best = *i; } + } + return best; +} + + +//************************************************************************ +// TAssistant implementation +//************************************************************************ + +TAssistant::Registry& +TAssistant::getRegistry() { + static Registry registry; + return registry; +} + +//--------------------------------------------------------------------------------------------------- + +TAssistant* +TAssistant::create(const std::string &name) { + const Registry ®istry = getRegistry(); + Registry::const_iterator i = registry.find(name); + return i == registry.end() ? NULL : i->second(); +} + +//--------------------------------------------------------------------------------------------------- + +TAssistantP +TAssistant::wrap(TAssistantDesc &desc) { + if (desc.handler) + return dynamic_cast<TAssistant*>(desc.handler.getPointer()); + TAssistantP assistant = create(desc.type); + desc.handler = assistant.getPointer(); + return assistant; +}