Blob Blame Raw


#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;
  if (i0 >= 0) {
    // calculate tangent length to make monotonic subdivisions,
    // (because we don't have valid input time)
    const TTrackPoint &p0 = original[i0];
    const TTrackPoint &p1 = original[i1];
    TTrackTangent t0 = i0 < (int)tangents.size() ? tangents[i0] : TTrackTangent();
    TTrackTangent t1 = i1 < (int)tangents.size() ? tangents[i1] : TTrackTangent();
    double l = fabs(p1.length - p0.length);
    t0.position.x *= l;
    t0.position.y *= l;
    t1.position.x *= l;
    t1.position.y *= l;
    p = TTrack::interpolationSpline(p0, p1, t0, t1, frac);
  }
  p.originalIndex = originalIndex;
  return p;
}


//*****************************************************************************************
//    TModifierTangents implementation
//*****************************************************************************************


TTrackTangent
TModifierTangents::calcLastTangent(const TTrack &track) const {
  if (track.size() < 2) return TTrackTangent();
  const TTrackPoint &p0 = track[track.size() - 2];
  const TTrackPoint &p1 = track.back();

  // calculate tangent (with normalized position)
  // with valid points time normalization does not required
  double dl = p1.length - p0.length;
  return TTrackTangent(
    dl > TConsts::epsilon ? (p1.position - p0.position)*(1.0/dl) : TPointD(),
    p1.pressure - p0.pressure,
    p1.tilt - p0.tilt );
}


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(calcLastTangent(track));
    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
    if (track.size() > 2) {
      while(index < track.size() - 1) {
        const TTrackPoint &p0 = track[index-1];
        const TTrackPoint &p1 = track[index];
        const TTrackPoint &p2 = track[index+1];

        // calculate tangents length by time
        // for that we need read time of user input
        // instead of time when message dispatched
        //double dt = p2.time - p0.time;
        //double k = dt > TConsts::epsilon ? (p1.time - p0.time)/dt : 0.0;
        //TTrackTangent tangent(
        //  (p2.position - p0.position)*k,
        //  (p2.pressure - p0.pressure)*k,
        //  (p2.tilt - p0.tilt)*k );
        
        // calculate tangent (with normalized position)
        TPointD d = p2.position - p0.position;
        double k = norm2(d);
        k = k > TConsts::epsilon*TConsts::epsilon ? 1.0/sqrt(k) : 0.0;
        TTrackTangent tangent(
          d*k,
          (p2.pressure - p0.pressure)*0.5,
          (p2.tilt - p0.tilt)*0.5 );
        
        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(calcLastTangent(track));
      subTrack.push_back(track.back());
    } else {
      // save key point
      modifier->savePoint = savePoint;
    }
  }
}