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;
da847a
class TTrackTransform;
2b429e
class TTrackHandler;
fa009d
class TSubTrackHandler;
fa009d
class TMultiTrackHandler;
fa009d
class TTrackInterpolator;
49945e
2b429e
typedef TSmartPointerT<ttrack> TTrackP;</ttrack>
2b429e
typedef TSmartPointerT<ttrackhandler> TTrackHandlerP;</ttrackhandler>
fa009d
typedef TSmartPointerT<tsubtrackhandler> TSubTrackHandlerP;</tsubtrackhandler>
fa009d
typedef TSmartPointerT<tmultitrackhandler> TMultiTrackHandlerP;</tmultitrackhandler>
fa009d
typedef TSmartPointerT<ttrackinterpolator> TTrackInterpolatorP;</ttrackinterpolator>
49945e
49945e
typedef std::vector<ttrackpoint> TTrackPointList;</ttrackpoint>
d8eddc
typedef std::vector<ttracktangent> TTrackTangentList;</ttracktangent>
da847a
typedef std::vector<ttracktransform> TTrackTransformList;</ttracktransform>
efa14d
typedef std::vector<ttrackp> TTrackList;</ttrackp>
2b429e
2b429e
//===================================================================
2b429e
2b429e
2b429e
//*****************************************************************************************
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>
fa009d
template class DVAPI TSmartPointerT<tsubtrackhandler>;</tsubtrackhandler>
fa009d
template class DVAPI TSmartPointerT<tmultitrackhandler>;</tmultitrackhandler>
fa009d
template class DVAPI TSmartPointerT<ttrackinterpolator>;</ttrackinterpolator>
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
da847a
class DVAPI TTrackTransform {
da847a
public:
da847a
  TAffine transform;
da847a
  TAffine tiltTransform;
da847a
  double pressureScale;
da847a
  double pressureOffset;
da847a
da847a
  inline TTrackTransform(
da847a
    const TAffine &transform,
da847a
    const TAffine &tiltTransform,
da847a
    double pressureScale = 1,
da847a
    double pressureOffset = 0
da847a
  ):
da847a
    transform(transform),
da847a
    tiltTransform(tiltTransform),
da847a
    pressureScale(pressureScale),
da847a
    pressureOffset(pressureOffset) { }
da847a
da847a
  inline explicit TTrackTransform(
da847a
    const TAffine &transform,
da847a
    double pressureScale = 1,
da847a
    double pressureOffset = 0
da847a
  ):
da847a
    transform(transform),
da847a
    tiltTransform(makeTiltTransform(transform)),
da847a
    pressureScale(pressureScale),
da847a
    pressureOffset(pressureOffset) { }
da847a
da847a
  inline explicit TTrackTransform(
da847a
    double pressureScale = 1,
da847a
    double pressureOffset = 0
da847a
  ):
da847a
    pressureScale(pressureScale),
da847a
    pressureOffset(pressureOffset) { }
da847a
  
da847a
  inline TTrackPoint apply(TTrackPoint p) const {
da847a
    p.position = transform * p.position;
da847a
    
da847a
    TPointD t = tiltTransform * p.tilt;
da847a
    p.tilt.x = t.x > -1 ? (t.x < 1 ? t.x : 1) : -1;
da847a
    p.tilt.y = t.y > -1 ? (t.y < 1 ? t.y : 1) : -1;
da847a
    
da847a
    double pr = p.pressure*pressureScale + pressureOffset;
da847a
    p.pressure = pr > 0 ? (pr < 1 ? pr : 1) : 0;
da847a
    
da847a
    return p;
da847a
  }
da847a
da847a
  inline void recalcTiltTransform()
da847a
    { tiltTransform = makeTiltTransform(transform); }
da847a
da847a
  static TAffine makeTiltTransform(const TAffine &a);
da847a
};
da847a
da847a
da847a
//*****************************************************************************************
da847a
//    TTrackHandler definition
da847a
//*****************************************************************************************
da847a
fa009d
class DVAPI TTrackHandler : public TSmartObject { };
fa009d
fa009d
fa009d
//*****************************************************************************************
fa009d
//    TSubTrackHandler definition
fa009d
//*****************************************************************************************
fa009d
fa009d
class DVAPI TSubTrackHandler: public TTrackHandler {
2b429e
public:
fa009d
  TTrackP track;
2b429e
};
2b429e
2b429e
2b429e
//*****************************************************************************************
fa009d
//    TMultiTrackHandler definition
2b429e
//*****************************************************************************************
2b429e
fa009d
class DVAPI TMultiTrackHandler: public TTrackHandler {
2b429e
public:
fa009d
  std::vector<ttrackp> tracks;</ttrackp>
fa009d
};
fa009d
fa009d
fa009d
//*****************************************************************************************
fa009d
//    TTrackInterpolator definition
fa009d
//*****************************************************************************************
2b429e
fa009d
class DVAPI TTrackInterpolator : public TSmartObject {
fa009d
public:
fa009d
  TTrack &track;
fa009d
  inline explicit TTrackInterpolator(TTrack &track);
fa009d
  virtual TTrackPoint interpolate(double index) = 0;
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
fa009d
  const TTrack* const original;
fa009d
  const double timeOffset;
fa009d
  const double rootTimeOffset;
fa009d
  
c3c215
  mutable TTrackHandlerP handler;
c3c215
  mutable int pointsRemoved;
c3c215
  mutable int pointsAdded;
f278a5
  mutable int fixedPointsAdded;
2b429e
2b429e
private:
fa009d
  friend class TTrackInterpolator;
fa009d
  TTrackInterpolatorP interpolator;
49945e
  TTrackPointList m_points;
49945e
  const TTrackPoint m_none;
f278a5
  int m_pointsFixed;
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,
fa009d
    bool hasTilt = false,
fa009d
    double timeOffset = 0
2b429e
  );
