Пример #1
0
void Checker::finishActiveSegment (const DocumentModelCoords &modelCoords,
                                   const QPointF &posStartScreen,
                                   const QPointF &posEndScreen,
                                   double yFrom,
                                   double yTo,
                                   const Transformation &transformation,
                                   SideSegments &sideSegments) const
{
  LOG4CPP_INFO_S ((*mainCat)) << "Checker::finishActiveSegment"
                              << " posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
                              << " posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data()
                              << " yFrom=" << yFrom
                              << " yTo=" << yTo;

  QGraphicsItem *item;
  if ((modelCoords.coordsType() == COORDS_TYPE_POLAR) &&
      (yFrom == yTo)) {

    // Linear cartesian radius
    double radiusLinearCartesian = yFrom;
    if (modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
      radiusLinearCartesian = transformation.logToLinearRadius(yFrom,
                                                               modelCoords.originRadius());
    } else {
      radiusLinearCartesian -= modelCoords.originRadius();
    }

    // Draw along an arc since this is a side of constant radius, and we have polar coordinates
    item = ellipseItem (transformation,
                        radiusLinearCartesian,
                        posStartScreen,
                        posEndScreen);

  } else {

    // Draw straight line
    item = lineItem (posStartScreen,
                     posEndScreen);
  }

  sideSegments.push_back (item);
  bindItemToScene (item);
}
QPointF Transformation::cartesianFromCartesianOrPolar (const DocumentModelCoords &modelCoords,
                                                       const QPointF &posGraphIn)
{
  // Initialize assuming input coordinates are already cartesian
  QPointF posGraphCartesian = posGraphIn;

  if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {

    // Input coordinates are polar so convert them
    double angleRadians = 0; // Initialized to prevent compiler warning
    switch (modelCoords.coordUnitsTheta())
    {
      case COORD_UNITS_POLAR_THETA_DEGREES:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
        angleRadians = posGraphIn.x () * PI / 180.0;
        break;

      case COORD_UNITS_POLAR_THETA_GRADIANS:
        angleRadians = posGraphIn.x () * PI / 200.0;
        break;

      case COORD_UNITS_POLAR_THETA_RADIANS:
        angleRadians = posGraphIn.x ();
        break;

      case COORD_UNITS_POLAR_THETA_TURNS:
        angleRadians = posGraphIn.x () * 2.0 * PI;
        break;

      default:
        ENGAUGE_ASSERT (false);
    }

    double radius = posGraphIn.y ();
    posGraphCartesian.setX (radius * cos (angleRadians));
    posGraphCartesian.setY (radius * sin (angleRadians));
  }

  return posGraphCartesian;
}
QPointF Transformation::cartesianOrPolarFromCartesian (const DocumentModelCoords &modelCoords,
                                                       const QPointF &posGraphIn)
{
  // Initialize assuming output coordinates are to be cartesian
  QPointF posGraphCartesianOrPolar = posGraphIn;

  if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {

    // Output coordinates are to be polar so convert them
    double angleRadians = qAtan2 (posGraphIn.y (),
                                  posGraphIn.x ());
    switch (modelCoords.coordUnitsTheta())
    {
      case COORD_UNITS_POLAR_THETA_DEGREES:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS:
      case COORD_UNITS_POLAR_THETA_DEGREES_MINUTES_SECONDS_NSEW:
        posGraphCartesianOrPolar.setX (angleRadians * 180.0 / PI);
        break;

      case COORD_UNITS_POLAR_THETA_GRADIANS:
        posGraphCartesianOrPolar.setX (angleRadians * 200.0 / PI);
        break;

      case COORD_UNITS_POLAR_THETA_RADIANS:
        posGraphCartesianOrPolar.setX (angleRadians);
        break;

      case COORD_UNITS_POLAR_THETA_TURNS:
        posGraphCartesianOrPolar.setX (angleRadians / 2.0 / PI);
        break;

      default:
        ENGAUGE_ASSERT (false);
    }

    double radius = qSqrt (posGraphIn.x () * posGraphIn.x () + posGraphIn.y () * posGraphIn.y ());
    posGraphCartesianOrPolar.setY (radius);
  }

  return posGraphCartesianOrPolar;
}
double ExportFileAbstractBase::linearlyInterpolateYRadiusFromTwoPoints (double xThetaValue,
                                                                        const DocumentModelCoords &modelCoords,
                                                                        const QPointF &posGraphBefore,
                                                                        const QPointF &posGraph) const
{
    // X coordinate scaling is linear or log
    double s;
    if (modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR) {
        s = (xThetaValue - posGraphBefore.x()) / (posGraph.x() - posGraphBefore.x());
    } else {
        s = (qLn (xThetaValue) - qLn (posGraphBefore.x())) / (qLn (posGraph.x()) - qLn (posGraphBefore.x()));
    }

    // Y coordinate scaling is linear or log
    double yRadius;
    if (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR) {
        yRadius = (1.0 - s) * posGraphBefore.y() + s * posGraph.y();
    } else {
        yRadius = qExp ((1.0 - s) * qLn (posGraphBefore.y()) + s * qLn (posGraph.y()));
    }

    return yRadius;
}
Пример #5
0
void FormatCoordsUnits::unformattedToFormatted (double xThetaUnformatted,
                                                double yRadiusUnformatted,
                                                const DocumentModelCoords &modelCoords,
                                                QString &xThetaFormatted,
                                                QString &yRadiusFormatted,
                                                const Transformation &transformation) const
{
  LOG4CPP_DEBUG_S ((*mainCat)) << "FormatCoordsUnits::unformattedToFormatted";

  FormatCoordsUnitsStrategyNonPolarTheta formatNonPolarTheta;
  FormatCoordsUnitsStrategyPolarTheta formatPolarTheta;

  if (modelCoords.coordsType() == COORDS_TYPE_CARTESIAN) {

    xThetaFormatted = formatNonPolarTheta.unformattedToFormatted (xThetaUnformatted,
                                                                  modelCoords.coordUnitsX(),
                                                                  modelCoords.coordUnitsDate(),
                                                                  modelCoords.coordUnitsTime(),
                                                                  IS_X_THETA,
                                                                  transformation,
                                                                  yRadiusUnformatted);
    yRadiusFormatted = formatNonPolarTheta.unformattedToFormatted (yRadiusUnformatted,
                                                                   modelCoords.coordUnitsY(),
                                                                   modelCoords.coordUnitsDate(),
                                                                   modelCoords.coordUnitsTime(),
                                                                   IS_NOT_X_THETA,
                                                                   transformation,
                                                                   xThetaUnformatted);
    
  } else {
    
    xThetaFormatted = formatPolarTheta.unformattedToFormatted (xThetaUnformatted,
                                                               modelCoords.coordUnitsTheta(),
                                                               transformation,
                                                               yRadiusUnformatted);
    yRadiusFormatted = formatNonPolarTheta.unformattedToFormatted (yRadiusUnformatted,
                                                                   modelCoords.coordUnitsRadius(),
                                                                   modelCoords.coordUnitsDate(),
                                                                   modelCoords.coordUnitsTime(),
                                                                   IS_NOT_X_THETA,
                                                                   transformation,
                                                                   xThetaUnformatted);
  }
}
Пример #6
0
void FormatCoordsUnits::formattedToUnformatted (const QString &xThetaFormatted,
                                                const QString &yRadiusFormatted,
                                                const DocumentModelCoords &modelCoords,
                                                double &xThetaUnformatted,
                                                double &yRadiusUnformatted) const
{
  LOG4CPP_DEBUG_S ((*mainCat)) << "FormatCoordsUnits::formattedToUnformatted";

  FormatCoordsUnitsStrategyNonPolarTheta formatNonPolarTheta;
  FormatCoordsUnitsStrategyPolarTheta formatPolarTheta;

  if (modelCoords.coordsType() == COORDS_TYPE_CARTESIAN) {

    xThetaUnformatted = formatNonPolarTheta.formattedToUnformatted (xThetaFormatted,
                                                                    modelCoords.coordUnitsX(),
                                                                    modelCoords.coordUnitsDate(),
                                                                    modelCoords.coordUnitsTime());
    yRadiusUnformatted = formatNonPolarTheta.formattedToUnformatted (yRadiusFormatted,
                                                                     modelCoords.coordUnitsY(),
                                                                     modelCoords.coordUnitsDate(),
                                                                     modelCoords.coordUnitsTime());

  } else {

    xThetaUnformatted = formatPolarTheta.formattedToUnformatted (xThetaFormatted,
                                                                 modelCoords.coordUnitsTheta());
    yRadiusUnformatted = formatNonPolarTheta.formattedToUnformatted (yRadiusFormatted,
                                                                     modelCoords.coordUnitsRadius(),
                                                                     modelCoords.coordUnitsDate(),
                                                                     modelCoords.coordUnitsTime());

  }
}
Пример #7
0
void Checker::adjustPolarAngleRanges (const DocumentModelCoords &modelCoords,
                                      const Transformation &transformation,
                                      const QList<Point> &points,
                                      double &xMin,
                                      double &xMax,
                                      double &yMin) const
{
    LOG4CPP_INFO_S ((*mainCat)) << "Checker::adjustPolarAngleRanges transformation=" << transformation;

    const double UNIT_LENGTH = 1.0;

    QString path; // For logging
    if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {

        // Range minimum is at origin
        yMin = modelCoords.originRadius();

        path = QString ("yMin=%1 ").arg (yMin); // For logging

        // Perform special processing to account for periodicity of polar coordinates. Start with unit vectors
        // in the directions of the three axis points
        double angle0 = points.at(0).posGraph().x();
        double angle1 = points.at(1).posGraph().x();
        double angle2 = points.at(2).posGraph().x();
        QPointF pos0 = transformation.cartesianFromCartesianOrPolar(modelCoords,
                       QPointF (angle0, UNIT_LENGTH));
        QPointF pos1 = transformation.cartesianFromCartesianOrPolar(modelCoords,
                       QPointF (angle1, UNIT_LENGTH));
        QPointF pos2 = transformation.cartesianFromCartesianOrPolar(modelCoords,
                       QPointF (angle2, UNIT_LENGTH));

        // Identify the axis point that is more in the center of the other two axis points. The arc is then drawn
        // from one of the other two points to the other. Center point has smaller angles with the other points
        double sumAngle0 = angleBetweenVectors(pos0, pos1) + angleBetweenVectors(pos0, pos2);
        double sumAngle1 = angleBetweenVectors(pos1, pos0) + angleBetweenVectors(pos1, pos2);
        double sumAngle2 = angleBetweenVectors(pos2, pos0) + angleBetweenVectors(pos2, pos1);
        if ((sumAngle0 <= sumAngle1) && (sumAngle0 <= sumAngle2)) {

            // Point 0 is in the middle. Either or neither of points 1 and 2 may be along point 0
            if ((angleFromVectorToVector (pos0, pos1) < 0) ||
                    (angleFromVectorToVector (pos0, pos2) > 0)) {
                path += QString ("from 1=%1 through 0 to 2=%2").arg (angle1).arg (angle2);
                xMin = angle1;
                xMax = angle2;
            } else {
                path += QString ("from 2=%1 through 0 to 1=%2").arg (angle2).arg (angle1);
                xMin = angle2;
                xMax = angle1;
            }
        } else if ((sumAngle1 <= sumAngle0) && (sumAngle1 <= sumAngle2)) {

            // Point 1 is in the middle. Either or neither of points 0 and 2 may be along point 1
            if ((angleFromVectorToVector (pos1, pos0) < 0) ||
                    (angleFromVectorToVector (pos1, pos2) > 0)) {
                path += QString ("from 0=%1 through 1 to 2=%2").arg (angle0).arg (angle2);
                xMin = angle0;
                xMax = angle2;
            } else {
                path += QString ("from 2=%1 through 1 to 0=%2").arg (angle2).arg (angle0);
                xMin = angle2;
                xMax = angle0;
            }
        } else {

            // Point 2 is in the middle. Either or neither of points 0 and 1 may be along point 2
            if ((angleFromVectorToVector (pos2, pos0) < 0) ||
                    (angleFromVectorToVector (pos2, pos1) > 0)) {
                path += QString ("from 0=%1 through 2 to 1=%2").arg (angle0).arg (angle1);
                xMin = angle0;
                xMax = angle1;
            } else {
                path += QString ("from 1=%1 through 2 to 0=%2").arg (angle1).arg (angle0);
                xMin = angle1;
                xMax = angle0;
            }
        }

        // Make sure theta is increasing
        while (xMax < xMin) {

            double thetaPeriod = modelCoords.thetaPeriod();

            path += QString (" xMax+=%1").arg (thetaPeriod);
            xMax += thetaPeriod;

        }
    }

    LOG4CPP_INFO_S ((*mainCat)) << "Checker::adjustPolarAngleRanges path=(" << path.toLatin1().data() << ")";
}
Пример #8
0
void Checker::createSide (int pointRadius,
                          const QList<Point> &points,
                          const DocumentModelCoords &modelCoords,
                          double xFrom,
                          double yFrom,
                          double xTo,
                          double yTo,
                          const Transformation &transformation,
                          SideSegments &sideSegments)
{
  LOG4CPP_INFO_S ((*mainCat)) << "Checker::createSide"
                              << " pointRadius=" << pointRadius
                              << " xFrom=" << xFrom
                              << " yFrom=" << yFrom
                              << " xTo=" << xTo
                              << " yTo=" << yTo
                              << " transformation=" << transformation;

  // Originally a complicated algorithm tried to intercept a straight line from (xFrom,yFrom) to (xTo,yTo). That did not work well since:
  // 1) Calculations for mostly orthogonal cartesian coordinates worked less well with non-orthogonal polar coordinates
  // 2) Ambiguity in polar coordinates between the shorter and longer paths between (theta0,radius) and (theta1,radius)
  //
  // Current algorithm breaks up the interval between (xMin,yMin) and (xMax,yMax) into many smaller pieces and stitches the
  // desired pieces together. For straight lines in linear graphs this algorithm is very much overkill, but there is no significant
  // penalty and this approach works in every situation

  // Should give single-pixel resolution on most images, and 'good enough' resolution on extremely large images
  const int NUM_STEPS = 1000;

  bool stateSegmentIsActive = false;
  QPointF posStartScreen (0, 0);

  // Loop through steps. Final step i=NUM_STEPS does final processing if a segment is active
  for (int i = 0; i <= NUM_STEPS; i++) {

    double s = (double) i / (double) NUM_STEPS;

    // Interpolate coordinates assuming normal linear scaling
    double xGraph = (1.0 - s) * xFrom + s * xTo;
    double yGraph = (1.0 - s) * yFrom + s * yTo;

    // Replace interpolated coordinates using log scaling if appropriate, preserving the same ranges
    if (modelCoords.coordScaleXTheta() == COORD_SCALE_LOG) {
      xGraph = qExp ((1.0 - s) * qLn (xFrom) + s * qLn (xTo));
    }
    if (modelCoords.coordScaleYRadius() == COORD_SCALE_LOG) {
      yGraph = qExp ((1.0 - s) * qLn (yFrom) + s * qLn (yTo));
    }

    QPointF pointScreen;
    transformation.transformRawGraphToScreen (QPointF (xGraph, yGraph),
                                              pointScreen);

    double distanceToNearestPoint = minScreenDistanceFromPoints (pointScreen,
                                                                 points);
    if ((distanceToNearestPoint < pointRadius) ||
        (i == NUM_STEPS)) {

        // Too close to point, so point is not included in side. Or this is the final iteration of the loop
      if (stateSegmentIsActive) {

        // State transition
        finishActiveSegment (modelCoords,
                             posStartScreen,
                             pointScreen,
                             yFrom,
                             yTo,
                             transformation,
                             sideSegments);
        stateSegmentIsActive = false;

      }
    } else {

      // Outside point, so include point in side
      if (!stateSegmentIsActive) {

        // State transition
        stateSegmentIsActive = true;
        posStartScreen = pointScreen;

      }
    }
  }
}