8#include "EngaugeAssert.h"
10#include "GraphicsArcItem.h"
14#include <QGraphicsScene>
18#include "QtToString.h"
19#include "Transformation.h"
21const int NUM_AXES_POINTS_3 = 3;
22const int NUM_AXES_POINTS_4 = 4;
24extern const QString DUMMY_CURVE_NAME;
25const int Z_VALUE_IN_FRONT = 100;
28const double CHECKER_OPACITY = 0.6;
33const int CHECKER_POINTS_WIDTH = 5;
35const double PI = 3.1415926535;
36const double TWO_PI = 2.0 * PI;
37const double DEGREES_TO_RADIANS = PI / 180.0;
38const double RADIANS_TO_TICS = 5760 / TWO_PI;
47 const QList<Point> &points,
52 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::adjustPolarAngleRanges transformation=" << transformation;
54 const double UNIT_LENGTH = 1.0;
57 if (modelCoords.
coordsType() == COORDS_TYPE_POLAR) {
62 path = QString (
"yMin=%1 ").arg (yMin);
66 double angle0 = points.at(0).posGraph().x();
67 double angle1 = points.at(1).posGraph().x();
68 double angle2 = points.at(2).posGraph().x();
70 QPointF (angle0, UNIT_LENGTH));
72 QPointF (angle1, UNIT_LENGTH));
74 QPointF (angle2, UNIT_LENGTH));
78 double sumAngle0 = angleBetweenVectors(pos0, pos1) + angleBetweenVectors(pos0, pos2);
79 double sumAngle1 = angleBetweenVectors(pos1, pos0) + angleBetweenVectors(pos1, pos2);
80 double sumAngle2 = angleBetweenVectors(pos2, pos0) + angleBetweenVectors(pos2, pos1);
81 if ((sumAngle0 <= sumAngle1) && (sumAngle0 <= sumAngle2)) {
84 if ((angleFromVectorToVector (pos0, pos1) < 0) ||
85 (angleFromVectorToVector (pos0, pos2) > 0)) {
86 path += QString (
"from 1=%1 through 0 to 2=%2").arg (angle1).arg (angle2);
90 path += QString (
"from 2=%1 through 0 to 1=%2").arg (angle2).arg (angle1);
94 }
else if ((sumAngle1 <= sumAngle0) && (sumAngle1 <= sumAngle2)) {
97 if ((angleFromVectorToVector (pos1, pos0) < 0) ||
98 (angleFromVectorToVector (pos1, pos2) > 0)) {
99 path += QString (
"from 0=%1 through 1 to 2=%2").arg (angle0).arg (angle2);
103 path += QString (
"from 2=%1 through 1 to 0=%2").arg (angle2).arg (angle0);
110 if ((angleFromVectorToVector (pos2, pos0) < 0) ||
111 (angleFromVectorToVector (pos2, pos1) > 0)) {
112 path += QString (
"from 0=%1 through 2 to 1=%2").arg (angle0).arg (angle1);
116 path += QString (
"from 1=%1 through 2 to 0=%2").arg (angle1).arg (angle0);
123 while (xMax < xMin) {
127 path += QString (
" xMax+=%1").arg (thetaPeriod);
133 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::adjustPolarAngleRanges path=(" << path.toLatin1().data() <<
")";
136void Checker::bindItemToScene(QGraphicsItem *item)
const
138 LOG4CPP_DEBUG_S ((*mainCat)) <<
"Checker::bindItemToScene";
140 item->setOpacity (CHECKER_OPACITY);
141 item->setZValue (Z_VALUE_IN_FRONT);
142 item->setToolTip (QObject::tr (
"Axes checker. If this does not align with the axes, then the axes points should be checked"));
144 m_scene.addItem (item);
147void Checker::createSide (
int pointRadius,
148 const QList<Point> &points,
155 SideSegments &sideSegments)
157 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::createSide"
158 <<
" pointRadius=" << pointRadius
159 <<
" xFrom=" << xFrom
160 <<
" yFrom=" << yFrom
163 <<
" transformation=" << transformation;
174 const int NUM_STEPS = 1000;
176 bool stateSegmentIsActive =
false;
177 QPointF posStartScreen (0, 0);
180 for (
int i = 0; i <= NUM_STEPS; i++) {
182 double s = (double) i / (
double) NUM_STEPS;
185 double xGraph = (1.0 - s) * xFrom + s * xTo;
186 double yGraph = (1.0 - s) * yFrom + s * yTo;
190 xGraph = qExp ((1.0 - s) * qLn (xFrom) + s * qLn (xTo));
193 yGraph = qExp ((1.0 - s) * qLn (yFrom) + s * qLn (yTo));
197 transformation.transformRawGraphToScreen (QPointF (xGraph, yGraph),
200 double distanceToNearestPoint = minScreenDistanceFromPoints (pointScreen,
202 if ((distanceToNearestPoint < pointRadius) ||
206 if (stateSegmentIsActive) {
209 finishActiveSegment (modelCoords,
216 stateSegmentIsActive =
false;
222 if (!stateSegmentIsActive) {
225 stateSegmentIsActive =
true;
226 posStartScreen = pointScreen;
233void Checker::createTransformAlign (
const Transformation &transformation,
234 double radiusLinearCartesian,
235 const QPointF &posOriginScreen,
236 QTransform &transformAlign,
237 double &ellipseXAxis,
238 double &ellipseYAxis)
const
251 QPointF posXRadiusY0Graph (radiusLinearCartesian, 0), posX0YRadiusGraph (0, radiusLinearCartesian);
252 QPointF posXRadiusY0Screen, posX0YRadiusScreen;
259 QPointF deltaXRadiusY0 = posXRadiusY0Screen - posOriginScreen;
260 QPointF deltaX0YRadius = posX0YRadiusScreen - posOriginScreen;
261 ellipseXAxis = qSqrt (deltaXRadiusY0.x () * deltaXRadiusY0.x () +
262 deltaXRadiusY0.y () * deltaXRadiusY0.y ());
263 ellipseYAxis = qSqrt (deltaX0YRadius.x () * deltaX0YRadius.x () +
264 deltaX0YRadius.y () * deltaX0YRadius.y ());
267 QPointF posXRadiusY0AlignedScreen (posOriginScreen.x() + ellipseXAxis, posOriginScreen.y());
268 QPointF posX0YRadiusAlignedScreen (posOriginScreen.x(), posOriginScreen.y() - ellipseYAxis);
274 posXRadiusY0AlignedScreen,
275 posX0YRadiusAlignedScreen);
277 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::createTransformAlign"
278 <<
" transformation=" << QTransformToString (transformation.
transformMatrix()).toLatin1().data() << endl
279 <<
" radiusLinearCartesian=" << radiusLinearCartesian
280 <<
" posXRadiusY0Screen=" << QPointFToString (posXRadiusY0Screen).toLatin1().data()
281 <<
" posX0YRadiusScreen=" << QPointFToString (posX0YRadiusScreen).toLatin1().data()
282 <<
" ellipseXAxis=" << ellipseXAxis
283 <<
" ellipseYAxis=" << ellipseYAxis
284 <<
" posXRadiusY0AlignedScreen=" << QPointFToString (posXRadiusY0AlignedScreen).toLatin1().data()
285 <<
" posX0YRadiusAlignedScreen=" << QPointFToString (posX0YRadiusAlignedScreen).toLatin1().data()
286 <<
" transformAlign=" << QTransformToString (transformAlign).toLatin1().data();
289void Checker::deleteSide (SideSegments &sideSegments)
291 for (
int i = 0; i < sideSegments.count(); i++) {
292 QGraphicsItem *item = sideSegments [i];
298 sideSegments.clear();
301QGraphicsItem *Checker::ellipseItem(
const Transformation &transformation,
302 double radiusLinearCartesian,
303 const QPointF &posStartScreen,
304 const QPointF &posEndScreen)
const
308 QPointF posStartGraph, posEndGraph;
316 double angleStart = posStartGraph.x() * DEGREES_TO_RADIANS;
317 double angleEnd = posEndGraph.x() * DEGREES_TO_RADIANS;
318 if (angleEnd < angleStart) {
321 double angleSpan = angleEnd - angleStart;
324 QPointF posOriginGraph (0, 0), posOriginScreen;
328 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::ellipseItem"
329 <<
" radiusLinearCartesian=" << radiusLinearCartesian
330 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
331 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data()
332 <<
" posOriginScreen=" << QPointFToString (posOriginScreen).toLatin1().data()
333 <<
" angleStart=" << angleStart / DEGREES_TO_RADIANS
334 <<
" angleEnd=" << angleEnd / DEGREES_TO_RADIANS
335 <<
" transformation=" << transformation;
340 double ellipseXAxis, ellipseYAxis;
341 QTransform transformAlign;
342 createTransformAlign (transformation,
343 radiusLinearCartesian,
350 QRectF boundingRect (-1.0 * ellipseXAxis + posOriginScreen.x(),
351 -1.0 * ellipseYAxis + posOriginScreen.y(),
355 item->setStartAngle (angleStart * RADIANS_TO_TICS);
356 item->setSpanAngle (angleSpan * RADIANS_TO_TICS);
358 item->setTransform (transformAlign.transposed ().inverted ());
364 const QPointF &posStartScreen,
365 const QPointF &posEndScreen,
369 SideSegments &sideSegments)
const
371 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::finishActiveSegment"
372 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
373 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data()
374 <<
" yFrom=" << yFrom
378 if ((modelCoords.
coordsType() == COORDS_TYPE_POLAR) &&
382 double radiusLinearCartesian = yFrom;
391 item = ellipseItem (transformation,
392 radiusLinearCartesian,
399 item = lineItem (posStartScreen,
403 sideSegments.push_back (item);
404 bindItemToScene (item);
407QGraphicsItem *Checker::lineItem (
const QPointF &posStartScreen,
408 const QPointF &posEndScreen)
const
410 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::lineItem"
411 <<
" posStartScreen=" << QPointFToString (posStartScreen).toLatin1().data()
412 <<
" posEndScreen=" << QPointFToString (posEndScreen).toLatin1().data();
414 return new QGraphicsLineItem (QLineF (posStartScreen,
418double Checker::minScreenDistanceFromPoints (
const QPointF &posScreen,
419 const QList<Point> &points)
421 double minDistance = 0;
422 for (
int i = 0; i < points.count (); i++) {
423 const Point &pointCenter = points.at (i);
425 double dx = posScreen.x() - pointCenter.
posScreen().x();
426 double dy = posScreen.y() - pointCenter.
posScreen().y();
428 double distance = qSqrt (dx * dx + dy * dy);
429 if (i == 0 || distance < minDistance) {
430 minDistance = distance;
441 DocumentAxesPointsRequired documentAxesPointsRequired)
443 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::prepareForDisplay";
445 ENGAUGE_ASSERT ((polygon.count () == NUM_AXES_POINTS_3) ||
446 (polygon.count () == NUM_AXES_POINTS_4));
451 QPolygonF::const_iterator itr;
452 for (itr = polygon.begin (); itr != polygon.end (); itr++) {
454 const QPointF &pF = *itr;
456 Point p (DUMMY_CURVE_NAME,
460 points.push_back (p);
471 documentAxesPointsRequired);
479 DocumentAxesPointsRequired documentAxesPointsRequired)
481 LOG4CPP_INFO_S ((*mainCat)) <<
"Checker::prepareForDisplay "
482 <<
" transformation=" << transformation;
484 ENGAUGE_ASSERT ((points.count () == NUM_AXES_POINTS_3) ||
485 (points.count () == NUM_AXES_POINTS_4));
488 deleteSide (m_sideLeft);
489 deleteSide (m_sideTop);
490 deleteSide (m_sideRight);
491 deleteSide (m_sideBottom);
493 bool fourPoints = (documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_4);
496 double xFrom = 0, xTo = 0, yFrom = 0, yTo = 0;
500 for (i = 0; i < points.count(); i++) {
501 if (!fourPoints || (points.at(i).isXOnly() && fourPoints)) {
505 xFrom = points.at(i).posGraph().x();
506 xTo = points.at(i).posGraph().x();
509 xFrom = qMin (xFrom, points.at(i).posGraph().x());
510 xTo = qMax (xTo , points.at(i).posGraph().x());
514 if (!fourPoints || (!points.at(i).isXOnly() && fourPoints)) {
518 yFrom = points.at(i).posGraph().y();
519 yTo = points.at(i).posGraph().y();
522 yFrom = qMin (yFrom, points.at(i).posGraph().y());
523 yTo = qMax (yTo , points.at(i).posGraph().y());
530 adjustPolarAngleRanges (modelCoords,
538 createSide (pointRadius, points, modelCoords, xFrom, yFrom, xFrom, yTo , transformation, m_sideLeft);
539 createSide (pointRadius, points, modelCoords, xFrom, yTo , xTo , yTo , transformation, m_sideTop);
540 createSide (pointRadius, points, modelCoords, xTo , yTo , xTo , yFrom, transformation, m_sideRight);
541 createSide (pointRadius, points, modelCoords, xTo , yFrom, xFrom, yFrom, transformation, m_sideBottom);
546void Checker::setLineColor (SideSegments &sideSegments,
549 for (
int i = 0; i < sideSegments.count(); i++) {
550 QGraphicsItem *item = sideSegments [i];
554 QGraphicsLineItem *itemLine =
dynamic_cast<QGraphicsLineItem*
> (item);
555 QGraphicsEllipseItem *itemArc =
dynamic_cast<QGraphicsEllipseItem*
> (item);
557 itemLine->setPen (pen);
558 }
else if (itemArc != 0) {
559 itemArc->setPen (pen);
567 setVisibleSide (m_sideLeft, visible);
568 setVisibleSide (m_sideTop, visible);
569 setVisibleSide (m_sideRight, visible);
570 setVisibleSide (m_sideBottom, visible);
573void Checker::setVisibleSide (SideSegments &sideSegments,
576 for (
int i = 0; i < sideSegments.count(); i++) {
577 QGraphicsItem *item = sideSegments [i];
579 item->setVisible (visible);
586 QColor color = ColorPaletteToQColor (modelAxesChecker.
lineColor());
587 QPen pen (QBrush (color), CHECKER_POINTS_WIDTH);
589 setLineColor (m_sideLeft, pen);
590 setLineColor (m_sideTop, pen);
591 setLineColor (m_sideRight, pen);
592 setLineColor (m_sideBottom, pen);
void prepareForDisplay(const QPolygonF &polygon, int pointRadius, const DocumentModelAxesChecker &modelAxesChecker, const DocumentModelCoords &modelCoords, DocumentAxesPointsRequired documentAxesPointsRequired)
Create the polygon from current information, including pixel coordinates, just prior to display.
Checker(QGraphicsScene &scene)
Single constructor for DlgSettingsAxesChecker, which does not have an explicit transformation....
void setVisible(bool visible)
Show/hide this axes checker.
virtual void updateModelAxesChecker(const DocumentModelAxesChecker &modelAxesChecker)
Apply the new DocumentModelAxesChecker, to the points already associated with this object.
Model for DlgSettingsAxesChecker and CmdSettingsAxesChecker.
ColorPalette lineColor() const
Get method for line color.
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
double thetaPeriod() const
Return the period of the theta value for polar coordinates, consistent with CoordThetaUnits.
CoordsType coordsType() const
Get method for coordinates type.
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.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
QPointF posScreen() const
Accessor for screen position.