From 9cf8be95e8b2ec8650670c1b7be2e6bb131c5c4d Mon Sep 17 00:00:00 2001 From: Ivan Mahonin <bh@icystar.com> Date: May 01 2023 07:52:44 +0000 Subject: #assistants: TModifierAssistants --- diff --git a/toonz/sources/common/tmetaimage/tmetaimage.cpp b/toonz/sources/common/tmetaimage/tmetaimage.cpp index 0c762b6..8a0c5b4 100644 --- a/toonz/sources/common/tmetaimage/tmetaimage.cpp +++ b/toonz/sources/common/tmetaimage/tmetaimage.cpp @@ -39,7 +39,7 @@ TMetaObject::setType(const TStringId &name) { void TMetaObject::onVariantChanged(const TVariant &value) - { if (m_handler) m_handler->onDataChanged(value); } + { if (m_handler) m_handler->dataChanged(value); } //--------------------------------------------------------- diff --git a/toonz/sources/common/tvariant.cpp b/toonz/sources/common/tvariant.cpp index 2559103..2716709 100644 --- a/toonz/sources/common/tvariant.cpp +++ b/toonz/sources/common/tvariant.cpp @@ -123,7 +123,7 @@ const TVariant& TVariant::byPath(const TVariantPath &path, int begin, int end) const { if ((int)path.size() <= begin || begin >= end) return *this; if (isNone()) return blank(); - return byPath(path[begin]).byPath(path, begin + 1, end); + return (*this)[path[begin]].byPath(path, begin + 1, end); } //--------------------------------------------------------- @@ -131,29 +131,41 @@ TVariant::byPath(const TVariantPath &path, int begin, int end) const { TVariant& TVariant::byPath(const TVariantPath &path, int begin, int end) { if ((int)path.size() <= begin || begin >= end) return *this; - return byPath(path[begin]).byPath(path, begin + 1, end); + return (*this)[path[begin]].byPath(path, begin + 1, end); } //--------------------------------------------------------- int -TVariant::getPathSize() const { - const TVariant *a = this->m_parent; +TVariant::getParentPathSize(const TVariant &parent) const { int ac = 0; - while(a) a = a->m_parent, ++ac; - return ac; + for(const TVariant *a = this; a; a = a->parent(), ++ac) + if (a == &parent) return ac; + return -1; } //--------------------------------------------------------- -void -TVariant::getParentPath(TVariantPath &outPath) const { - if (m_parent) { - m_parent->getParentPath(outPath); - outPath.push_back(parentPathEntry()); - } else { - outPath.clear(); - } +bool +TVariant::getParentPath(TVariantPath &outPath, const TVariant &parent) const { + if (!m_parent) + { outPath.clear(); return false; } + if (m_parent == this) + { outPath.clear(); return true; } + if (m_parent->getParentPath(outPath)) + { outPath.push_back(parentPathEntry()); return true; } + return false; +} + +//--------------------------------------------------------- + +bool +TVariant::getChildPathEntry(const TVariant &child, TVariantPathEntry &outEntry) const { + for(const TVariant *a = &child; a->parent(); a = a->parent()) + if (a->parent() == this) + { outEntry = a->parentPathEntry(); return true; } + outEntry = TVariantPathEntry(); + return false; } //--------------------------------------------------------- diff --git a/toonz/sources/include/tmetaimage.h b/toonz/sources/include/tmetaimage.h index 8504441..75a876e 100644 --- a/toonz/sources/include/tmetaimage.h +++ b/toonz/sources/include/tmetaimage.h @@ -30,7 +30,6 @@ class TMetaObject; class TMetaObjectHandler; typedef TSmartPointerT<TMetaObject> TMetaObjectP; typedef TSmartRefT<TMetaObject> TMetaObjectR; -typedef std::vector<TMetaObjectP> TMetaObjectList; typedef std::vector<TMetaObjectR> TMetaObjectRefList; //------------------------------------------------------------------- @@ -98,6 +97,7 @@ public: class DVAPI TMetaObjectHandler { private: TMetaObject &m_object; + TAtomicVar m_fixindData; public: TMetaObjectHandler(TMetaObject &object): @@ -113,8 +113,19 @@ public: inline TVariant& data() { return object().data(); } +protected: virtual void onDataChanged(const TVariant &value) { } - virtual void fixData() { } + virtual void onFixData() { } + +public: + void dataChanged(const TVariant &value) + { if (m_fixindData != 0) onFixData(); } + + void fixData() { + ++m_fixindData; + if (m_fixindData == 1) onFixData(); + --m_fixindData; + } }; //------------------------------------------------------------------- diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h index a6b7192..625e66f 100644 --- a/toonz/sources/include/tools/assistant.h +++ b/toonz/sources/include/tools/assistant.h @@ -36,10 +36,12 @@ class TToolViewer; class TAssistant; +class TAssistantPoint; class TGuideline; typedef TSmartPointerT<TGuideline> TGuidelineP; typedef std::vector<TGuidelineP> TGuidelineList; +typedef std::vector<TAssistantPoint> TAssistantPointList; //=================================================================== @@ -51,28 +53,89 @@ class DVAPI TGuideline final : public TSmartObject { public: virtual TTrackPoint transformPoint(const TTrackPoint &point) const { return point; } - virtual void draw(TToolViewer *viewer, bool active) const + virtual void draw(bool active) const { } - void draw(TToolViewer *viewer) const - { draw(viewer, false); } + void draw() const + { draw(false); } - double calcTrackWeight(const TTrack &track, const TAffine &affine) const; - static TGuidelineP findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &affine); + double calcTrackWeight(const TTrack &track, const TAffine &toScreen, bool &outLongEnough) const; + static TGuidelineP findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &toScreen, bool &outLongEnough); }; //***************************************************************************************** +// TAssistantPoint definition +//***************************************************************************************** + +class DVAPI TAssistantPoint { +public: + enum Type { + Circle, + CircleFill, + CircleCross + }; + + Type type; + TPointD position; + bool selected; + + inline explicit TAssistantPoint(Type type = Circle, const TPointD &position = TPointD()): + type(Circle), position(position), selected() { } +}; + +//***************************************************************************************** // TAssistant definition //***************************************************************************************** class DVAPI TAssistant final : public TMetaObjectHandler { +protected: + const TStringId m_idPoints; + const TStringId m_idX; + const TStringId m_idY; + + TAssistantPointList m_points; + public: - // TODO: handle data changes + TAssistant(TMetaObject &object); + + static const TPointD& blank(); + + inline const TAssistantPointList& points() const + { return m_points; } + inline const int pointsCount() const + { return (int)m_points.size(); } + + void fixPoints(int index, const TPointD &position); + void movePoint(int index, const TPointD &position); + void setPointSelection(int index, bool selected); + + inline void selectPoint(int index) + { setPointSelection(index, true); } + inline void deselectPoint(int index) + { setPointSelection(index, false); } + inline void selectAll() + { for(int i = 0; i < pointsCount(); ++i) setPointSelection(i, false); } + inline void deselectAll() + { for(int i = 0; i < pointsCount(); ++i) setPointSelection(i, false); } + +protected: + //! called when part of variant data changed + void onDataChanged(const TVariant &value) override; + //! load object data from variant + virtual void onAllDataChanged(); + //! fix positions of all points + virtual void onFixPoints(); + //! try to move point + virtual void onMovePoint(int index, const TPointD &position); + //! save object data to variant + virtual void onFixData(); + + void drawPoint(const TAssistantPoint &point, double pixelSize) const; - virtual void getGuidelines(const TPointD &position, TGuidelineList &outGuidelines) { } - virtual void draw(TToolViewer *viewer) { } - virtual void drawEdit(TToolViewer *viewer, int currentPointIndex) { } +public: + virtual void getGuidelines(const TPointD &position, const TAffine &toTool, TGuidelineList &outGuidelines) const; + virtual void draw(TToolViewer *viewer) const; + virtual void drawEdit(TToolViewer *viewer) const; }; - #endif diff --git a/toonz/sources/include/tools/inputmanager.h b/toonz/sources/include/tools/inputmanager.h index 4696042..5b6d677 100644 --- a/toonz/sources/include/tools/inputmanager.h +++ b/toonz/sources/include/tools/inputmanager.h @@ -10,6 +10,7 @@ // TnzCore includes #include <tcommon.h> +#include <tgeometry.h> #include <tsmartpointer.h> // Qt includes @@ -36,6 +37,7 @@ // Forward declarations +class TTool; class TInputModifier; class TInputManager; @@ -178,8 +180,10 @@ public: virtual TRectD calcDrawBoundsTrack(const TTrack &track) { return TRectD(); } virtual TRectD calcDrawBounds(const TTrackList &tracks, const THoverList &hovers); - virtual void drawHover(const TPointD &hover) { } virtual void drawTrack(const TTrack &track) { } + virtual void drawHover(const TPointD &hover) { } + virtual void drawTracks(const TTrackList &tracks); + virtual void drawHovers(const THoverList &hovers); virtual void draw(const TTrackList &tracks, const THoverList &hovers); virtual void deactivate() { } @@ -240,6 +244,9 @@ public: virtual void inputPaintPop(int count) { } virtual void inputInvalidateRect(const TRectD &bounds) { } + + virtual TAffine toWorld() { return TAffine(); }; + virtual TTool* getTool() { return nullptr; }; }; diff --git a/toonz/sources/include/tools/modifiers/modifierassistants.h b/toonz/sources/include/tools/modifiers/modifierassistants.h new file mode 100644 index 0000000..e0f8a76 --- /dev/null +++ b/toonz/sources/include/tools/modifiers/modifierassistants.h @@ -0,0 +1,57 @@ +#pragma once + +#ifndef MODIFIERASSISTANTS_INCLUDED +#define MODIFIERASSISTANTS_INCLUDED + +// TnzTools includes +#include <tools/assistant.h> +#include <tools/inputmanager.h> + +#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 + + +//=================================================================== + +//***************************************************************************************** +// TModifierAssistants definition +//***************************************************************************************** + +class TModifierAssistants: public TInputModifier { +public: + class Modifier: public TTrackModifier { + public: + bool initialized; + TInputSavePoint::Holder savePoint; + TGuidelineList guidelines; + + Modifier(TTrackHandler &handler); + TTrackPoint calcPoint(double originalIndex) override; + }; + +public: + const double sensitiveLength; + + TModifierAssistants(); + + void findGuidelines( + const TPointD &position, + TGuidelineList &outGuidelines ) const; + + void modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) override; + void drawHover(const TPointD &hover) override; + void drawTrack(const TTrack &track) override; +}; + + +#endif diff --git a/toonz/sources/include/tvariant.h b/toonz/sources/include/tvariant.h index 4934276..224e083 100644 --- a/toonz/sources/include/tvariant.h +++ b/toonz/sources/include/tvariant.h @@ -68,6 +68,11 @@ public: class DVAPI TVariantPath: public std::vector<TVariantPathEntry> { public: + inline TVariantPath& append(const TVariantPathEntry &x) + { push_back(x); return *this; } + inline TVariantPath& append(const TVariantPath &x) + { insert(end(), x.begin(), x.end()); return *this; } + inline bool isSubPathOf(const TVariantPath &other) const { return compare(*this, 0, other, 0, (int)size()); } inline bool isBasePathOf(const TVariantPath &other) const @@ -289,12 +294,12 @@ public: // path methods const TVariant& byPath(const TVariantPath &path, int begin, int end) const; TVariant& byPath(const TVariantPath &path, int begin, int end); - inline const TVariant& byPath(const TVariantPathEntry &entry) const { + inline const TVariant& operator[] (const TVariantPathEntry &entry) const { return entry.isIndex() ? (m_type == List ? (*this)[entry.index()] : blank()) : (m_type == Map ? (*this)[entry.field()] : blank()); } - inline TVariant& byPath(const TVariantPathEntry &entry) + inline TVariant& operator[] (const TVariantPathEntry &entry) { return entry.isIndex() ? (*this)[entry.index()] : (*this)[entry.field()]; } inline const TVariant& byPath(const TVariantPath &path, int begin = 0) const { return byPath(path, begin, (int)path.size()); } @@ -325,15 +330,23 @@ public: inline bool isRoot() const { return this == m_root; } - int getPathSize() const; - void getParentPath(TVariantPath &outPath) const; + int getParentPathSize(const TVariant &parent) const; + bool getParentPath(TVariantPath &outPath, const TVariant &parent) const; inline TVariantPathEntry parentPathEntry() const { return !m_parent ? TVariantPathEntry() : m_parent->m_type == Map ? TVariantPathEntry(m_parentField) : TVariantPathEntry( this - &m_parent->m_list.front() ); } - inline TVariantPath getParentPath() const - { TVariantPath path; getParentPath(path); return path; } + inline int getParentPathSize() const + { return getParentPathSize(*m_root); } + inline bool getParentPath(TVariantPath &outPath) const + { return getParentPath(outPath, *m_root); } + + inline int getChildPathSize(const TVariant &child) const + { return child.getParentPathSize(*this); } + inline bool getChildPath(TVariantPath &outPath, const TVariant &child) const + { return child.getParentPath(outPath, *this); } + bool getChildPathEntry(const TVariant &child, TVariantPathEntry &outEntry) const; bool isChildOf(const TVariant &other) const; bool isChildOrEqual(const TVariant &other) const; diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index d06bc2d..b272a75 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -48,10 +48,11 @@ set(HEADERS ../include/tools/inputstate.h ../include/tools/track.h ../include/tools/inputmanager.h + ../include/tools/assistant.h ../include/tools/modifiers/modifiertest.h ../include/tools/modifiers/modifiertangents.h ../include/tools/modifiers/modifiersegmentation.h - ../include/tools/assistant.h + ../include/tools/modifiers/modifierassistants.h ) set(SOURCES @@ -119,10 +120,11 @@ set(SOURCES inputstate.cpp track.cpp inputmanager.cpp - modifiertest.cpp - modifiertangents.cpp - modifiersegmentation.cpp assistant.cpp + modifiers/modifiertest.cpp + modifiers/modifiertangents.cpp + modifiers/modifiersegmentation.cpp + modifiers/modifierassistants.cpp ) set(RESOURCES tnztools.qrc) diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp index 80510cd..eda9f1e 100644 --- a/toonz/sources/tnztools/assistant.cpp +++ b/toonz/sources/tnztools/assistant.cpp @@ -1,6 +1,8 @@ #include <tools/assistant.h> +#include <tgl.h> + #include <limits> @@ -9,22 +11,23 @@ //************************************************************************ double -TGuideline::calcTrackWeight(const TTrack &track, const TAffine &affine) const { - if (track.empty() < 1) +TGuideline::calcTrackWeight(const TTrack &track, const TAffine &toScreen, bool &outLongEnough) const { + outLongEnough = false; + if (track.size() < 2) return std::numeric_limits<double>::infinity(); const double snapLenght = 20.0; const double snapScale = 1.0; - const double maxLenght = 20.0*snapLenght*snapScale; + const double maxLength = 20.0*snapLenght*snapScale; double sumWeight = 0.0; double sumLength = 0.0; double sumDeviation = 0.0; - TPointD prev = affine*track[0].position; + TPointD prev = toScreen*track[0].position; for(int i = 0; i < track.size(); ++i) { const TTrackPoint &tp = track[i]; - TPointD p = affine*tp.position; + TPointD p = toScreen*tp.position; double length = tdistance(p, prev); sumLength += length; @@ -34,24 +37,28 @@ TGuideline::calcTrackWeight(const TTrack &track, const TAffine &affine) const { sumWeight += weight; TTrackPoint ntp = transformPoint(tp); - double deviation = tdistance(affine*ntp.position, p); + double deviation = tdistance(toScreen*ntp.position, p); sumDeviation += weight*deviation; } prev = p; + + if (sumLength >= maxLength) + { outLongEnough = true; break; } } - if (sumWeight < TTrack::epsilon) - return std::numeric_limits<double>::infinity(); - return sumDeviation/sumWeight; + return sumWeight > TTrack::epsilon + ? sumDeviation/sumWeight + : std::numeric_limits<double>::infinity(); } //--------------------------------------------------------------------------------------------------- TGuidelineP -TGuideline::findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &affine) { +TGuideline::findBest(const TGuidelineList &guidelines, const TTrack &track, const TAffine &toScreen, bool &outLongEnough) { + outLongEnough = true; double bestWeight = 0.0; TGuidelineP best; for(TGuidelineList::const_iterator i = guidelines.begin(); i != guidelines.end(); ++i) { - double weight = (*i)->calcTrackWeight(track, affine); + double weight = (*i)->calcTrackWeight(track, toScreen, outLongEnough); if (!best || weight < bestWeight) { bestWeight = weight; best = *i; } } @@ -63,4 +70,165 @@ TGuideline::findBest(const TGuidelineList &guidelines, const TTrack &track, cons // TAssistant implementation //************************************************************************ -// TODO: +TAssistant::TAssistant(TMetaObject &object): + TMetaObjectHandler(object), + m_idPoints("points"), + m_idX("x"), + m_idY("y") +{ } + +//--------------------------------------------------------------------------------------------------- + +const TPointD& +TAssistant::blank() { + static TPointD point; + return point; +} + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::fixPoints(int index, const TPointD &position) + { onFixPoints(); } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::movePoint(int index, const TPointD &position) + { if (index >= 0 && index < (int)m_points.size()) onMovePoint(index, position); } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::setPointSelection(int index, bool selected) { + if (index >= 0 && index < pointsCount()) + m_points[index].selected = selected; +} + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::onDataChanged(const TVariant &value) { + const TVariant& pointsData = data()[m_idPoints]; + TVariantPathEntry entry; + + if (&value == &data() || &value == &pointsData) + onAllDataChanged(); + else + if (pointsData.getChildPathEntry(value, entry) && entry.isIndex()) { + const TVariant& pointData = pointsData[entry]; + TPointD position = TPointD( + pointData[m_idX].getDouble(), + pointData[m_idY].getDouble() ); + movePoint(entry.index(), position); + } +} + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::onAllDataChanged() { + const TVariant& pointsData = data()[m_idPoints]; + for(int i = 0; i < pointsCount(); ++i) { + const TVariant& pointData = pointsData[i]; + m_points[i].position = TPointD( + pointData[m_idX].getDouble(), + pointData[m_idY].getDouble() ); + } +} + +//--------------------------------------------------------------------------------------------------- + +//! fix positions of all points +void +TAssistant::onFixPoints() + { } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::onMovePoint(int index, const TPointD &position) + { m_points[index].position = position; } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::onFixData() { + TVariant& pointsData = data()[m_idPoints]; + for(int i = 0; i < pointsCount(); ++i) { + TVariant& pointData = pointsData[i]; + pointData[m_idX].setDouble( m_points[i].position.x ); + pointData[m_idY].setDouble( m_points[i].position.y ); + } +} + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::drawPoint(const TAssistantPoint &point, double pixelSize) const { + double radius = 10.0; + double crossSize = 1.2*radius; + + double colorBlack[4] = { 0.0, 0.0, 0.0, 0.5 }; + double colorGray[4] = { 0.5, 0.5, 0.5, 0.5 }; + double colorWhite[4] = { 1.0, 1.0, 1.0, 0.5 }; + + if (point.selected) { + colorBlack[2] = 1.0; + colorGray[2] = 1.0; + } + + glPushAttrib(GL_ALL_ATTRIB_BITS); + + tglEnableBlending(); + tglEnableLineSmooth(true, 0.5); + + if (point.type == TAssistantPoint::CircleFill) { + glColor4dv(colorGray); + tglDrawDisk(point.position, radius*pixelSize); + } + + if (point.type == TAssistantPoint::CircleCross) { + TPointD dp(0.5*pixelSize, 0.5*pixelSize); + TPointD dx(pixelSize*crossSize, 0.0); + TPointD dy(0.0, pixelSize*crossSize); + + glColor4dv(colorWhite); + tglDrawSegment(point.position - dx + dp, point.position + dx + dp); + tglDrawSegment(point.position - dy + dp, point.position + dy + dp); + glColor4dv(colorBlack); + tglDrawSegment(point.position - dx - dp, point.position + dx - dp); + tglDrawSegment(point.position - dy - dp, point.position + dy - dp); + } + + glColor4dv(colorWhite); + tglDrawCircle(point.position, (radius + 0.5)*pixelSize); + glColor4dv(colorBlack); + tglDrawCircle(point.position, (radius - 0.5)*pixelSize); + + glPopAttrib(); +} + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::getGuidelines(const TPointD &position, const TAffine &toTool, TGuidelineList &outGuidelines) const + { } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::draw(TToolViewer *viewer) const + { } + +//--------------------------------------------------------------------------------------------------- + +void +TAssistant::drawEdit(TToolViewer *viewer) const { + // paint all points + double pixelSize = sqrt(tglGetPixelSize2()); + for(int i = 0; i < pointsCount(); ++i) + drawPoint(m_points[i], pixelSize); +} + +//--------------------------------------------------------------------------------------------------- diff --git a/toonz/sources/tnztools/inputmanager.cpp b/toonz/sources/tnztools/inputmanager.cpp index 0cb6bc7..b65a2f5 100644 --- a/toonz/sources/tnztools/inputmanager.cpp +++ b/toonz/sources/tnztools/inputmanager.cpp @@ -98,14 +98,26 @@ TInputModifier::calcDrawBounds(const TTrackList &tracks, const THoverList &hover void -TInputModifier::draw(const TTrackList &tracks, const THoverList &hovers) { +TInputModifier::drawTracks(const TTrackList &tracks) { for(TTrackList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) drawTrack(**i); - for(THoverList::const_iterator i = hovers.begin(); i != hovers.end(); ++i) +} + + +void +TInputModifier::drawHovers(const std::vector<TPointD> &hovers) { + for(std::vector<TPointD>::const_iterator i = hovers.begin(); i != hovers.end(); ++i) drawHover(*i); } +void +TInputModifier::draw(const TTrackList &tracks, const std::vector<TPointD> &hovers) { + drawTracks(tracks); + drawHovers(hovers); +} + + //***************************************************************************************** // TInputHandler implementation //***************************************************************************************** diff --git a/toonz/sources/tnztools/modifiers/modifierassistants.cpp b/toonz/sources/tnztools/modifiers/modifierassistants.cpp new file mode 100644 index 0000000..acd24da --- /dev/null +++ b/toonz/sources/tnztools/modifiers/modifierassistants.cpp @@ -0,0 +1,159 @@ + + +#include <tools/modifiers/modifierassistants.h> + +// TnzTools includes +#include <tools/tool.h> + +// TnzLib includes +#include <toonz/tapplication.h> +#include <toonz/txshlevelhandle.h> +#include <toonz/txsheethandle.h> +#include <toonz/txsheet.h> +#include <toonz/tframehandle.h> + +// TnzCore includes +#include <tmetaimage.h> + + +//***************************************************************************************** +// TModifierAssistants::Modifier implementation +//***************************************************************************************** + + +TModifierAssistants::Modifier::Modifier(TTrackHandler &handler): + TTrackModifier(handler), + initialized() +{ } + + +TTrackPoint +TModifierAssistants::Modifier::calcPoint(double originalIndex) { + TTrackPoint p = TTrackModifier::calcPoint(originalIndex); + return guidelines.empty() > 0 ? p : guidelines.front()->transformPoint(p); +} + + +//***************************************************************************************** +// TModifierAssistants implementation +//***************************************************************************************** + + +TModifierAssistants::TModifierAssistants(): + sensitiveLength(50.0) { } + + +void +TModifierAssistants::findGuidelines(const TPointD &position, TGuidelineList &outGuidelines) const { + if (TInputManager *manager = getManager()) + if (TInputHandler *handler = manager->getHandler()) + if (TTool *tool = handler->getTool()) + if (TToolViewer *viewer = tool->getViewer()) + if (TApplication *application = tool->getApplication()) + if (TFrameHandle *frameHandle = application->getCurrentFrame()) + if (TXsheetHandle *XsheetHandle = application->getCurrentXsheet()) + if (TXsheet *Xsheet = XsheetHandle->getXsheet()) + { + int frame = frameHandle->getFrame(); + int count = Xsheet->getColumnCount(); + TAffine worldToTrack = viewer->getViewMatrix(); + + for(int i = 0; i < count; ++i) + if (TImageP image = Xsheet->getCell(frame, i).getImage(false)) + if (image->getType() == TImage::META) + if (TMetaImage *metaImage = dynamic_cast<TMetaImage*>(image.getPointer())) + { + TAffine imageToTrack = tool->getColumnMatrix(i) + * worldToTrack; + TMetaImage::Reader reader(*metaImage); + + for(TMetaObjectRefList::const_iterator i = reader->begin(); i != reader->end(); ++i) + if (*i) + if (const TAssistant *assistant = (*i)->getHandler<TAssistant>()) + assistant->getGuidelines(position, imageToTrack, outGuidelines); + } + } +} + + +void +TModifierAssistants::modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + if (!track.handler) { + track.handler = new TTrackHandler(track); + Modifier *modifier = new Modifier(*track.handler); + findGuidelines(track[0].position, modifier->guidelines); + + track.handler->tracks.push_back(new TTrack(modifier)); + + if ((int)modifier->guidelines.size() > 1) { + modifier->savePoint = savePoint; + outTracks.push_back(track.handler->tracks.front()); + return; + } + } + + outTracks.push_back(track.handler->tracks.front()); + TTrack &subTrack = *track.handler->tracks.front(); + if (!track.changed()) return; + if (Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer())) { + // remove points + int start = track.size() - track.pointsAdded; + if (start < 0) start = 0; + + if ((int)modifier->guidelines.size() > 1 && modifier->savePoint.available()) { + // select guideline + bool longEnough = false; + if (TInputManager *manager = getManager()) { + if (TToolViewer *viewer = manager->getViewer()) { + TAffine trackToScreen = manager->toolToWorld() + * viewer->get3dViewMatrix().get2d().inv(); + TGuidelineP guideline = TGuideline::findBest(modifier->guidelines, track, trackToScreen, longEnough); + if (guideline != modifier->guidelines.front()) + for(int i = 1; i < (int)modifier->guidelines.size(); ++i) + if (modifier->guidelines[i] == guideline) { + std::swap(modifier->guidelines[i], modifier->guidelines.front()); + start = 0; + break; + } + } + } + modifier->savePoint.setLock(!longEnough); + } else { + modifier->savePoint.reset(); + } + + // add points + subTrack.truncate(start); + for(int i = start; i < track.size(); ++i) + subTrack.push_back( modifier->calcPoint(i) ); + } + track.resetChanges(); +} + + +void +TModifierAssistants::drawHover(const TPointD &hover) { + TGuidelineList guidelines; + findGuidelines(hover, guidelines); + for(TGuidelineList::const_iterator i = guidelines.begin(); i != guidelines.end(); ++i) + (*i)->draw(); +} + + +void +TModifierAssistants::drawTrack(const TTrack &track) { + if (!track.handler) return; + TTrack &subTrack = *track.handler->tracks.front(); + if (Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer())) { + const TGuidelineList &guidelines = modifier->guidelines; + if (!guidelines.empty()) { + guidelines.front()->draw(true); + for(TGuidelineList::const_iterator i = guidelines.begin() + 1; i != guidelines.end(); ++i) + (*i)->draw(); + } + } +} diff --git a/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp b/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp new file mode 100644 index 0000000..dc00b39 --- /dev/null +++ b/toonz/sources/tnztools/modifiers/modifiersegmentation.cpp @@ -0,0 +1,73 @@ + + +#include <tools/modifiers/modifiersegmentation.h> +#include <algorithm> + + +//***************************************************************************************** +// TModifierSegmentation implementation +//***************************************************************************************** + + +TModifierSegmentation::TModifierSegmentation(double precision): + precision(std::max(TTrack::epsilon, precision)), + precisionSqr(this->precision * this->precision) +{ } + + +void +TModifierSegmentation::addSegments( + TTrack &track, + const TTrackPoint &p0, + const TTrackPoint &p1, + int level) +{ + static const int maxRecursion = 10; + TPointD d = p1.position - p0.position; + + if (level >= maxRecursion || d.x*d.x + d.y*d.y <= precisionSqr) { + track.push_back(p1); + return; + } + + TTrackPoint p = track.modifier->calcPoint(0.5*(p0.originalIndex + p1.originalIndex)); + addSegments(track, p0, p, level + 1); + addSegments(track, p, p1, level + 1); +} + + +void +TModifierSegmentation::modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + if (!track.handler) { + track.handler = new TTrackHandler(track); + track.handler->tracks.push_back( + new TTrack( + new TTrackModifier(*track.handler) )); + } + + if (!track.changed() || track.handler->tracks.empty()) + return; + + TTrack &subTrack = *track.handler->tracks.front(); + outTracks.push_back(track.handler->tracks.front()); + + // remove points + int start = track.size() - track.pointsAdded; + if (start < 0) start = 0; + int subStart = subTrack.ceilIndex(subTrack.indexByOriginalIndex(start-1)) + 1; + subTrack.truncate(subStart); + + // add points + TTrackPoint p0 = subTrack.modifier->calcPoint(start - 1); + for(int i = start; i < track.size(); ++i) { + TTrackPoint p1 = subTrack.modifier->calcPoint(i); + addSegments(subTrack, p0, p1); + p0 = p1; + } + + track.resetChanges(); +} diff --git a/toonz/sources/tnztools/modifiers/modifiertangents.cpp b/toonz/sources/tnztools/modifiers/modifiertangents.cpp new file mode 100644 index 0000000..1dab9cc --- /dev/null +++ b/toonz/sources/tnztools/modifiers/modifiertangents.cpp @@ -0,0 +1,118 @@ + + +#include <tools/modifiers/modifiertangents.h> + + +//***************************************************************************************** +// TModifierTangents::Modifier implementation +//***************************************************************************************** + + +TTrackPoint +TModifierTangents::Modifier::calcPoint(double originalIndex) { + double frac; + int i0 = original.floorIndex(originalIndex, &frac); + int i1 = original.ceilIndex(originalIndex); + TTrackPoint p = i0 < 0 ? TTrackPoint() + : TTrack::interpolationSpline( + original[i0], + original[i1], + i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent(), + i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent(), + frac ); + p.originalIndex = originalIndex; + return p; +} + + +//***************************************************************************************** +// TModifierTangents implementation +//***************************************************************************************** + + +void +TModifierTangents::modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + if (!track.handler) { + track.handler = new TTrackHandler(track); + track.handler->tracks.push_back( + new TTrack( + new Modifier(*track.handler) )); + } + + if (track.handler->tracks.empty()) + return; + + TTrack &subTrack = *track.handler->tracks.front(); + Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer()); + if (!modifier) + return; + + outTracks.push_back(track.handler->tracks.front()); + + if ( !track.changed() + && track.size() == subTrack.size() + && track.size() == (int)modifier->tangents.size() ) + return; + + if (!track.changed() && subTrack.size() == track.size() - 1) { + // add temporary point + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track.back()); + } else { + // apply permanent changes + + // remove points + int start = track.size() - track.pointsAdded; + if (start < 0) start = 0; + if (start > 1) --start; + subTrack.truncate(start); + TTrackTangent lastTangent = + start < (int)modifier->tangents.size() ? modifier->tangents[start] + : modifier->tangents.empty() ? TTrackTangent() + : modifier->tangents.back(); + modifier->tangents.resize(start, lastTangent); + + // add first point + int index = start; + if (index == 0) { + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track.back()); + ++index; + } + + // add points with tangents + while(index < track.size() - 1) { + const TTrackPoint &p0 = track[index-1]; + const TTrackPoint &p1 = track[index]; + const TTrackPoint &p2 = track[index+1]; + double dt = p2.time - p0.time; + double k = dt > TTrack::epsilon ? (p1.time - p0.time)/dt : 0.5; + TTrackTangent tangent( + (p2.position - p0.position)*k, + (p2.pressure - p0.pressure)*k, + (p2.tilt - p0.tilt)*k ); + modifier->tangents.push_back(tangent); + subTrack.push_back(p1); + ++index; + } + + track.resetChanges(); + + // release previous key point + modifier->savePoint.reset(); + + if (track.finished()) { + // finish + modifier->tangents.push_back(TTrackTangent()); + subTrack.push_back(track.back()); + } else { + // save key point + modifier->savePoint = savePoint; + } + } +} + diff --git a/toonz/sources/tnztools/modifiers/modifiertest.cpp b/toonz/sources/tnztools/modifiers/modifiertest.cpp new file mode 100644 index 0000000..75090d6 --- /dev/null +++ b/toonz/sources/tnztools/modifiers/modifiertest.cpp @@ -0,0 +1,153 @@ + + +#include <tools/modifiers/modifiertest.h> + +// std includes +#include <cmath> + +//***************************************************************************************** +// TModifierTest::Modifier implementation +//***************************************************************************************** + + +TModifierTest::Modifier::Modifier( + TTrackHandler &handler, + double angle, + double radius, + double speed +): + TTrackModifier(handler), + angle(angle), + radius(radius), + speed(speed) +{ } + + +TTrackPoint +TModifierTest::Modifier::calcPoint(double originalIndex) { + TTrackPoint p = TTrackModifier::calcPoint(originalIndex); + + if (p.length > 2.0) { + double frac; + int i0 = original.floorIndex(originalIndex, &frac); + int i1 = original.ceilIndex(originalIndex); + if (i0 < 0) return p; + + if (Handler *handler = dynamic_cast<Handler*>(&this->handler)) { + double angle = this->angle + speed*TTrack::interpolationLinear( + handler->angles[i0], handler->angles[i1], frac); + double radius = 2.0*this->radius*p.pressure; + double s = sin(angle); + double c = cos(angle); + + TPointD tangent = TPointD(1.0, 0.0); // original.calcTangent(originalIndex, fabs(2.0*this->radius/speed)); + p.position.x += radius*(c*tangent.x - s*tangent.y); + p.position.y += radius*(s*tangent.x + c*tangent.y); + p.pressure *= 0.5*(1.0 + c); + } + } else { + p.pressure = 0.0; + } + + return p; +} + + +//***************************************************************************************** +// TModifierTest implementation +//***************************************************************************************** + + +TModifierTest::TModifierTest(): + count(1), + radius(40.0) +{ } + + +void +TModifierTest::modifyTrack( + const TTrack &track, + const TInputSavePoint::Holder &savePoint, + TTrackList &outTracks ) +{ + const double segmentSize = M_PI/180.0*10.0; + + if (!track.handler) { + if (track.getKeyState(track.front().time).isPressed(TKey(Qt::Key_Alt))) { + // TModifierTest::Handler for spiro + track.handler = new Handler(track); + for(int i = 0; i < count; ++i) + track.handler->tracks.push_back( + new TTrack( + new Modifier( + *track.handler, + i*2.0*M_PI/(double)count, + radius, + 2.0 ))); + } + } + + Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer()); + if (!handler) { + TInputModifier::modifyTrack(track, savePoint, outTracks); + return; + } + + outTracks.insert( + outTracks.end(), + track.handler->tracks.begin(), + track.handler->tracks.end() ); + if (!track.changed()) + return; + + int start = track.size() - track.pointsAdded; + if (start < 0) start = 0; + + // remove angles + double lastAngle = start < (int)handler->angles.size() ? handler->angles[start] + : handler->angles.empty() ? 0.0 + : handler->angles.back(); + handler->angles.resize(start, lastAngle); + + // add angles + for(int i = start; i < track.size(); ++i) { + if (i > 0) { + double dl = track[i].length - track[i-1].length; + double da = track[i].pressure > TTrack::epsilon + ? dl/(2.0*radius*track[i].pressure) : 0.0; + handler->angles.push_back(handler->angles[i-1] + da); + } else { + handler->angles.push_back(0.0); + } + } + + // process sub-tracks + for(TTrackList::const_iterator ti = handler->tracks.begin(); ti != handler->tracks.end(); ++ti) { + TTrack &subTrack = **ti; + + // remove points + int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); + if (subStart < 0) subStart = 0; + if (subStart < subTrack.size() && subTrack[subStart].originalIndex + TTrack::epsilon < start) + ++subStart; + subTrack.truncate(subStart); + + // add points + for(int i = start; i < track.size(); ++i) { + if (i > 0) { + double prevAngle = handler->angles[i-1]; + double nextAngle = handler->angles[i]; + if (fabs(nextAngle - prevAngle) > 1.5*segmentSize) { + double step = segmentSize/fabs(nextAngle - prevAngle); + double end = 1.0 - 0.5*step; + for(double frac = step; frac < end; frac += step) + subTrack.push_back( subTrack.modifier->calcPoint((double)i - 1.0 + frac) ); + } + } + subTrack.push_back( subTrack.modifier->calcPoint(i) ); + } + } + + track.resetChanges(); +} + diff --git a/toonz/sources/tnztools/modifiersegmentation.cpp b/toonz/sources/tnztools/modifiersegmentation.cpp deleted file mode 100644 index dc00b39..0000000 --- a/toonz/sources/tnztools/modifiersegmentation.cpp +++ /dev/null @@ -1,73 +0,0 @@ - - -#include <tools/modifiers/modifiersegmentation.h> -#include <algorithm> - - -//***************************************************************************************** -// TModifierSegmentation implementation -//***************************************************************************************** - - -TModifierSegmentation::TModifierSegmentation(double precision): - precision(std::max(TTrack::epsilon, precision)), - precisionSqr(this->precision * this->precision) -{ } - - -void -TModifierSegmentation::addSegments( - TTrack &track, - const TTrackPoint &p0, - const TTrackPoint &p1, - int level) -{ - static const int maxRecursion = 10; - TPointD d = p1.position - p0.position; - - if (level >= maxRecursion || d.x*d.x + d.y*d.y <= precisionSqr) { - track.push_back(p1); - return; - } - - TTrackPoint p = track.modifier->calcPoint(0.5*(p0.originalIndex + p1.originalIndex)); - addSegments(track, p0, p, level + 1); - addSegments(track, p, p1, level + 1); -} - - -void -TModifierSegmentation::modifyTrack( - const TTrack &track, - const TInputSavePoint::Holder &savePoint, - TTrackList &outTracks ) -{ - if (!track.handler) { - track.handler = new TTrackHandler(track); - track.handler->tracks.push_back( - new TTrack( - new TTrackModifier(*track.handler) )); - } - - if (!track.changed() || track.handler->tracks.empty()) - return; - - TTrack &subTrack = *track.handler->tracks.front(); - outTracks.push_back(track.handler->tracks.front()); - - // remove points - int start = track.size() - track.pointsAdded; - if (start < 0) start = 0; - int subStart = subTrack.ceilIndex(subTrack.indexByOriginalIndex(start-1)) + 1; - subTrack.truncate(subStart); - - // add points - TTrackPoint p0 = subTrack.modifier->calcPoint(start - 1); - for(int i = start; i < track.size(); ++i) { - TTrackPoint p1 = subTrack.modifier->calcPoint(i); - addSegments(subTrack, p0, p1); - p0 = p1; - } - - track.resetChanges(); -} diff --git a/toonz/sources/tnztools/modifiertangents.cpp b/toonz/sources/tnztools/modifiertangents.cpp deleted file mode 100644 index 1dab9cc..0000000 --- a/toonz/sources/tnztools/modifiertangents.cpp +++ /dev/null @@ -1,118 +0,0 @@ - - -#include <tools/modifiers/modifiertangents.h> - - -//***************************************************************************************** -// TModifierTangents::Modifier implementation -//***************************************************************************************** - - -TTrackPoint -TModifierTangents::Modifier::calcPoint(double originalIndex) { - double frac; - int i0 = original.floorIndex(originalIndex, &frac); - int i1 = original.ceilIndex(originalIndex); - TTrackPoint p = i0 < 0 ? TTrackPoint() - : TTrack::interpolationSpline( - original[i0], - original[i1], - i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent(), - i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent(), - frac ); - p.originalIndex = originalIndex; - return p; -} - - -//***************************************************************************************** -// TModifierTangents implementation -//***************************************************************************************** - - -void -TModifierTangents::modifyTrack( - const TTrack &track, - const TInputSavePoint::Holder &savePoint, - TTrackList &outTracks ) -{ - if (!track.handler) { - track.handler = new TTrackHandler(track); - track.handler->tracks.push_back( - new TTrack( - new Modifier(*track.handler) )); - } - - if (track.handler->tracks.empty()) - return; - - TTrack &subTrack = *track.handler->tracks.front(); - Modifier *modifier = dynamic_cast<Modifier*>(subTrack.modifier.getPointer()); - if (!modifier) - return; - - outTracks.push_back(track.handler->tracks.front()); - - if ( !track.changed() - && track.size() == subTrack.size() - && track.size() == (int)modifier->tangents.size() ) - return; - - if (!track.changed() && subTrack.size() == track.size() - 1) { - // add temporary point - modifier->tangents.push_back(TTrackTangent()); - subTrack.push_back(track.back()); - } else { - // apply permanent changes - - // remove points - int start = track.size() - track.pointsAdded; - if (start < 0) start = 0; - if (start > 1) --start; - subTrack.truncate(start); - TTrackTangent lastTangent = - start < (int)modifier->tangents.size() ? modifier->tangents[start] - : modifier->tangents.empty() ? TTrackTangent() - : modifier->tangents.back(); - modifier->tangents.resize(start, lastTangent); - - // add first point - int index = start; - if (index == 0) { - modifier->tangents.push_back(TTrackTangent()); - subTrack.push_back(track.back()); - ++index; - } - - // add points with tangents - while(index < track.size() - 1) { - const TTrackPoint &p0 = track[index-1]; - const TTrackPoint &p1 = track[index]; - const TTrackPoint &p2 = track[index+1]; - double dt = p2.time - p0.time; - double k = dt > TTrack::epsilon ? (p1.time - p0.time)/dt : 0.5; - TTrackTangent tangent( - (p2.position - p0.position)*k, - (p2.pressure - p0.pressure)*k, - (p2.tilt - p0.tilt)*k ); - modifier->tangents.push_back(tangent); - subTrack.push_back(p1); - ++index; - } - - track.resetChanges(); - - // release previous key point - modifier->savePoint.reset(); - - if (track.finished()) { - // finish - modifier->tangents.push_back(TTrackTangent()); - subTrack.push_back(track.back()); - } else { - // save key point - modifier->savePoint = savePoint; - } - } -} - diff --git a/toonz/sources/tnztools/modifiertest.cpp b/toonz/sources/tnztools/modifiertest.cpp deleted file mode 100644 index 75090d6..0000000 --- a/toonz/sources/tnztools/modifiertest.cpp +++ /dev/null @@ -1,153 +0,0 @@ - - -#include <tools/modifiers/modifiertest.h> - -// std includes -#include <cmath> - -//***************************************************************************************** -// TModifierTest::Modifier implementation -//***************************************************************************************** - - -TModifierTest::Modifier::Modifier( - TTrackHandler &handler, - double angle, - double radius, - double speed -): - TTrackModifier(handler), - angle(angle), - radius(radius), - speed(speed) -{ } - - -TTrackPoint -TModifierTest::Modifier::calcPoint(double originalIndex) { - TTrackPoint p = TTrackModifier::calcPoint(originalIndex); - - if (p.length > 2.0) { - double frac; - int i0 = original.floorIndex(originalIndex, &frac); - int i1 = original.ceilIndex(originalIndex); - if (i0 < 0) return p; - - if (Handler *handler = dynamic_cast<Handler*>(&this->handler)) { - double angle = this->angle + speed*TTrack::interpolationLinear( - handler->angles[i0], handler->angles[i1], frac); - double radius = 2.0*this->radius*p.pressure; - double s = sin(angle); - double c = cos(angle); - - TPointD tangent = TPointD(1.0, 0.0); // original.calcTangent(originalIndex, fabs(2.0*this->radius/speed)); - p.position.x += radius*(c*tangent.x - s*tangent.y); - p.position.y += radius*(s*tangent.x + c*tangent.y); - p.pressure *= 0.5*(1.0 + c); - } - } else { - p.pressure = 0.0; - } - - return p; -} - - -//***************************************************************************************** -// TModifierTest implementation -//***************************************************************************************** - - -TModifierTest::TModifierTest(): - count(1), - radius(40.0) -{ } - - -void -TModifierTest::modifyTrack( - const TTrack &track, - const TInputSavePoint::Holder &savePoint, - TTrackList &outTracks ) -{ - const double segmentSize = M_PI/180.0*10.0; - - if (!track.handler) { - if (track.getKeyState(track.front().time).isPressed(TKey(Qt::Key_Alt))) { - // TModifierTest::Handler for spiro - track.handler = new Handler(track); - for(int i = 0; i < count; ++i) - track.handler->tracks.push_back( - new TTrack( - new Modifier( - *track.handler, - i*2.0*M_PI/(double)count, - radius, - 2.0 ))); - } - } - - Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer()); - if (!handler) { - TInputModifier::modifyTrack(track, savePoint, outTracks); - return; - } - - outTracks.insert( - outTracks.end(), - track.handler->tracks.begin(), - track.handler->tracks.end() ); - if (!track.changed()) - return; - - int start = track.size() - track.pointsAdded; - if (start < 0) start = 0; - - // remove angles - double lastAngle = start < (int)handler->angles.size() ? handler->angles[start] - : handler->angles.empty() ? 0.0 - : handler->angles.back(); - handler->angles.resize(start, lastAngle); - - // add angles - for(int i = start; i < track.size(); ++i) { - if (i > 0) { - double dl = track[i].length - track[i-1].length; - double da = track[i].pressure > TTrack::epsilon - ? dl/(2.0*radius*track[i].pressure) : 0.0; - handler->angles.push_back(handler->angles[i-1] + da); - } else { - handler->angles.push_back(0.0); - } - } - - // process sub-tracks - for(TTrackList::const_iterator ti = handler->tracks.begin(); ti != handler->tracks.end(); ++ti) { - TTrack &subTrack = **ti; - - // remove points - int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start)); - if (subStart < 0) subStart = 0; - if (subStart < subTrack.size() && subTrack[subStart].originalIndex + TTrack::epsilon < start) - ++subStart; - subTrack.truncate(subStart); - - // add points - for(int i = start; i < track.size(); ++i) { - if (i > 0) { - double prevAngle = handler->angles[i-1]; - double nextAngle = handler->angles[i]; - if (fabs(nextAngle - prevAngle) > 1.5*segmentSize) { - double step = segmentSize/fabs(nextAngle - prevAngle); - double end = 1.0 - 0.5*step; - for(double frac = step; frac < end; frac += step) - subTrack.push_back( subTrack.modifier->calcPoint((double)i - 1.0 + frac) ); - } - } - subTrack.push_back( subTrack.modifier->calcPoint(i) ); - } - } - - track.resetChanges(); -} -