21 m_modelCoords (modelCoords),
23 m_documentAxesPointsRequired (documentAxesPointsRequired)
28 const QString pointIdentifierOverride,
29 const QPointF &posScreenOverride,
30 const QPointF &posGraphOverride,
32 m_modelCoords (modelCoords),
33 m_pointIdentifierOverride (pointIdentifierOverride),
34 m_posScreenOverride (posScreenOverride),
35 m_posGraphOverride (posGraphOverride),
37 m_documentAxesPointsRequired (documentAxesPointsRequired)
41 bool CallbackAxisPointsAbstract::anyPointsRepeatPair (
const CoordPairVector &vector,
44 for (
int pointLeft = 0; pointLeft < vector.count(); pointLeft++) {
45 for (
int pointRight = pointLeft + 1; pointRight < vector.count(); pointRight++) {
47 if (qAbs (vector.at(pointLeft).x() - vector.at(pointRight).x()) <= epsilon &&
48 qAbs (vector.at(pointLeft).y() - vector.at(pointRight).y()) <= epsilon) {
60 bool CallbackAxisPointsAbstract::anyPointsRepeatSingle (
const CoordSingleVector &vector,
63 for (
int pointLeft = 0; pointLeft < vector.count(); pointLeft++) {
64 for (
int pointRight = pointLeft + 1; pointRight < vector.count(); pointRight++) {
66 if (qAbs (vector.at(pointLeft) - vector.at(pointRight)) <= epsilon) {
82 QPointF posGraph = point.
posGraph ();
84 if (m_pointIdentifierOverride == point.
identifier ()) {
87 posScreen = m_posScreenOverride;
88 posGraph = m_posGraphOverride;
93 return callbackRequire2AxisPoints (posScreen,
96 return callbackRequire3AxisPoints (posScreen,
99 return callbackRequire4AxisPoints (point.
isXOnly(),
105 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire2AxisPoints (
const QPointF &posScreen,
106 const QPointF &posGraph)
113 m_xGraphHigh = posGraph.x();
114 m_yGraphHigh = posGraph.x();
116 int numberPoints = m_screenInputs.count();
117 if (numberPoints < 2) {
120 m_screenInputs.push_back (posScreen);
121 m_graphOutputs.push_back (posGraph);
122 numberPoints = m_screenInputs.count();
124 if (numberPoints == 2) {
129 if (anyPointsRepeatPair (m_screenInputs,
133 m_errorMessage = QObject::tr (
"New axis point cannot be at the same screen position as an existing axis point");
139 if (m_screenInputs.count() > 1) {
149 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire3AxisPoints (
const QPointF &posScreen,
150 const QPointF &posGraph)
155 int numberPoints = m_screenInputs.count();
156 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
157 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
158 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
159 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
161 if (numberPoints < 3) {
164 m_screenInputs.push_back (posScreen);
165 m_graphOutputs.push_back (posGraph);
166 numberPoints = m_screenInputs.count();
168 if (numberPoints == 3) {
175 anyPointsRepeatPair (m_screenInputs,
ONE_PIXEL)) {
178 m_errorMessage = QObject::tr (
"New axis point cannot be at the same screen position as an existing axis point");
186 m_errorMessage = QObject::tr (
"New axis point cannot have the same graph coordinates as an existing axis point");
189 }
else if ((numberPoints == 3) && threePointsAreCollinear (m_screenInputsTransform,
194 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line on the screen");
197 }
else if ((numberPoints == 3) && threePointsAreCollinear (m_graphOutputsTransform,
202 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line in graph coordinates");
208 if (m_screenInputs.count() > 2) {
219 const QPointF &posScreen,
220 const QPointF &posGraph)
225 int numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
226 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
227 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
228 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
229 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
231 if (numberPoints < 4) {
236 m_screenInputsX.push_back (posScreen);
237 m_graphOutputsX.push_back (posGraph.x());
241 m_screenInputsY.push_back (posScreen);
242 m_graphOutputsY.push_back (posGraph.y());
246 numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
247 if (numberPoints == 4) {
252 if (m_screenInputsX.count() > 2) {
255 m_errorMessage = QObject::tr (
"Too many x axis points. There should only be two");
258 }
else if (m_screenInputsY.count() > 2) {
261 m_errorMessage = QObject::tr (
"Too many y axis points. There should only be two");
266 if ((m_screenInputsX.count() == 2) &&
267 (m_screenInputsY.count() == 2)) {
274 if (anyPointsRepeatPair (m_screenInputsX,
276 anyPointsRepeatPair (m_screenInputsY,
280 m_errorMessage = QObject::tr (
"New axis point cannot be at the same screen position as an existing axis point");
283 }
else if (anyPointsRepeatSingle (m_graphOutputsX,
285 anyPointsRepeatSingle (m_graphOutputsY,
289 m_errorMessage = QObject::tr (
"New axis point cannot have the same graph coordinates as an existing axis point");
292 }
else if ((numberPoints == 4) && threePointsAreCollinear (m_screenInputsTransform,
297 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line on the screen");
300 }
else if ((numberPoints == 4) && threePointsAreCollinear (m_graphOutputsTransform,
305 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line in graph coordinates");
316 return m_documentAxesPointsRequired;
319 void CallbackAxisPointsAbstract::loadTransforms2 ()
326 double d0To1ScreenX = m_screenInputs.at (1).x () - m_screenInputs.at (0).x ();
327 double d0To1ScreenY = m_screenInputs.at (1).y () - m_screenInputs.at (0).y ();
328 double d0To1ScreenZ = 0;
329 double d0To1GraphX = m_graphOutputs.at (1).x () - m_graphOutputs.at (0).x ();
330 double d0To1GraphY = m_graphOutputs.at (1).y () - m_graphOutputs.at (0).y ();
331 double d0To1GraphZ = 0;
333 double unitNormalX = 0;
334 double unitNormalY = 0;
335 double unitNormalZ = 1;
337 double d0To2ScreenX = unitNormalY * d0To1ScreenZ - unitNormalZ * d0To1ScreenY;
338 double d0To2ScreenY = unitNormalZ * d0To1ScreenX - unitNormalX * d0To1ScreenZ;
339 double d0To2GraphX = unitNormalY * d0To1GraphZ - unitNormalZ * d0To1GraphY;
340 double d0To2GraphY = unitNormalZ * d0To1GraphX - unitNormalX * d0To1GraphZ;
344 const double FLIP_Y_SCREEN = -1.0;
346 double screenX2 = m_screenInputs.at (0).x () + FLIP_Y_SCREEN * d0To2ScreenX;
347 double screenY2 = m_screenInputs.at (0).y () + FLIP_Y_SCREEN * d0To2ScreenY;
348 double graphX2 = m_graphOutputs.at (0).x () + d0To2GraphX;
349 double graphY2 = m_graphOutputs.at (0).y () + d0To2GraphY;
352 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), screenX2,
353 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), screenY2,
357 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), graphX2,
358 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), graphY2,
362 void CallbackAxisPointsAbstract::loadTransforms3 ()
365 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), m_screenInputs.at(2).x(),
366 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), m_screenInputs.at(2).y(),
370 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), m_graphOutputs.at(2).x(),
371 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), m_graphOutputs.at(2).y(),
375 void CallbackAxisPointsAbstract::loadTransforms4 ()
377 double x1Screen = m_screenInputsX.at(0).x();
378 double y1Screen = m_screenInputsX.at(0).y();
379 double x2Screen = m_screenInputsX.at(1).x();
380 double y2Screen = m_screenInputsX.at(1).y();
381 double x3Screen = m_screenInputsY.at(0).x();
382 double y3Screen = m_screenInputsY.at(0).y();
383 double x4Screen = m_screenInputsY.at(1).x();
384 double y4Screen = m_screenInputsY.at(1).y();
387 double x1Graph = m_graphOutputsX.at(0);
388 double x2Graph = m_graphOutputsX.at(1);
389 double y3Graph = m_graphOutputsY.at(0);
390 double y4Graph = m_graphOutputsY.at(1);
401 double A00 = x1Screen - x2Screen;
402 double A01 = x4Screen - x3Screen;
403 double A10 = y1Screen - y2Screen;
404 double A11 = y4Screen - y3Screen;
405 double b0 = x1Screen - x3Screen;
406 double b1 = y1Screen - y3Screen;
407 double numeratorx = (b0 * A11 - A01 * b1);
408 double numeratory = (A00 * b1 - b0 * A10);
409 double denominator = (A00 * A11 - A01 * A10);
410 double sx = numeratorx / denominator;
411 double sy = numeratory / denominator;
414 double xIntScreen = (1.0 - sx) * x1Screen + sx * x2Screen;
415 double yIntScreen = (1.0 - sy) * y3Screen + sy * y4Screen;
416 double xIntGraph, yIntGraph;
418 xIntGraph = (1.0 - sx) * x1Graph + sx * x2Graph;
420 xIntGraph = qExp ((1.0 - sx) * qLn (x1Graph) + sx * qLn (x2Graph));
423 yIntGraph = (1.0 - sy) * y3Graph + sy * y4Graph;
425 yIntGraph = qExp ((1.0 - sy) * qLn (y3Graph) + sy * qLn (y4Graph));
429 double distance1 = qSqrt ((x1Screen - xIntScreen) * (x1Screen - xIntScreen) +
430 (y1Screen - yIntScreen) * (y1Screen - yIntScreen));
431 double distance2 = qSqrt ((x2Screen - xIntScreen) * (x2Screen - xIntScreen) +
432 (y2Screen - yIntScreen) * (y2Screen - yIntScreen));
433 double distance3 = qSqrt ((x3Screen - xIntScreen) * (x3Screen - xIntScreen) +
434 (y3Screen - yIntScreen) * (y3Screen - yIntScreen));
435 double distance4 = qSqrt ((x4Screen - xIntScreen) * (x4Screen - xIntScreen) +
436 (y4Screen - yIntScreen) * (y4Screen - yIntScreen));
442 double xFurthestXAxisScreen, yFurthestXAxisScreen, xFurthestYAxisScreen, yFurthestYAxisScreen;
443 double xFurthestXAxisGraph, yFurthestXAxisGraph, xFurthestYAxisGraph, yFurthestYAxisGraph;
444 if (distance1 < distance2) {
445 xFurthestXAxisScreen = x2Screen;
446 yFurthestXAxisScreen = y2Screen;
447 xFurthestXAxisGraph = x2Graph;
448 yFurthestXAxisGraph = yIntGraph;
450 xFurthestXAxisScreen = x1Screen;
451 yFurthestXAxisScreen = y1Screen;
452 xFurthestXAxisGraph = x1Graph;
453 yFurthestXAxisGraph = yIntGraph;
455 if (distance3 < distance4) {
456 xFurthestYAxisScreen = x4Screen;
457 yFurthestYAxisScreen = y4Screen;
458 xFurthestYAxisGraph = xIntGraph;
459 yFurthestYAxisGraph = y4Graph;
461 xFurthestYAxisScreen = x3Screen;
462 yFurthestYAxisScreen = y3Screen;
463 xFurthestYAxisGraph = xIntGraph;
464 yFurthestYAxisGraph = y3Graph;
468 m_screenInputsTransform = QTransform (xIntScreen, xFurthestXAxisScreen, xFurthestYAxisScreen,
469 yIntScreen, yFurthestXAxisScreen, yFurthestYAxisScreen,
473 m_graphOutputsTransform = QTransform (xIntGraph, xFurthestXAxisGraph, xFurthestYAxisGraph,
474 yIntGraph, yFurthestXAxisGraph, yFurthestYAxisGraph,
478 CallbackAxisPointsAbstract::LinearOrLog CallbackAxisPointsAbstract::logXGraph ()
const
483 CallbackAxisPointsAbstract::LinearOrLog CallbackAxisPointsAbstract::logYGraph ()
const
490 return m_graphOutputsTransform;
495 return m_screenInputsTransform;
501 return unsigned (m_screenInputs.count());
503 return unsigned (m_screenInputs.count());
505 return unsigned (m_screenInputsX.count() + m_screenInputsY.count());
509 bool CallbackAxisPointsAbstract::threePointsAreCollinear (
const QTransform &transformIn,
511 LinearOrLog logY)
const
513 double m11 = (logX == COORD_IS_LOG) ? qLn (transformIn.m11()) : transformIn.m11();
514 double m12 = (logX == COORD_IS_LOG) ? qLn (transformIn.m12()) : transformIn.m12();
515 double m13 = (logX == COORD_IS_LOG) ? qLn (transformIn.m13()) : transformIn.m13();
516 double m21 = (logY == COORD_IS_LOG) ? qLn (transformIn.m21()) : transformIn.m21();
517 double m22 = (logY == COORD_IS_LOG) ? qLn (transformIn.m22()) : transformIn.m22();
518 double m23 = (logY == COORD_IS_LOG) ? qLn (transformIn.m23()) : transformIn.m23();
519 double m31 = transformIn.m31();
520 double m32 = transformIn.m32();
521 double m33 = transformIn.m33();
523 QTransform transform (m11, m12, m13,
527 return !transform.isInvertible ();
QPointF posGraph(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Accessor for graph position. Skip check if copying one instance to another.
QTransform matrixGraph() const
Returns graph coordinates matrix after transformIsDefined has already indicated success.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Number of axes points required for the transformation.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
QPointF posScreen() const
Accessor for screen position.
QList< QPointF > CoordPairVector
CallbackSearchReturn
Return values for search callback methods.
QString identifier() const
Unique identifier for a specific Point.
Continue normal execution of the search.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
QList< double > CoordSingleVector
bool isXOnly() const
In DOCUMENT_AXES_POINTS_REQUIRED_4 modes, this is true/false if y/x coordinate is undefined...
Model for DlgSettingsCoords and CmdSettingsCoords.
CallbackAxisPointsAbstract(const DocumentModelCoords &modelCoords, DocumentAxesPointsRequired documentAxesPointsRequired)
Constructor for when all of the existing axis points are to be processed as is.
unsigned int numberAxisPoints() const
Number of axis points which is less than 3 if the axes curve is incomplete.
Immediately terminate the current search.
const double ZERO_EPSILON
DocumentAxesPointsRequired
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.
QTransform matrixScreen() const
Returns screen coordinates matrix after transformIsDefined has already indicated success.