Beispiel #1
0
void TestSpline::testSplinesAsControlPoints ()
{
  const int T_START = 1, T_STOP = 7;
  const double SPLINE_EPSILON = 0.01;
  const int NUM_T = 60;

  bool success = true;

  vector<double> t;
  vector<SplinePair> xy;
  
  // Independent variable must be evenly spaced
  t.push_back (T_START);
  t.push_back (2);
  t.push_back (3);
  t.push_back (4);
  t.push_back (5);
  t.push_back (6);
  t.push_back (T_STOP);

  // Simple curve, with x values tweaked slightly (from even spacing) to make the test data more stressing
  xy.push_back (SplinePair (1, 0.22));
  xy.push_back (SplinePair (1.8, 0.04));
  xy.push_back (SplinePair (3.2, -0.13));
  xy.push_back (SplinePair (4.3, -0.17));
  xy.push_back (SplinePair (5, -0.04));
  xy.push_back (SplinePair (5.8, 0.09));
  xy.push_back (SplinePair (7, 0.11));

  Spline s (t, xy);

  for (int i = 0; i <= NUM_T; i++) {
    double t = T_START + (double) i * (T_STOP - T_START) / (double) NUM_T;
    SplinePair spCoeff = s.interpolateCoeff (t);
    SplinePair spBezier = s.interpolateControlPoints (t);

    double xCoeff = spCoeff.x();
    double yCoeff = spCoeff.y();
    double xControl = spBezier.x();
    double yControl = spBezier.y();

    if (qAbs (xCoeff - xControl) > SPLINE_EPSILON) {
      success = false;
    }

    if (qAbs (yCoeff - yControl) > SPLINE_EPSILON) {
      success = false;
    }
  }

  QVERIFY (success);
}
Beispiel #2
0
void ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedSmooth (const DocumentModelCoords &modelCoords,
                                                                             const DocumentModelGeneral &modelGeneral,
                                                                             const MainWindowModel &modelMainWindow,
                                                                             const Points &points,
                                                                             const ExportValuesOrdinal &ordinals,
                                                                             QVector<QString*> &xThetaValues,
                                                                             QVector<QString*> &yRadiusValues,
                                                                             const Transformation &transformation) const
{
  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedSmooth";

  vector<double> t;
  vector<SplinePair> xy;
  ExportOrdinalsSmooth ordinalsSmooth;

  ordinalsSmooth.loadSplinePairsWithTransformation (points,
                                                    transformation,
                                                    t,
                                                    xy);

  // Spline class requires at least one point
  if (xy.size() > 0) {

    // Fit a spline
    Spline spline (t,
                   xy);

    FormatCoordsUnits format;

    // Extract the points
    for (int row = 0; row < ordinals.count(); row++) {

      double ordinal = ordinals.at (row);
      SplinePair splinePairFound = spline.interpolateCoeff(ordinal);
      double xTheta = splinePairFound.x ();
      double yRadius = splinePairFound.y ();

      // Save values for this row into xThetaValues and yRadiusValues, after appropriate formatting
      format.unformattedToFormatted (xTheta,
                                     yRadius,
                                     modelCoords,
                                     modelGeneral,
                                     modelMainWindow,
                                     *(xThetaValues [row]),
                                     *(yRadiusValues [row]),
                                     transformation);
    }
  }
}
ExportValuesOrdinal ExportOrdinalsSmooth::ordinalsAtIntervalsGraph (const vector<double> &t,
                                                                    const vector<SplinePair> &xy,
                                                                    double pointsInterval) const
{
  LOG4CPP_INFO_S ((*mainCat)) << "ExportOrdinalsSmooth::ordinalsAtIntervalsGraph";

  const double NUM_SMALLER_INTERVALS = 1000;

  // Results. Initially empty, but at the end it will have tMin, ..., tMax
  ExportValuesOrdinal ordinals;

  // Fit a spline
  Spline spline (t,
                 xy);

  // Integrate the distances for the subintervals
  double integratedSeparation = 0;
  QPointF posLast (xy [0].x(),
                   xy [0].y());

  // Simplest method to find the intervals is to break up the curve into many smaller intervals, and then aggregate them
  // into intervals that, as much as possible, have the desired length. Simplicity wins out over accuracy in this
  // approach - accuracy is sacrificed to achieve simplicity
  double tMin = t.front();
  double tMax = t.back();

  double tLast = 0.0;
  int iTLastInterval = 0;
  for (int iT = 0; iT < NUM_SMALLER_INTERVALS; iT++) {

    double t = tMin + ((tMax - tMin) * iT) / (NUM_SMALLER_INTERVALS - 1.0);

    SplinePair pairNew = spline.interpolateCoeff(t);

    QPointF posNew = QPointF (pairNew.x(),
                              pairNew.y());

    QPointF posDelta = posNew - posLast;
    double integratedSeparationDelta = qSqrt (posDelta.x() * posDelta.x() + posDelta.y() * posDelta.y());
    integratedSeparation += integratedSeparationDelta;

    while (integratedSeparation >= pointsInterval) {

      // End of current interval, and start of next interval. For better accuracy without having to crank up
      // the number of points by orders of magnitude, we use linear interpolation
      double sInterp;
      if (iT == 0) {
        sInterp = 0.0;
      } else {
        sInterp = (double) pointsInterval / (double) integratedSeparation;
      }
      double tInterp = (1.0 - sInterp) * tLast + sInterp * t;

      integratedSeparation -= pointsInterval; // Part of delta that was not used gets applied to next interval

      tLast = tInterp;
      ordinals.push_back (tInterp);
      iTLastInterval = iT;
    }

    tLast = t;
    posLast = posNew;
  }

  if (iTLastInterval < NUM_SMALLER_INTERVALS - 1) {

    // Add last point so we end up at tMax
    ordinals.push_back (tMax);

  }

  return ordinals;
}