2b429e
#pragma once
2b429e
2b429e
#ifndef TRACK_INCLUDED
2b429e
#define TRACK_INCLUDED
2b429e
2b429e
// TnzTools includes
efa14d
#include <tools inputstate.h=""></tools>
efa14d
efa14d
// TnzCore includes
2b429e
#include <tcommon.h></tcommon.h>
2b429e
#include <tgeometry.h></tgeometry.h>
2b429e
2b429e
// Qt headers
2b429e
#include <qt></qt>
2b429e
2b429e
// std includes
2b429e
#include <vector></vector>
2b429e
#include <algorithm></algorithm>
2b429e
2b429e
2b429e
#undef DVAPI
2b429e
#undef DVVAR
2b429e
#ifdef TNZTOOLS_EXPORTS
2b429e
#define DVAPI DV_EXPORT_API
2b429e
#define DVVAR DV_EXPORT_VAR
2b429e
#else
2b429e
#define DVAPI DV_IMPORT_API
2b429e
#define DVVAR DV_IMPORT_VAR
2b429e
#endif
2b429e
2b429e
2b429e
//===================================================================
2b429e
2b429e
//    Forward Declarations
2b429e
2b429e
class TTrack;
49945e
class TTrackPoint;
d8eddc
class TTrackTangent;
2b429e
class TTrackHandler;
7a5892
class TTrackToolHandler;
2b429e
class TTrackModifier;
49945e
2b429e
typedef TSmartPointerT<ttrack> TTrackP;</ttrack>
2b429e
typedef TSmartPointerT<ttrackhandler> TTrackHandlerP;</ttrackhandler>
7a5892
typedef TSmartPointerT<ttracktoolhandler> TTrackToolHandlerP;</ttracktoolhandler>
2b429e
typedef TSmartPointerT<ttrackmodifier> TTrackModifierP;</ttrackmodifier>
49945e
49945e
typedef std::vector<ttrackpoint> TTrackPointList;</ttrackpoint>
d8eddc
typedef std::vector<ttracktangent> TTrackTangentList;</ttracktangent>
efa14d
typedef std::vector<ttrackp> TTrackList;</ttrackp>
2b429e
2b429e
//===================================================================
2b429e
2b429e
2b429e
//*****************************************************************************************
7a5892
//    TTrackToolHandler definition
7a5892
//*****************************************************************************************
7a5892
7a5892
class DVAPI TTrackToolHandler : public TSmartObject { };
7a5892
7a5892
7a5892
//*****************************************************************************************
16421e
//    export template implementations for win32
16421e
//*****************************************************************************************
16421e
16421e
#ifdef _WIN32
16421e
template class DVAPI TSmartPointerT<ttrack>;</ttrack>
16421e
template class DVAPI TSmartPointerT<ttrackhandler>;</ttrackhandler>
16421e
template class DVAPI TSmartPointerT<ttracktoolhandler>;</ttracktoolhandler>
16421e
template class DVAPI TSmartPointerT<ttrackmodifier>;</ttrackmodifier>
16421e
#endif
16421e
16421e
16421e
//*****************************************************************************************
2b429e
//    TTrackPoint definition
2b429e
//*****************************************************************************************
2b429e
6be163
class DVAPI TTrackPoint {
2b429e
public:
2b429e
  TPointD position;
2b429e
  double pressure;
2b429e
  TPointD tilt;
2b429e
2b429e
  double originalIndex;
2b429e
  double time;
2b429e
  double length;
2b429e
2b429e
  bool final;
2b429e
2b429e
  explicit TTrackPoint(
2b429e
    const TPointD &position = TPointD(),
2b429e
    double pressure = 0.5,
2b429e
    const TPointD &tilt = TPointD(),
2b429e
    double originalIndex = 0.0,
2b429e
    double time = 0.0,
2b429e
    double length = 0.0,
2b429e
    bool final = false
2b429e
  ):
2b429e
    position(position),
2b429e
    pressure(pressure),
2b429e
    tilt(tilt),
2b429e
    originalIndex(originalIndex),
2b429e
    time(time),
2b429e
    length(length),
2b429e
    final(final)
2b429e
  { }
2b429e
};
2b429e
2b429e
2b429e
//*****************************************************************************************
d8eddc
//    TTrackTangent definition
d8eddc
//*****************************************************************************************
d8eddc
6be163
class DVAPI TTrackTangent {
d8eddc
public:
d8eddc
  TPointD position;
d8eddc
  double pressure;
d8eddc
  TPointD tilt;
d8eddc
d8eddc
  inline explicit TTrackTangent(
d8eddc
    const TPointD &position = TPointD(),
d8eddc
    double pressure = 0.0,
d8eddc
    const TPointD &tilt = TPointD()
d8eddc
  ):
d8eddc
    position(position),
d8eddc
    pressure(pressure),
d8eddc
    tilt(tilt)
d8eddc
  { }
d8eddc
};
d8eddc
d8eddc
d8eddc
//*****************************************************************************************
2b429e
//    TTrackHandler definition
2b429e
//*****************************************************************************************
2b429e
2b429e
class DVAPI TTrackHandler : public TSmartObject {
2b429e
public:
c3c215
  const TTrack &original;
2b429e
  std::vector<ttrackp> tracks;</ttrackp>
c3c215
  TTrackHandler(const TTrack &original):
efa14d
    original(original) { }
2b429e
};
2b429e
2b429e
2b429e
//*****************************************************************************************
2b429e
//    TTrackModifier definition
2b429e
//*****************************************************************************************
2b429e
2b429e
class DVAPI TTrackModifier : public TSmartObject {
2b429e
public:
2b429e
    TTrackHandler &handler;
c3c215
    const TTrack &original;
2b429e
    const double timeOffset;
2b429e
2b429e
    explicit TTrackModifier(TTrackHandler &handler, double timeOffset = 0.0):
2b429e
      handler(handler), original(handler.original), timeOffset(timeOffset) { }
2b429e
    virtual TTrackPoint calcPoint(double originalIndex);
2b429e
};
2b429e
2b429e
2b429e
//*****************************************************************************************
2b429e
//    TTrack definition
2b429e
//*****************************************************************************************
2b429e
2b429e
class DVAPI TTrack : public TSmartObject {
2b429e
public:
2b429e
  typedef long long Id;
2b429e
2b429e
private:
49945e
  static Id m_lastId;
2b429e
2b429e
public:
2b429e
  const Id id;
efa14d
  const TInputState::DeviceId deviceId;
efa14d
  const TInputState::TouchId touchId;
efa14d
  const TInputState::KeyHistory::Holder keyHistory;
efa14d
  const TInputState::ButtonHistory::Holder buttonHistory;
49945e
  const bool hasPressure;
49945e
  const bool hasTilt;
2b429e
  const TTrackModifierP modifier;
2b429e
c3c215
  mutable TTrackHandlerP handler;
7a5892
  mutable TTrackToolHandlerP toolHandler;
c3c215
  mutable int pointsRemoved;
c3c215
  mutable int pointsAdded;
2b429e
2b429e
private:
49945e
  TTrackPointList m_points;
49945e
  const TTrackPoint m_none;
2b429e
2b429e
public:
2b429e
2b429e
  explicit TTrack(
efa14d
    TInputState::DeviceId deviceId = TInputState::DeviceId(),
efa14d
    TInputState::TouchId touchId = TInputState::TouchId(),
efa14d
    const TInputState::KeyHistory::Holder &keyHistory = TInputState::KeyHistory::Holder(),
49945e
    const TInputState::ButtonHistory::Holder &buttonHistory = TInputState::ButtonHistory::Holder(),
49945e
    bool hasPressure = false,
49945e
    bool hasTilt = false
2b429e
  );
2b429e
2b429e
  explicit TTrack(const TTrackModifierP &modifier);
2b429e
c3c215
  inline const TTrack* original() const
2b429e
    { return modifier ? &modifier->original : NULL; }
2b429e
  inline double timeOffset() const
2b429e
    { return modifier ? modifier->timeOffset : 0.0; }
2b429e
  inline TTimerTicks ticks() const
2b429e
    { return keyHistory.ticks(); }
2b429e
  inline bool changed() const
49945e
    { return pointsAdded != 0 || pointsRemoved != 0; }
2b429e
2b429e
  const TTrack* root() const;
2b429e
  int level() const;
2b429e
2b429e
  inline int clampIndex(int index) const
2b429e
    { return std::min(std::max(index, 0), size() - 1); }
2b429e
  inline int floorIndexNoClamp(double index) const
9f0c16
    { return (int)floor(index + TConsts::epsilon); }
2b429e
  inline int floorIndex(double index) const
2b429e
    { return clampIndex(floorIndexNoClamp(index)); }
2b429e
  inline int ceilIndexNoClamp(double index) const
9f0c16
    { return (int)ceil(index - TConsts::epsilon); }
2b429e
  inline int ceilIndex(double index) const
2b429e
    { return clampIndex(ceilIndexNoClamp(index)); }
2b429e
7e9eb1
  int floorIndex(double index, double *outFrac) const;
2b429e
7e9eb1
  inline const TTrackPoint& floorPoint(double index, double *outFrac = NULL) const
2b429e
    { return point(floorIndex(index, outFrac)); }
2b429e
  inline const TTrackPoint& ceilPoint(double index) const
2b429e
    { return point(ceilIndex(index)); }
2b429e
2b429e
  inline const TTrackPoint& point(int index) const
49945e
    { return empty() ? m_none : m_points[clampIndex(index)]; }
2b429e
2b429e
  inline int size() const
49945e
    { return (int)m_points.size(); }
2b429e
  inline bool empty() const
49945e
    { return m_points.empty(); }
2b429e
  inline const TTrackPoint& front() const
2b429e
    { return point(0); }
2b429e
  inline const TTrackPoint& back() const
2b429e
    { return point(size() - 1); }
2b429e
  inline bool finished() const
49945e
    { return !m_points.empty() && back().final; }
2b429e
  inline const TTrackPoint& operator[] (int index) const
2b429e
    { return point(index); }
49945e
  inline const TTrackPointList& points() const
49945e
    { return m_points; }
2b429e
00337d
  inline void resetRemoved() const
00337d
    { pointsRemoved = 0; }
00337d
  inline void resetAdded() const
00337d
    { pointsAdded = 0; }
00337d
  inline void resetChanges() const
00337d
    { resetRemoved(); resetAdded(); }
00337d
2b429e
  void push_back(const TTrackPoint &point);
2b429e
  void pop_back(int count = 1);
2b429e
2b429e
  inline void truncate(int count)
2b429e
    { pop_back(size() - count); }
2b429e
49945e
  inline const TTrackPoint& current() const
49945e
    { return point(size() - pointsAdded); }
7a5892
  inline const TTrackPoint& previous() const
7a5892
    { return point(size() - pointsAdded - 1); }
7a5892
  inline const TTrackPoint& next() const
7a5892
    { return point(size() - pointsAdded + 1); }
7a5892
49945e
  inline TInputState::KeyState::Holder getKeyState(double time) const
49945e
    { return keyHistory.get(time); }
d8eddc
  inline TInputState::KeyState::Holder getKeyState(const TTrackPoint &point) const
d8eddc
    { return getKeyState(timeOffset() + point.time); }
49945e
  inline TInputState::KeyState::Holder getCurrentKeyState() const
9f0c16
    { return getKeyState(timeOffset() + current().time); }
49945e
  inline TInputState::ButtonState::Holder getButtonState(double time) const
49945e
    { return buttonHistory.get(time); }
d8eddc
  inline TInputState::ButtonState::Holder getButtonState(const TTrackPoint &point) const
d8eddc
    { return getButtonState(timeOffset() + point.time); }
49945e
  inline TInputState::ButtonState::Holder getCurrentButtonState() const
9f0c16
    { return getButtonState(timeOffset() + current().time); }
2b429e
2b429e
private:
2b429e
  template<double ttrackpoint::*field=""></double>
2b429e
  double binarySearch(double value) const {
2b429e
    // points_[a].value <= value < points_[b].value
49945e
    if (m_points.empty()) return 0.0;
2b429e
    int a = 0;
49945e
    double aa = m_points[a].*Field;
9f0c16
    if (value - aa <= 0.5*TConsts::epsilon) return (double)a;
49945e
    int b = (int)m_points.size() - 1;
49945e
    double bb = m_points[b].*Field;
9f0c16
    if (bb - value <= 0.5*TConsts::epsilon) return (double)b;
2b429e
    while(true) {
2b429e
      int c = (a + b)/2;
2b429e
      if (a == c) break;
49945e
      double cc = m_points[c].*Field;
9f0c16
      if (cc - value > 0.5*TConsts::epsilon)
2b429e
        { b = c; bb = cc; } else { a = c; aa = cc; }
2b429e
    }
9f0c16
    return bb - aa >= 0.5*TConsts::epsilon ? (double)a + (value - aa)/(bb - aa) : (double)a;
2b429e
  }
2b429e
2b429e
public:
2b429e
  inline double indexByOriginalIndex(double originalIndex) const
2b429e
    { return binarySearch<&TTrackPoint::originalIndex>(originalIndex); }
2b429e
  inline double indexByTime(double time) const
2b429e
    { return binarySearch<&TTrackPoint::time>(time); }
2b429e
  inline double indexByLength(double length) const
2b429e
    { return binarySearch<&TTrackPoint::length>(length); }
2b429e
2b429e
  inline double originalIndexByIndex(double index) const {
2b429e
    double frac;
7e9eb1
    const TTrackPoint &p0 = floorPoint(index, &frac);
2b429e
    const TTrackPoint &p1 = ceilPoint(index);
2b429e
    return interpolationLinear(p0.originalIndex, p1.originalIndex, frac);
2b429e
  }
2b429e
  inline double timeByIndex(double index) const {
2b429e
    double frac;
7e9eb1
    const TTrackPoint &p0 = floorPoint(index, &frac);
2b429e
    const TTrackPoint &p1 = ceilPoint(index);
2b429e
    return interpolationLinear(p0.time, p1.time, frac);
2b429e
  }
2b429e
  inline double lengthByIndex(double index) const {
2b429e
    double frac;
7e9eb1
    const TTrackPoint &p0 = floorPoint(index, &frac);
2b429e
    const TTrackPoint &p1 = ceilPoint(index);
2b429e
    return interpolationLinear(p0.length, p1.length, frac);
2b429e
  }
2b429e
2b429e
  TTrackPoint calcPoint(double index) const;
2b429e
  TPointD calcTangent(double index, double distance = 0.1) const;
49945e
  double rootIndexByIndex(double index) const;
49945e
  TTrackPoint calcRootPoint(double index) const;
2b429e
2b429e
  inline TTrackPoint interpolateLinear(double index) const {
2b429e
    double frac;
7e9eb1
    const TTrackPoint &p0 = floorPoint(index, &frac);
2b429e
    const TTrackPoint &p1 = ceilPoint(index);
2b429e
    return interpolationLinear(p0, p1, frac);
2b429e
  }
2b429e
2b429e
  template<typename t=""></typename>
2b429e
  static inline T interpolationLinear(const T &p0, const T &p1, double l)
2b429e
    { return p0*(1.0 - l) + p1*l; }
2b429e
d8eddc
  template<typename t=""></typename>
d8eddc
  static T interpolationSpline(const T &p0, const T &p1, const T &t0, const T &t1, double l) {
d8eddc
    double ll = l*l;
d8eddc
    double lll = ll*l;
d8eddc
    return p0*( 2.0*lll - 3.0*ll + 1.0)
d8eddc
         + p1*(-2.0*lll + 3.0*ll      )
d8eddc
         + t0*(     lll - 2.0*ll + l  )
d8eddc
         + t1*(     lll - 1.0*ll      );
d8eddc
  }
d8eddc
2b429e
  static inline TTrackPoint interpolationLinear(const TTrackPoint &p0, const TTrackPoint &p1, double l) {
9f0c16
    if (l <= TConsts::epsilon) return p0;
9f0c16
    if (l >= 1.0 - TConsts::epsilon) return p1;
2b429e
    return TTrackPoint(
2b429e
      interpolationLinear(p0.position      , p1.position      , l),
2b429e
      interpolationLinear(p0.pressure      , p1.pressure      , l),
2b429e
      interpolationLinear(p0.tilt          , p1.tilt          , l),
2b429e
      interpolationLinear(p0.originalIndex , p1.originalIndex , l),
2b429e
      interpolationLinear(p0.time          , p1.time          , l),
2b429e
      interpolationLinear(p0.length        , p1.length        , l) );
2b429e
  }
d8eddc
d8eddc
  static inline TTrackPoint interpolationSpline(
d8eddc
    const TTrackPoint &p0,
d8eddc
    const TTrackPoint &p1,
d8eddc
    const TTrackTangent &t0,
d8eddc
    const TTrackTangent &t1,
d8eddc
    double l )
d8eddc
  {
9f0c16
    if (l <= TConsts::epsilon) return p0;
9f0c16
    if (l >= 1.0 - TConsts::epsilon) return p1;
d8eddc
    return TTrackPoint(
d8eddc
      interpolationSpline(p0.position      , p1.position      , t0.position , t1.position , l),
9f0c16
      interpolationLinear(p0.pressure      , p1.pressure      , l),
9f0c16
      //interpolationSpline(p0.pressure      , p1.pressure      , t0.pressure , t1.pressure , l),
9f0c16
      interpolationLinear(p0.tilt          , p1.tilt          , l),
9f0c16
      //interpolationSpline(p0.tilt          , p1.tilt          , t0.tilt     , t1.tilt     , l),
d8eddc
      interpolationLinear(p0.originalIndex , p1.originalIndex , l),
d8eddc
      interpolationLinear(p0.time          , p1.time          , l),
d8eddc
      interpolationLinear(p0.length        , p1.length        , l) );
d8eddc
  }
2b429e
};
2b429e
16421e
2b429e
#endif