2b429e
fa009d
  explicit TTrack(const TTrack &original, double timeOffset = 0);
fa009d
fa009d
  const TTrackInterpolatorP& getInterpolator() const
fa009d
    { return interpolator; }
fa009d
  void removeInterpolator()
fa009d
    { interpolator.reset(); }
2b429e
2b429e
  inline TTimerTicks ticks() const
2b429e
    { return keyHistory.ticks(); }
2b429e
  inline bool changed() const
f278a5
    { return pointsRemoved || pointsAdded || fixedPointsAdded; }
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); }
fa009d
  inline double clampIndexFloat(double index) const
fa009d
    { return std::min(std::max(index, 0.0), (double)(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
fa009d
    { return floorIndexNoClamp(index) + 1; }
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(); }
f278a5
  inline int fixedSize() const
f278a5
    { return m_pointsFixed; }
f278a5
  inline int previewSize() const
f278a5
    { return size() - fixedSize(); }
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; }
f278a5
  inline bool fixedFinished() const
f278a5
    { return finished() && !previewSize(); }
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; }
f278a5
  inline void resetFixedAdded() const
f278a5
    { fixedPointsAdded = 0; }
00337d
  inline void resetChanges() const
f278a5
    { resetRemoved(); resetAdded(); resetFixedAdded(); }
00337d
f278a5
  void push_back(const TTrackPoint &point, bool fixed);
2b429e
  void pop_back(int count = 1);
f278a5
  void fix_points(int count = 1);
2b429e
2b429e
  inline void truncate(int count)
2b429e
    { pop_back(size() - count); }
f278a5
  inline void fix_to(int count)
f278a5
    { fix_points(count - fixedSize()); }
f278a5
  inline void fix_all()
f278a5
    { fix_to(size()); }
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
fa009d
    { return getKeyState(rootTimeOffset + point.time); }
49945e
  inline TInputState::KeyState::Holder getCurrentKeyState() const
fa009d
    { return getKeyState(rootTimeOffset + 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
fa009d
    { return getButtonState(rootTimeOffset + point.time); }
49945e
  inline TInputState::ButtonState::Holder getCurrentButtonState() const
fa009d
    { return getButtonState(rootTimeOffset + 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
fa009d
  inline TTrackPoint calcPoint(double index) const
fa009d
    { return interpolator ? interpolator->interpolate(index) : interpolateLinear(index); }
2b429e
  TPointD calcTangent(double index, double distance = 0.1) const;
49945e
  double rootIndexByIndex(double index) const;
49945e
  TTrackPoint calcRootPoint(double index) const;
2b429e
fa009d
  inline TTrackPoint pointFromOriginal(const TTrackPoint &originalPoint, double originalIndex) const {
fa009d
    TTrackPoint p = originalPoint;
fa009d
    p.originalIndex = original ? original->clampIndexFloat(originalIndex) : originalIndex;
fa009d
    p.time -= timeOffset;
fa009d
    return p;
fa009d
  }
fa009d
  
fa009d
  inline TTrackPoint pointFromOriginal(int originalIndex) const
fa009d
    { return original ? pointFromOriginal(original->point(originalIndex), originalIndex) : TTrackPoint(); }
fa009d
  
fa009d
  inline TTrackPoint calcPointFromOriginal(double originalIndex) const
fa009d
    { return original ? pointFromOriginal(original->calcPoint(originalIndex), originalIndex) : TTrackPoint(); }
fa009d
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),
7dd550
      interpolationLinear(p0.length        , p1.length        , l),
7dd550
      p0.final && p1.final );
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),
f278a5
    //interpolationSpline(p0.pressure      , p1.pressure      , t0.pressure , t1.pressure , l),
9f0c16
      interpolationLinear(p0.tilt          , p1.tilt          , l),
f278a5
    //interpolationSpline(p0.tilt          , p1.tilt          , t0.tilt     , t1.tilt     , l),
d8eddc
      interpolationLinear(p0.originalIndex , p1.originalIndex , l),
d8eddc
      interpolationLinear(p0.time          , p1.time          , l),
7dd550
      interpolationLinear(p0.length        , p1.length        , l),
7dd550
      p0.final && p1.final );
d8eddc
  }
2b429e
};
2b429e
16421e
fa009d
fa009d
//*****************************************************************************************
fa009d
//    TTrackInterpolator implemantation
fa009d
//*****************************************************************************************
fa009d
fa009d
inline TTrackInterpolator::TTrackInterpolator(TTrack &track):
fa009d
  track(track) { track.interpolator = this; }
fa009d
fa009d
fa009d
//*****************************************************************************************
fa009d
//    TTrackIntrOrig definition
fa009d
//*****************************************************************************************
fa009d
fa009d
class DVAPI TTrackIntrOrig : public TTrackInterpolator {
fa009d
public:
fa009d
  using TTrackInterpolator::TTrackInterpolator;
fa009d
  TTrackPoint interpolate(double index) override;
fa009d
};
fa009d
fa009d
2b429e
#endif