2 #include "EngaugeAssert.h"
4 #include "GraphicsArcItem.h"
8 #include <QGraphicsScene>
11 #include <QTextStream>
12 #include "QtToString.h"
13 #include "Transformation.h"
15 const int NUM_AXES_POINTS = 3;
17 const QString DUMMY_CURVENAME (
"dummy");
18 const int Z_VALUE_IN_FRONT = 100;
19 const int NO_SIDE = -1;
22 const double CHECKER_OPACITY = 0.6;
27 const int CHECKER_POINTS_WIDTH = 5;
29 const double PI = 3.1415926535;
30 const double TWO_PI = 2.0 * PI;
31 const double DEGREES_TO_RADIANS = PI / 180.0;
32 const double RADIANS_TO_TICS = 5760 / TWO_PI;
33 const double RADIANS_TO_DEGREES = 180.0 / PI;
42 const QList<Point> &points,
47 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::adjustPolarAngleRanges transformation=" << transformation;
49 const double UNIT_LENGTH = 1.0;
52 if (modelCoords.
coordsType() == COORDS_TYPE_POLAR) {
57 path = QString (
"yMin=%1 ").arg (yMin);
61 double angle0 = points.at(0).posGraph().x();
62 double angle1 = points.at(1).posGraph().x();
63 double angle2 = points.at(2).posGraph().x();
65 QPointF (angle0, UNIT_LENGTH));
67 QPointF (angle1, UNIT_LENGTH));
69 QPointF (angle2, UNIT_LENGTH));
73 double sumAngle0 = angleBetweenVectors(pos0, pos1) + angleBetweenVectors(pos0, pos2);
74 double sumAngle1 = angleBetweenVectors(pos1, pos0) + angleBetweenVectors(pos1, pos2);
75 double sumAngle2 = angleBetweenVectors(pos2, pos0) + angleBetweenVectors(pos2, pos1);
76 if ((sumAngle0 <= sumAngle1) && (sumAngle0 <= sumAngle2)) {
79 if ((angleFromVectorToVector (pos0, pos1) < 0) ||
80 (angleFromVectorToVector (pos0, pos2) > 0)) {
81 path += QString (
"from 1=%1 through 0 to 2=%2").arg (angle1).arg (angle2);
85 path += QString (
"from 2=%1 through 0 to 1=%2").arg (angle2).arg (angle1);
89 }
else if ((sumAngle1 <= sumAngle0) && (sumAngle1 <= sumAngle2)) {
92 if ((angleFromVectorToVector (pos1, pos0) < 0) ||
93 (angleFromVectorToVector (pos1, pos2) > 0)) {
94 path += QString (
"from 0=%1 through 1 to 2=%2").arg (angle0).arg (angle2);
98 path += QString (
"from 2=%1 through 1 to 0=%2").arg (angle2).arg (angle0);
105 if ((angleFromVectorToVector (pos2, pos0) < 0) ||
106 (angleFromVectorToVector (pos2, pos1) > 0)) {
107 path += QString (
"from 0=%1 through 2 to 1=%2").arg (angle0).arg (angle1);
111 path += QString (
"from 1=%1 through 2 to 0=%2").arg (angle1).arg (angle0);
118 while (xMax < xMin) {
122 path += QString (
" xMax+=%1").arg (thetaPeriod);
128 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::adjustPolarAngleRanges path=(" << path.toLatin1().data() <<
")";
131 void Checker::bindItemToScene(QGraphicsItem *item)
const
133 LOG4CPP_DEBUG_S ((*mainCat)) <<
"Checker::bindItemToScene";
135 item->setOpacity (CHECKER_OPACITY);
136 item->setZValue (Z_VALUE_IN_FRONT);
137 item->setToolTip (QObject::tr (
"Axes checker. If this does not align with the axes, then the axes points should be checked"));
139 m_scene.addItem (item);
142 void Checker::createSide (
int pointRadius,
143 const QList<Point> &points,
150 SideSegments &sideSegments)
152 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::createSide"
153 <<
" pointRadius=" << pointRadius
154 <<
" xFrom=" << xFrom
155 <<
" yFrom=" << yFrom
158 <<
" transformation=" << transformation;
169 const int NUM_STEPS = 1000;
171 bool stateSegmentIsActive =
false;
172 QPointF posStartScreen (0, 0);
175 for (
int i = 0; i <= NUM_STEPS; i++) {
177 double s = (double) i / (
double) NUM_STEPS;
180 double xGraph = (1.0 - s) * xFrom + s * xTo;
181 double yGraph = (1.0 - s) * yFrom + s * yTo;
185 xGraph = qExp ((1.0 - s) * qLn (xFrom) + s * qLn (xTo));
188 yGraph = qExp ((1.0 - s) * qLn (yFrom) + s * qLn (yTo));
192 transformation.transformRawGraphToScreen (QPointF (xGraph, yGraph),
195 double distanceToNearestPoint = minScreenDistanceFromPoints (pointScreen,
197 if ((distanceToNearestPoint < pointRadius) ||
201 if (stateSegmentIsActive) {
204 finishActiveSegment (modelCoords,
211 stateSegmentIsActive =
false;
217 if (!stateSegmentIsActive) {
220 stateSegmentIsActive =
true;
221 posStartScreen = pointScreen;
228 void Checker::createTransformAlign (
const Transformation &transformation,
229 double radiusLinearCartesian,
230 const QPointF &posOriginScreen,
231 QTransform &transformAlign,
232 double &ellipseXAxis,
233 double &ellipseYAxis)
const
246 QPointF posXRadiusY0Graph (radiusLinearCartesian, 0), posX0YRadiusGraph (0, radiusLinearCartesian);
247 QPointF posXRadiusY0Screen, posX0YRadiusScreen;
254 QPointF deltaXRadiusY0 = posXRadiusY0Screen - posOriginScreen;
255 QPointF deltaX0YRadius = posX0YRadiusScreen - posOriginScreen;
256 ellipseXAxis = qSqrt (deltaXRadiusY0.x () * deltaXRadiusY0.x () +
257 deltaXRadiusY0.y () * deltaXRadiusY0.y ());
258 ellipseYAxis = qSqrt (deltaX0YRadius.x () * deltaX0YRadius.x () +
259 deltaX0YRadius.y () * deltaX0YRadius.y ());
262 QPointF posXRadiusY0AlignedScreen (posOriginScreen.x() + ellipseXAxis, posOriginScreen.y());
263 QPointF posX0YRadiusAlignedScreen (posOriginScreen.x(), posOriginScreen.y() - ellipseYAxis);
269 posXRadiusY0AlignedScreen,
270 posX0YRadiusAlignedScreen);
272 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::createTransformAlign"
273 <<
" transformation=" << QTransformToString (transformation.
transformMatrix()).toLatin1().data() << endl
274 <<
" radiusLinearCartesian=" << radiusLinearCartesian
275 <<
" posXRadiusY0Screen=" << QPointFToString (posXRadiusY0Screen).toLatin1().data()
276 <<
" posX0YRadiusScreen=" << QPointFToString (posX0YRadiusScreen).toLatin1().data()
277 <<
" ellipseXAxis=" << ellipseXAxis
278 <<
" ellipseYAxis=" << ellipseYAxis
279 <<
" posXRadiusY0AlignedScreen=" << QPointFToString (posXRadiusY0AlignedScreen).toLatin1().data()
280 <<
" posX0YRadiusAlignedScreen=" << QPointFToString (posX0YRadiusAlignedScreen).toLatin1().data()
281 <<
" transformAlign=" << QTransformToString (transformAlign).toLatin1().data();
284 void Checker::deleteSide (SideSegments &sideSegments)
286 for (
int i = 0; i < sideSegments.count(); i++) {
287 QGraphicsItem *item = sideSegments [i];
293 sideSegments.clear();
296 QGraphicsItem *Checker::ellipseItem(
const Transformation &transformation,
297 double radiusLinearCartesian,
298 const QPointF &posStartScreen,
299 const QPointF &posEndScreen)
const
303 QPointF posStartGraph, posEndGraph;
311 double angleStart = posStartGraph.x() * DEGREES_TO_RADIANS;
312 double angleEnd = posEndGraph.x() * DEGREES_TO_RADIANS;
313 if (angleEnd < angleStart) {
316 double angleSpan = angleEnd - angleStart;
319 QPointF posOriginGraph (0, 0), posOriginScreen;
323 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::ellipseItem"
324 <<
" radiusLinearCartesian=" << radiusLinearCartesian
325 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
326 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data()
327 <<
" posOriginScreen=" << QPointFToString (posOriginScreen).toLatin1().data()
328 <<
" angleStart=" << angleStart / DEGREES_TO_RADIANS
329 <<
" angleEnd=" << angleEnd / DEGREES_TO_RADIANS
330 <<
" transformation=" << transformation;
335 double ellipseXAxis, ellipseYAxis;
336 QTransform transformAlign;
337 createTransformAlign (transformation,
338 radiusLinearCartesian,
345 QRectF boundingRect (-1.0 * ellipseXAxis + posOriginScreen.x(),
346 -1.0 * ellipseYAxis + posOriginScreen.y(),
350 item->setStartAngle (angleStart * RADIANS_TO_TICS);
351 item->setSpanAngle (angleSpan * RADIANS_TO_TICS);
353 item->setTransform (transformAlign.transposed ().inverted ());
359 const QPointF &posStartScreen,
360 const QPointF &posEndScreen,
364 SideSegments &sideSegments)
const
366 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::finishActiveSegment"
367 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
368 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data()
369 <<
" yFrom=" << yFrom
373 if ((modelCoords.
coordsType() == COORDS_TYPE_POLAR) &&
377 double radiusLinearCartesian = yFrom;
386 item = ellipseItem (transformation,
387 radiusLinearCartesian,
394 item = lineItem (posStartScreen,
398 sideSegments.push_back (item);
399 bindItemToScene (item);
402 QGraphicsItem *Checker::lineItem (
const QPointF &posStartScreen,
403 const QPointF &posEndScreen)
const
405 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::lineItem"
406 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
407 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data();
409 return new QGraphicsLineItem (QLineF (posStartScreen,
413 double Checker::minScreenDistanceFromPoints (
const QPointF &posScreen,
414 const QList<Point> &points)
416 double minDistance = 0;
417 for (
int i = 0; i < points.count (); i++) {
418 const Point &pointCenter = points.at (i);
420 double dx = posScreen.x() - pointCenter.
posScreen().x();
421 double dy = posScreen.y() - pointCenter.
posScreen().y();
423 double distance = qSqrt (dx * dx + dy * dy);
424 if (i == 0 || distance < minDistance) {
425 minDistance = distance;
437 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::prepareForDisplay";
439 ENGAUGE_ASSERT (polygon.count () == NUM_AXES_POINTS);
444 QPolygonF::const_iterator itr;
445 for (itr = polygon.begin (); itr != polygon.end (); itr++) {
447 const QPointF &pF = *itr;
449 Point p (DUMMY_CURVENAME,
452 points.push_back (p);
471 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::prepareForDisplay "
472 <<
" transformation=" << transformation;
474 ENGAUGE_ASSERT (points.count () == NUM_AXES_POINTS);
477 deleteSide (m_sideLeft);
478 deleteSide (m_sideTop);
479 deleteSide (m_sideRight);
480 deleteSide (m_sideBottom);
483 double xFrom, xTo, yFrom, yTo;
485 for (i = 0; i < NUM_AXES_POINTS; i++) {
487 xFrom = points.at(i).posGraph().x();
488 xTo = points.at(i).posGraph().x();
489 yFrom = points.at(i).posGraph().y();
490 yTo = points.at(i).posGraph().y();
492 xFrom = qMin (xFrom, points.at(i).posGraph().x());
493 xTo = qMax (xTo , points.at(i).posGraph().x());
494 yFrom = qMin (yFrom, points.at(i).posGraph().y());
495 yTo = qMax (yTo , points.at(i).posGraph().y());
500 adjustPolarAngleRanges (modelCoords,
508 createSide (pointRadius, points, modelCoords, xFrom, yFrom, xFrom, yTo , transformation, m_sideLeft);
509 createSide (pointRadius, points, modelCoords, xFrom, yTo , xTo , yTo , transformation, m_sideTop);
510 createSide (pointRadius, points, modelCoords, xTo , yTo , xTo , yFrom, transformation, m_sideRight);
511 createSide (pointRadius, points, modelCoords, xTo , yFrom, xFrom, yFrom, transformation, m_sideBottom);
516 void Checker::setLineColor (SideSegments &sideSegments,
519 for (
int i = 0; i < sideSegments.count(); i++) {
520 QGraphicsItem *item = sideSegments [i];
524 QGraphicsLineItem *itemLine =
dynamic_cast<QGraphicsLineItem*
> (item);
525 QGraphicsEllipseItem *itemArc =
dynamic_cast<QGraphicsEllipseItem*
> (item);
527 itemLine->setPen (pen);
528 }
else if (itemArc != 0) {
529 itemArc->setPen (pen);
537 setVisibleSide (m_sideLeft, visible);
538 setVisibleSide (m_sideTop, visible);
539 setVisibleSide (m_sideRight, visible);
540 setVisibleSide (m_sideBottom, visible);
543 void Checker::setVisibleSide (SideSegments &sideSegments,
546 for (
int i = 0; i < sideSegments.count(); i++) {
547 QGraphicsItem *item = sideSegments [i];
549 item->setVisible (visible);
556 QColor color = ColorPaletteToQColor (modelAxesChecker.
lineColor());
557 QPen pen (QBrush (color), CHECKER_POINTS_WIDTH);
559 setLineColor (m_sideLeft, pen);
560 setLineColor (m_sideTop, pen);
561 setLineColor (m_sideRight, pen);
562 setLineColor (m_sideBottom, pen);
virtual void updateModelAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Apply the new DocumentModelAxesChecker, to the points already associated with this object...
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
double originRadius() const
Get method for origin radius in polar mode.
Draw an arc as an ellipse but without lines from the center to the start and end points.
ColorPalette lineColor() const
Get method for line color.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
QPointF posScreen() const
Accessor for screen position.
double thetaPeriod() const
Return the period of the theta value for polar coordinates, consistent with CoordThetaUnits.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
CoordsType coordsType() const
Get method for coordinates type.
Model for DlgSettingsCoords and CmdSettingsCoords.
Model for DlgSettingsAxesChecker and CmdSettingsAxesChecker.
Checker(QGraphicsScene &scene)
Single constructor for DlgSettingsAxesChecker, which does not have an explicit transformation. The identity transformation is assumed.
void setVisible(bool visible)
Show/hide this axes checker.
void prepareForDisplay(const QPolygonF &polygon, int pointRadius, const DocumentModelAxesChecker &modelAxesChecker, const DocumentModelCoords &modelCoords)
Create the polygon from current information, including pixel coordinates, just prior to display...