8 #include "EngaugeAssert.h"
10 #include "GraphicsArcItem.h"
14 #include <QGraphicsScene>
17 #include <QTextStream>
18 #include "QtToString.h"
19 #include "Transformation.h"
21 const int NUM_AXES_POINTS_3 = 3;
22 const int NUM_AXES_POINTS_4 = 4;
24 extern const QString DUMMY_CURVE_NAME;
25 const int Z_VALUE_IN_FRONT = 100;
28 const double CHECKER_OPACITY = 0.6;
33 const int CHECKER_POINTS_WIDTH = 5;
35 const double PI = 3.1415926535;
36 const double TWO_PI = 2.0 * PI;
37 const double DEGREES_TO_RADIANS = PI / 180.0;
38 const 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() <<
")";
136 void 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);
147 void 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;
233 void 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();
289 void Checker::deleteSide (SideSegments &sideSegments)
291 for (
int i = 0; i < sideSegments.count(); i++) {
292 QGraphicsItem *item = sideSegments [i];
298 sideSegments.clear();
301 QGraphicsItem *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);
407 QGraphicsItem *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,
418 double 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);
546 void 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);
573 void 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);
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.
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...
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.