7 #include "CallbackAxisPointsAbstract.h" 8 #include "EngaugeAssert.h" 12 #include "QtToString.h" 13 #include "Transformation.h" 16 const double ONE_PIXEL = 1.0;
17 const double ZERO_EPSILON = 0.0;
20 DocumentAxesPointsRequired documentAxesPointsRequired) :
21 m_modelCoords (modelCoords),
23 m_documentAxesPointsRequired (documentAxesPointsRequired)
28 const QString pointIdentifierOverride,
29 const QPointF &posScreenOverride,
30 const QPointF &posGraphOverride,
31 DocumentAxesPointsRequired documentAxesPointsRequired) :
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;
92 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2) {
93 return callbackRequire2AxisPoints (posScreen,
95 }
else if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) {
96 return callbackRequire3AxisPoints (posScreen,
99 return callbackRequire4AxisPoints (point.
isXOnly(),
105 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire2AxisPoints (
const QPointF &posScreen,
106 const QPointF &posGraph)
108 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
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");
134 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
139 if (m_screenInputs.count() > 1) {
142 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
149 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire3AxisPoints (
const QPointF &posScreen,
150 const QPointF &posGraph)
152 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
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) {
173 if ((m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2 ||
174 m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_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");
179 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
181 }
else if ((m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2 ||
182 m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) &&
183 anyPointsRepeatPair (m_graphOutputs, ZERO_EPSILON)) {
186 m_errorMessage = QObject::tr (
"New axis point cannot have the same graph coordinates as an existing axis point");
187 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
189 }
else if ((numberPoints == 3) && threePointsAreCollinear (m_screenInputsTransform)) {
192 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line on the screen");
193 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
195 }
else if ((numberPoints == 3) && threePointsAreCollinear (m_graphOutputsTransform)) {
198 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line in graph coordinates");
199 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
204 if (m_screenInputs.count() > 2) {
207 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
214 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire4AxisPoints (
bool isXOnly,
215 const QPointF &posScreen,
216 const QPointF &posGraph)
218 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
221 int numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
222 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
223 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
224 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
225 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
227 if (numberPoints < 4) {
232 m_screenInputsX.push_back (posScreen);
233 m_graphOutputsX.push_back (posGraph.x());
237 m_screenInputsY.push_back (posScreen);
238 m_graphOutputsY.push_back (posGraph.y());
242 numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
243 if (numberPoints == 4) {
248 if (m_screenInputsX.count() > 2) {
251 m_errorMessage = QObject::tr (
"Too many x axis points. There should only be two");
252 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
254 }
else if (m_screenInputsY.count() > 2) {
257 m_errorMessage = QObject::tr (
"Too many y axis points. There should only be two");
258 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
262 if ((m_screenInputsX.count() == 2) &&
263 (m_screenInputsY.count() == 2)) {
266 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
270 if (anyPointsRepeatPair (m_screenInputsX,
272 anyPointsRepeatPair (m_screenInputsY,
276 m_errorMessage = QObject::tr (
"New axis point cannot be at the same screen position as an existing axis point");
277 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
279 }
else if (anyPointsRepeatSingle (m_graphOutputsX,
281 anyPointsRepeatSingle (m_graphOutputsY,
285 m_errorMessage = QObject::tr (
"New axis point cannot have the same graph coordinates as an existing axis point");
286 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
288 }
else if ((numberPoints == 4) && threePointsAreCollinear (m_screenInputsTransform)) {
291 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line on the screen");
292 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
294 }
else if ((numberPoints == 4) && threePointsAreCollinear (m_graphOutputsTransform)) {
297 m_errorMessage = QObject::tr (
"No more than two axis points can lie along the same line in graph coordinates");
298 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
308 return m_documentAxesPointsRequired;
311 void CallbackAxisPointsAbstract::loadTransforms2 ()
318 double d0To1ScreenX = m_screenInputs.at (1).x () - m_screenInputs.at (0).x ();
319 double d0To1ScreenY = m_screenInputs.at (1).y () - m_screenInputs.at (0).y ();
320 double d0To1ScreenZ = 0;
321 double d0To1GraphX = m_graphOutputs.at (1).x () - m_graphOutputs.at (0).x ();
322 double d0To1GraphY = m_graphOutputs.at (1).y () - m_graphOutputs.at (0).y ();
323 double d0To1GraphZ = 0;
325 double unitNormalX = 0;
326 double unitNormalY = 0;
327 double unitNormalZ = 1;
329 double d0To2ScreenX = unitNormalY * d0To1ScreenZ - unitNormalZ * d0To1ScreenY;
330 double d0To2ScreenY = unitNormalZ * d0To1ScreenX - unitNormalX * d0To1ScreenZ;
331 double d0To2GraphX = unitNormalY * d0To1GraphZ - unitNormalZ * d0To1GraphY;
332 double d0To2GraphY = unitNormalZ * d0To1GraphX - unitNormalX * d0To1GraphZ;
336 const double FLIP_Y_SCREEN = -1.0;
338 double screenX2 = m_screenInputs.at (0).x () + FLIP_Y_SCREEN * d0To2ScreenX;
339 double screenY2 = m_screenInputs.at (0).y () + FLIP_Y_SCREEN * d0To2ScreenY;
340 double graphX2 = m_graphOutputs.at (0).x () + d0To2GraphX;
341 double graphY2 = m_graphOutputs.at (0).y () + d0To2GraphY;
344 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), screenX2,
345 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), screenY2,
349 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), graphX2,
350 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), graphY2,
354 void CallbackAxisPointsAbstract::loadTransforms3 ()
357 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), m_screenInputs.at(2).x(),
358 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), m_screenInputs.at(2).y(),
362 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), m_graphOutputs.at(2).x(),
363 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), m_graphOutputs.at(2).y(),
367 void CallbackAxisPointsAbstract::loadTransforms4 ()
369 double x1Screen = m_screenInputsX.at(0).x();
370 double y1Screen = m_screenInputsX.at(0).y();
371 double x2Screen = m_screenInputsX.at(1).x();
372 double y2Screen = m_screenInputsX.at(1).y();
373 double x3Screen = m_screenInputsY.at(0).x();
374 double y3Screen = m_screenInputsY.at(0).y();
375 double x4Screen = m_screenInputsY.at(1).x();
376 double y4Screen = m_screenInputsY.at(1).y();
379 double x1Graph = m_graphOutputsX.at(0);
380 double x2Graph = m_graphOutputsX.at(1);
381 double y3Graph = m_graphOutputsY.at(0);
382 double y4Graph = m_graphOutputsY.at(1);
393 double A00 = x1Screen - x2Screen;
394 double A01 = x4Screen - x3Screen;
395 double A10 = y1Screen - y2Screen;
396 double A11 = y4Screen - y3Screen;
397 double b0 = x1Screen - x3Screen;
398 double b1 = y1Screen - y3Screen;
399 double numeratorx = (b0 * A11 - A01 * b1);
400 double numeratory = (A00 * b1 - b0 * A10);
401 double denominator = (A00 * A11 - A01 * A10);
402 double sx = numeratorx / denominator;
403 double sy = numeratory / denominator;
406 double xIntScreen = (1.0 - sx) * x1Screen + sx * x2Screen;
407 double yIntScreen = (1.0 - sy) * y3Screen + sy * y4Screen;
408 double xIntGraph, yIntGraph;
410 xIntGraph = (1.0 - sx) * x1Graph + sx * x2Graph;
412 xIntGraph = qExp ((1.0 - sx) * qLn (x1Graph) + sx * qLn (x2Graph));
415 yIntGraph = (1.0 - sy) * y3Graph + sy * y4Graph;
417 yIntGraph = qExp ((1.0 - sy) * qLn (y3Graph) + sy * qLn (y4Graph));
421 double distance1 = qSqrt ((x1Screen - xIntScreen) * (x1Screen - xIntScreen) +
422 (y1Screen - yIntScreen) * (y1Screen - yIntScreen));
423 double distance2 = qSqrt ((x2Screen - xIntScreen) * (x2Screen - xIntScreen) +
424 (y2Screen - yIntScreen) * (y2Screen - yIntScreen));
425 double distance3 = qSqrt ((x3Screen - xIntScreen) * (x3Screen - xIntScreen) +
426 (y3Screen - yIntScreen) * (y3Screen - yIntScreen));
427 double distance4 = qSqrt ((x4Screen - xIntScreen) * (x4Screen - xIntScreen) +
428 (y4Screen - yIntScreen) * (y4Screen - yIntScreen));
434 double xFurthestXAxisScreen, yFurthestXAxisScreen, xFurthestYAxisScreen, yFurthestYAxisScreen;
435 double xFurthestXAxisGraph, yFurthestXAxisGraph, xFurthestYAxisGraph, yFurthestYAxisGraph;
436 if (distance1 < distance2) {
437 xFurthestXAxisScreen = x2Screen;
438 yFurthestXAxisScreen = y2Screen;
439 xFurthestXAxisGraph = x2Graph;
440 yFurthestXAxisGraph = yIntGraph;
442 xFurthestXAxisScreen = x1Screen;
443 yFurthestXAxisScreen = y1Screen;
444 xFurthestXAxisGraph = x1Graph;
445 yFurthestXAxisGraph = yIntGraph;
447 if (distance3 < distance4) {
448 xFurthestYAxisScreen = x4Screen;
449 yFurthestYAxisScreen = y4Screen;
450 xFurthestYAxisGraph = xIntGraph;
451 yFurthestYAxisGraph = y4Graph;
453 xFurthestYAxisScreen = x3Screen;
454 yFurthestYAxisScreen = y3Screen;
455 xFurthestYAxisGraph = xIntGraph;
456 yFurthestYAxisGraph = y3Graph;
460 m_screenInputsTransform = QTransform (xIntScreen, xFurthestXAxisScreen, xFurthestYAxisScreen,
461 yIntScreen, yFurthestXAxisScreen, yFurthestYAxisScreen,
465 m_graphOutputsTransform = QTransform (xIntGraph, xFurthestXAxisGraph, xFurthestYAxisGraph,
466 yIntGraph, yFurthestXAxisGraph, yFurthestYAxisGraph,
472 return m_graphOutputsTransform;
477 return m_screenInputsTransform;
482 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2) {
483 return unsigned (m_screenInputs.count());
484 }
else if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) {
485 return unsigned (m_screenInputs.count());
487 return unsigned (m_screenInputsX.count() + m_screenInputsY.count());
491 bool CallbackAxisPointsAbstract::threePointsAreCollinear (
const QTransform &transform)
493 return !transform.isInvertible ();
bool isXOnly() const
In DOCUMENT_AXES_POINTS_REQUIRED_4 modes, this is true/false if y/x coordinate is undefined.
QTransform matrixScreen() const
Returns screen coordinates matrix after transformIsDefined has already indicated success.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
QPointF posScreen() const
Accessor for screen position.
unsigned int numberAxisPoints() const
Number of axis points which is less than 3 if the axes curve is incomplete.
QString identifier() const
Unique identifier for a specific Point.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
QPointF posGraph(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Accessor for graph position. Skip check if copying one instance to another.
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CallbackAxisPointsAbstract(const DocumentModelCoords &modelCoords, DocumentAxesPointsRequired documentAxesPointsRequired)
Constructor for when all of the existing axis points are to be processed as is.
QTransform matrixGraph() const
Returns graph coordinates matrix after transformIsDefined has already indicated success.
DocumentAxesPointsRequired documentAxesPointsRequired() const
Number of axes points required for the transformation.
CallbackSearchReturn callback(const QString &curveName, const Point &point)
Callback method.