00001
00002
00003
00004
00005
00006
00007 #include "CallbackAxisPointsAbstract.h"
00008 #include "EngaugeAssert.h"
00009 #include "Logger.h"
00010 #include "Point.h"
00011 #include <qmath.h>
00012 #include "QtToString.h"
00013 #include "Transformation.h"
00014
00015 CallbackAxisPointsAbstract::CallbackAxisPointsAbstract(const DocumentModelCoords &modelCoords,
00016 DocumentAxesPointsRequired documentAxesPointsRequired) :
00017 m_modelCoords (modelCoords),
00018 m_isError (false),
00019 m_documentAxesPointsRequired (documentAxesPointsRequired)
00020 {
00021 }
00022
00023 CallbackAxisPointsAbstract::CallbackAxisPointsAbstract(const DocumentModelCoords &modelCoords,
00024 const QString pointIdentifierOverride,
00025 const QPointF &posScreenOverride,
00026 const QPointF &posGraphOverride,
00027 DocumentAxesPointsRequired documentAxesPointsRequired) :
00028 m_modelCoords (modelCoords),
00029 m_pointIdentifierOverride (pointIdentifierOverride),
00030 m_posScreenOverride (posScreenOverride),
00031 m_posGraphOverride (posGraphOverride),
00032 m_isError (false),
00033 m_documentAxesPointsRequired (documentAxesPointsRequired)
00034 {
00035 }
00036
00037 bool CallbackAxisPointsAbstract::anyPointsRepeatPair (const CoordPairVector &vector) const
00038 {
00039 for (int pointLeft = 0; pointLeft < vector.count(); pointLeft++) {
00040 for (int pointRight = pointLeft + 1; pointRight < vector.count(); pointRight++) {
00041
00042 if ((vector.at(pointLeft).x() == vector.at(pointRight).x()) &&
00043 (vector.at(pointLeft).y() == vector.at(pointRight).y())) {
00044
00045
00046 return true;
00047 }
00048 }
00049 }
00050
00051
00052 return false;
00053 }
00054
00055 bool CallbackAxisPointsAbstract::anyPointsRepeatSingle (const CoordSingleVector &vector) const
00056 {
00057 for (int pointLeft = 0; pointLeft < vector.count(); pointLeft++) {
00058 for (int pointRight = pointLeft + 1; pointRight < vector.count(); pointRight++) {
00059
00060 if (vector.at(pointLeft) == vector.at(pointRight)) {
00061
00062
00063 return true;
00064 }
00065 }
00066 }
00067
00068
00069 return false;
00070 }
00071
00072 CallbackSearchReturn CallbackAxisPointsAbstract::callback (const QString & ,
00073 const Point &point)
00074 {
00075 QPointF posScreen = point.posScreen ();
00076 QPointF posGraph = point.posGraph ();
00077
00078 if (m_pointIdentifierOverride == point.identifier ()) {
00079
00080
00081 posScreen = m_posScreenOverride;
00082 posGraph = m_posGraphOverride;
00083 }
00084
00085
00086 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2) {
00087 return callbackRequire2AxisPoints (posScreen,
00088 posGraph);
00089 } else if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) {
00090 return callbackRequire3AxisPoints (posScreen,
00091 posGraph);
00092 } else {
00093 return callbackRequire4AxisPoints (point.isXOnly(),
00094 posScreen,
00095 posGraph);
00096 }
00097 }
00098
00099 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire2AxisPoints (const QPointF &posScreen,
00100 const QPointF &posGraph)
00101 {
00102 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
00103
00104
00105 m_xGraphLow = 0;
00106 m_yGraphLow = 0;
00107 m_xGraphHigh = posGraph.x();
00108 m_yGraphHigh = posGraph.x();
00109
00110 int numberPoints = m_screenInputs.count();
00111 if (numberPoints < 2) {
00112
00113
00114 m_screenInputs.push_back (posScreen);
00115 m_graphOutputs.push_back (posGraph);
00116 numberPoints = m_screenInputs.count();
00117
00118 if (numberPoints == 2) {
00119 loadTransforms2 ();
00120 }
00121
00122
00123 if (anyPointsRepeatPair (m_screenInputs)) {
00124
00125 m_isError = true;
00126 m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point");
00127 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00128
00129 }
00130 }
00131
00132 if (m_screenInputs.count() > 1) {
00133
00134
00135 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00136
00137 }
00138
00139 return rtn;
00140 }
00141
00142 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire3AxisPoints (const QPointF &posScreen,
00143 const QPointF &posGraph)
00144 {
00145 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
00146
00147
00148 int numberPoints = m_screenInputs.count();
00149 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
00150 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
00151 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
00152 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
00153
00154 if (numberPoints < 3) {
00155
00156
00157 m_screenInputs.push_back (posScreen);
00158 m_graphOutputs.push_back (posGraph);
00159 numberPoints = m_screenInputs.count();
00160
00161 if (numberPoints == 3) {
00162 loadTransforms3 ();
00163 }
00164
00165
00166 if ((m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2 ||
00167 m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) &&
00168 anyPointsRepeatPair (m_screenInputs)) {
00169
00170 m_isError = true;
00171 m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point");
00172 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00173
00174 } else if ((m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2 ||
00175 m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) &&
00176 anyPointsRepeatPair (m_graphOutputs)) {
00177
00178 m_isError = true;
00179 m_errorMessage = QObject::tr ("New axis point cannot have the same graph coordinates as an existing axis point");
00180 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00181
00182 } else if ((numberPoints == 3) && threePointsAreCollinear (m_screenInputsTransform)) {
00183
00184 m_isError = true;
00185 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line on the screen");
00186 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00187
00188 } else if ((numberPoints == 3) && threePointsAreCollinear (m_graphOutputsTransform)) {
00189
00190 m_isError = true;
00191 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line in graph coordinates");
00192 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00193
00194 }
00195 }
00196
00197 if (m_screenInputs.count() > 2) {
00198
00199
00200 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00201
00202 }
00203
00204 return rtn;
00205 }
00206
00207 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire4AxisPoints (bool isXOnly,
00208 const QPointF &posScreen,
00209 const QPointF &posGraph)
00210 {
00211 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
00212
00213
00214 int numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
00215 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
00216 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
00217 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
00218 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
00219
00220 if (numberPoints < 4) {
00221
00222
00223 if (isXOnly) {
00224
00225 m_screenInputsX.push_back (posScreen);
00226 m_graphOutputsX.push_back (posGraph.x());
00227
00228 } else {
00229
00230 m_screenInputsY.push_back (posScreen);
00231 m_graphOutputsY.push_back (posGraph.y());
00232
00233 }
00234
00235 numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
00236 if (numberPoints == 4) {
00237 loadTransforms4 ();
00238 }
00239 }
00240
00241 if (m_screenInputsX.count() > 2) {
00242
00243 m_isError = true;
00244 m_errorMessage = QObject::tr ("Too many x axis points. There should only be two");
00245 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00246
00247 } else if (m_screenInputsY.count() > 2) {
00248
00249 m_isError = true;
00250 m_errorMessage = QObject::tr ("Too many y axis points. There should only be two");
00251 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00252
00253 } else {
00254
00255 if ((m_screenInputsX.count() == 2) &&
00256 (m_screenInputsY.count() == 2)) {
00257
00258
00259 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00260 }
00261
00262
00263 if (anyPointsRepeatPair (m_screenInputsX) ||
00264 anyPointsRepeatPair (m_screenInputsY)) {
00265
00266 m_isError = true;
00267 m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point");
00268 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00269
00270 } else if (anyPointsRepeatSingle (m_graphOutputsX) ||
00271 anyPointsRepeatSingle (m_graphOutputsY)) {
00272
00273 m_isError = true;
00274 m_errorMessage = QObject::tr ("New axis point cannot have the same graph coordinates as an existing axis point");
00275 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00276
00277 } else if ((numberPoints == 4) && threePointsAreCollinear (m_screenInputsTransform)) {
00278
00279 m_isError = true;
00280 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line on the screen");
00281 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00282
00283 } else if ((numberPoints == 4) && threePointsAreCollinear (m_graphOutputsTransform)) {
00284
00285 m_isError = true;
00286 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line in graph coordinates");
00287 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00288
00289 }
00290 }
00291
00292 return rtn;
00293 }
00294
00295 DocumentAxesPointsRequired CallbackAxisPointsAbstract::documentAxesPointsRequired() const
00296 {
00297 return m_documentAxesPointsRequired;
00298 }
00299
00300 void CallbackAxisPointsAbstract::loadTransforms2 ()
00301 {
00302
00303
00304
00305
00306
00307 double d0To1ScreenX = m_screenInputs.at (1).x () - m_screenInputs.at (0).x ();
00308 double d0To1ScreenY = m_screenInputs.at (1).y () - m_screenInputs.at (0).y ();
00309 double d0To1ScreenZ = 0;
00310 double d0To1GraphX = m_graphOutputs.at (1).x () - m_graphOutputs.at (0).x ();
00311 double d0To1GraphY = m_graphOutputs.at (1).y () - m_graphOutputs.at (0).y ();
00312 double d0To1GraphZ = 0;
00313
00314 double unitNormalX = 0;
00315 double unitNormalY = 0;
00316 double unitNormalZ = 1;
00317
00318 double d0To2ScreenX = unitNormalY * d0To1ScreenZ - unitNormalZ * d0To1ScreenY;
00319 double d0To2ScreenY = unitNormalZ * d0To1ScreenX - unitNormalX * d0To1ScreenZ;
00320 double d0To2GraphX = unitNormalY * d0To1GraphZ - unitNormalZ * d0To1GraphY;
00321 double d0To2GraphY = unitNormalZ * d0To1GraphX - unitNormalX * d0To1GraphZ;
00322
00323
00324
00325 const double FLIP_Y_SCREEN = -1.0;
00326
00327 double screenX2 = m_screenInputs.at (0).x () + FLIP_Y_SCREEN * d0To2ScreenX;
00328 double screenY2 = m_screenInputs.at (0).y () + FLIP_Y_SCREEN * d0To2ScreenY;
00329 double graphX2 = m_graphOutputs.at (0).x () + d0To2GraphX;
00330 double graphY2 = m_graphOutputs.at (0).y () + d0To2GraphY;
00331
00332
00333 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), screenX2,
00334 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), screenY2,
00335 1.0 , 1.0 , 1.0 );
00336
00337
00338 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), graphX2,
00339 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), graphY2,
00340 1.0 , 1.0 , 1.0 );
00341 }
00342
00343 void CallbackAxisPointsAbstract::loadTransforms3 ()
00344 {
00345
00346 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), m_screenInputs.at(2).x(),
00347 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), m_screenInputs.at(2).y(),
00348 1.0 , 1.0 , 1.0 );
00349
00350
00351 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), m_graphOutputs.at(2).x(),
00352 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), m_graphOutputs.at(2).y(),
00353 1.0 , 1.0 , 1.0 );
00354 }
00355
00356 void CallbackAxisPointsAbstract::loadTransforms4 ()
00357 {
00358 double x1Screen = m_screenInputsX.at(0).x();
00359 double y1Screen = m_screenInputsX.at(0).y();
00360 double x2Screen = m_screenInputsX.at(1).x();
00361 double y2Screen = m_screenInputsX.at(1).y();
00362 double x3Screen = m_screenInputsY.at(0).x();
00363 double y3Screen = m_screenInputsY.at(0).y();
00364 double x4Screen = m_screenInputsY.at(1).x();
00365 double y4Screen = m_screenInputsY.at(1).y();
00366
00367
00368 double x1Graph = m_graphOutputsX.at(0);
00369 double x2Graph = m_graphOutputsX.at(1);
00370 double y3Graph = m_graphOutputsY.at(0);
00371 double y4Graph = m_graphOutputsY.at(1);
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 double A00 = x1Screen - x2Screen;
00383 double A01 = x4Screen - x3Screen;
00384 double A10 = y1Screen - y2Screen;
00385 double A11 = y4Screen - y3Screen;
00386 double b0 = x1Screen - x3Screen;
00387 double b1 = y1Screen - y3Screen;
00388 double numeratorx = (b0 * A11 - A01 * b1);
00389 double numeratory = (A00 * b1 - b0 * A10);
00390 double denominator = (A00 * A11 - A01 * A10);
00391 double sx = numeratorx / denominator;
00392 double sy = numeratory / denominator;
00393
00394
00395 double xIntScreen = (1.0 - sx) * x1Screen + sx * x2Screen;
00396 double yIntScreen = (1.0 - sy) * y3Screen + sy * y4Screen;
00397 double xIntGraph, yIntGraph;
00398 if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR) {
00399 xIntGraph = (1.0 - sx) * x1Graph + sx * x2Graph;
00400 } else {
00401 xIntGraph = qExp ((1.0 - sx) * qLn (x1Graph) + sx * qLn (x2Graph));
00402 }
00403 if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR) {
00404 yIntGraph = (1.0 - sy) * y3Graph + sy * y4Graph;
00405 } else {
00406 yIntGraph = qExp ((1.0 - sy) * qLn (y3Graph) + sy * qLn (y4Graph));
00407 }
00408
00409
00410 double distance1 = qSqrt ((x1Screen - xIntScreen) * (x1Screen - xIntScreen) +
00411 (y1Screen - yIntScreen) * (y1Screen - yIntScreen));
00412 double distance2 = qSqrt ((x2Screen - xIntScreen) * (x2Screen - xIntScreen) +
00413 (y2Screen - yIntScreen) * (y2Screen - yIntScreen));
00414 double distance3 = qSqrt ((x3Screen - xIntScreen) * (x3Screen - xIntScreen) +
00415 (y3Screen - yIntScreen) * (y3Screen - yIntScreen));
00416 double distance4 = qSqrt ((x4Screen - xIntScreen) * (x4Screen - xIntScreen) +
00417 (y4Screen - yIntScreen) * (y4Screen - yIntScreen));
00418
00419
00420
00421
00422
00423 double xFurthestXAxisScreen, yFurthestXAxisScreen, xFurthestYAxisScreen, yFurthestYAxisScreen;
00424 double xFurthestXAxisGraph, yFurthestXAxisGraph, xFurthestYAxisGraph, yFurthestYAxisGraph;
00425 if (distance1 < distance2) {
00426 xFurthestXAxisScreen = x2Screen;
00427 yFurthestXAxisScreen = y2Screen;
00428 xFurthestXAxisGraph = x2Graph;
00429 yFurthestXAxisGraph = yIntGraph;
00430 } else {
00431 xFurthestXAxisScreen = x1Screen;
00432 yFurthestXAxisScreen = y1Screen;
00433 xFurthestXAxisGraph = x1Graph;
00434 yFurthestXAxisGraph = yIntGraph;
00435 }
00436 if (distance3 < distance4) {
00437 xFurthestYAxisScreen = x4Screen;
00438 yFurthestYAxisScreen = y4Screen;
00439 xFurthestYAxisGraph = xIntGraph;
00440 yFurthestYAxisGraph = y4Graph;
00441 } else {
00442 xFurthestYAxisScreen = x3Screen;
00443 yFurthestYAxisScreen = y3Screen;
00444 xFurthestYAxisGraph = xIntGraph;
00445 yFurthestYAxisGraph = y3Graph;
00446 }
00447
00448
00449 m_screenInputsTransform = QTransform (xIntScreen, xFurthestXAxisScreen, xFurthestYAxisScreen,
00450 yIntScreen, yFurthestXAxisScreen, yFurthestYAxisScreen,
00451 1.0 , 1.0 , 1.0 );
00452
00453
00454 m_graphOutputsTransform = QTransform (xIntGraph, xFurthestXAxisGraph, xFurthestYAxisGraph,
00455 yIntGraph, yFurthestXAxisGraph, yFurthestYAxisGraph,
00456 1.0 , 1.0 , 1.0 );
00457 }
00458
00459 QTransform CallbackAxisPointsAbstract::matrixGraph () const
00460 {
00461 return m_graphOutputsTransform;
00462 }
00463
00464 QTransform CallbackAxisPointsAbstract::matrixScreen () const
00465 {
00466 return m_screenInputsTransform;
00467 }
00468
00469 unsigned int CallbackAxisPointsAbstract::numberAxisPoints () const
00470 {
00471 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_2) {
00472 return m_screenInputs.count();
00473 } else if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) {
00474 return m_screenInputs.count();
00475 } else {
00476 return m_screenInputsX.count() + m_screenInputsY.count();
00477 }
00478 }
00479
00480 bool CallbackAxisPointsAbstract::threePointsAreCollinear (const QTransform &transform)
00481 {
00482 return (transform.determinant() == 0);
00483 }