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_3) {
00087 return callbackRequire3AxisPoints (posScreen,
00088 posGraph);
00089 } else {
00090 return callbackRequire4AxisPoints (point.isXOnly(),
00091 posScreen,
00092 posGraph);
00093 }
00094 }
00095
00096 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire3AxisPoints (const QPointF &posScreen,
00097 const QPointF &posGraph)
00098 {
00099 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
00100
00101
00102 int numberPoints = m_screenInputs.count();
00103 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
00104 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
00105 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
00106 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
00107
00108 if (numberPoints < 3) {
00109
00110
00111 m_screenInputs.push_back (posScreen);
00112 m_graphOutputs.push_back (posGraph);
00113 numberPoints = m_screenInputs.count();
00114
00115 if (numberPoints == 3) {
00116 loadTransforms3 ();
00117 }
00118
00119
00120 if (anyPointsRepeatPair (m_screenInputs)) {
00121
00122 m_isError = true;
00123 m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point");
00124 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00125
00126 } else if (anyPointsRepeatPair (m_graphOutputs)) {
00127
00128 m_isError = true;
00129 m_errorMessage = QObject::tr ("New axis point cannot have the same graph coordinates as an existing axis point");
00130 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00131
00132 } else if ((numberPoints == 3) && threePointsAreCollinear (m_screenInputsTransform)) {
00133
00134 m_isError = true;
00135 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line on the screen");
00136 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00137
00138 } else if ((numberPoints == 3) && threePointsAreCollinear (m_graphOutputsTransform)) {
00139
00140 m_isError = true;
00141 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line in graph coordinates");
00142 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00143
00144 }
00145 }
00146
00147 if (m_screenInputs.count() > 2) {
00148
00149
00150 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00151
00152 }
00153
00154 return rtn;
00155 }
00156
00157 CallbackSearchReturn CallbackAxisPointsAbstract::callbackRequire4AxisPoints (bool isXOnly,
00158 const QPointF &posScreen,
00159 const QPointF &posGraph)
00160 {
00161 CallbackSearchReturn rtn = CALLBACK_SEARCH_RETURN_CONTINUE;
00162
00163
00164 int numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
00165 if ((numberPoints == 0) || (posGraph.x () < m_xGraphLow)) { m_xGraphLow = posGraph.x (); }
00166 if ((numberPoints == 0) || (posGraph.y () < m_yGraphLow)) { m_yGraphLow = posGraph.y (); }
00167 if ((numberPoints == 0) || (posGraph.x () > m_xGraphHigh)) { m_xGraphHigh = posGraph.x (); }
00168 if ((numberPoints == 0) || (posGraph.y () > m_yGraphHigh)) { m_yGraphHigh = posGraph.y (); }
00169
00170 if (numberPoints < 4) {
00171
00172
00173 if (isXOnly) {
00174
00175 m_screenInputsX.push_back (posScreen);
00176 m_graphOutputsX.push_back (posGraph.x());
00177
00178 } else {
00179
00180 m_screenInputsY.push_back (posScreen);
00181 m_graphOutputsY.push_back (posGraph.y());
00182
00183 }
00184
00185 numberPoints = m_screenInputsX.count() + m_screenInputsY.count();
00186 if (numberPoints == 4) {
00187 loadTransforms4 ();
00188 }
00189 }
00190
00191 if (m_screenInputsX.count() > 2) {
00192
00193 m_isError = true;
00194 m_errorMessage = QObject::tr ("Too many x axis points. There should only be two");
00195 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00196
00197 } else if (m_screenInputsY.count() > 2) {
00198
00199 m_isError = true;
00200 m_errorMessage = QObject::tr ("Too many y axis points. There should only be two");
00201 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00202
00203 } else {
00204
00205 if ((m_screenInputsX.count() == 2) &&
00206 (m_screenInputsY.count() == 2)) {
00207
00208
00209 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00210 }
00211
00212
00213 if (anyPointsRepeatPair (m_screenInputsX) ||
00214 anyPointsRepeatPair (m_screenInputsY)) {
00215
00216 m_isError = true;
00217 m_errorMessage = QObject::tr ("New axis point cannot be at the same screen position as an existing axis point");
00218 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00219
00220 } else if (anyPointsRepeatSingle (m_graphOutputsX) ||
00221 anyPointsRepeatSingle (m_graphOutputsY)) {
00222
00223 m_isError = true;
00224 m_errorMessage = QObject::tr ("New axis point cannot have the same graph coordinates as an existing axis point");
00225 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00226
00227 } else if ((numberPoints == 4) && threePointsAreCollinear (m_screenInputsTransform)) {
00228
00229 m_isError = true;
00230 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line on the screen");
00231 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00232
00233 } else if ((numberPoints == 4) && threePointsAreCollinear (m_graphOutputsTransform)) {
00234
00235 m_isError = true;
00236 m_errorMessage = QObject::tr ("No more than two axis points can lie along the same line in graph coordinates");
00237 rtn = CALLBACK_SEARCH_RETURN_INTERRUPT;
00238
00239 }
00240 }
00241
00242 return rtn;
00243 }
00244
00245 DocumentAxesPointsRequired CallbackAxisPointsAbstract::documentAxesPointsRequired() const
00246 {
00247 return m_documentAxesPointsRequired;
00248 }
00249
00250 void CallbackAxisPointsAbstract::loadTransforms3 ()
00251 {
00252
00253 m_screenInputsTransform = QTransform (m_screenInputs.at(0).x(), m_screenInputs.at(1).x(), m_screenInputs.at(2).x(),
00254 m_screenInputs.at(0).y(), m_screenInputs.at(1).y(), m_screenInputs.at(2).y(),
00255 1.0 , 1.0 , 1.0 );
00256
00257
00258 m_graphOutputsTransform = QTransform (m_graphOutputs.at(0).x(), m_graphOutputs.at(1).x(), m_graphOutputs.at(2).x(),
00259 m_graphOutputs.at(0).y(), m_graphOutputs.at(1).y(), m_graphOutputs.at(2).y(),
00260 1.0 , 1.0 , 1.0 );
00261 }
00262
00263 void CallbackAxisPointsAbstract::loadTransforms4 ()
00264 {
00265 double x1Screen = m_screenInputsX.at(0).x();
00266 double y1Screen = m_screenInputsX.at(0).y();
00267 double x2Screen = m_screenInputsX.at(1).x();
00268 double y2Screen = m_screenInputsX.at(1).y();
00269 double x3Screen = m_screenInputsY.at(0).x();
00270 double y3Screen = m_screenInputsY.at(0).y();
00271 double x4Screen = m_screenInputsY.at(1).x();
00272 double y4Screen = m_screenInputsY.at(1).y();
00273
00274
00275 double x1Graph = m_graphOutputsX.at(0);
00276 double x2Graph = m_graphOutputsX.at(1);
00277 double y3Graph = m_graphOutputsY.at(0);
00278 double y4Graph = m_graphOutputsY.at(1);
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 double A00 = x1Screen - x2Screen;
00290 double A01 = x4Screen - x3Screen;
00291 double A10 = y1Screen - y2Screen;
00292 double A11 = y4Screen - y3Screen;
00293 double b0 = x1Screen - x3Screen;
00294 double b1 = y1Screen - y3Screen;
00295 double numeratorx = (b0 * A11 - A01 * b1);
00296 double numeratory = (A00 * b1 - b0 * A10);
00297 double denominator = (A00 * A11 - A01 * A10);
00298 double sx = numeratorx / denominator;
00299 double sy = numeratory / denominator;
00300
00301
00302 double xIntScreen = (1.0 - sx) * x1Screen + sx * x2Screen;
00303 double yIntScreen = (1.0 - sy) * y3Screen + sy * y4Screen;
00304 double xIntGraph, yIntGraph;
00305 if (m_modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR) {
00306 xIntGraph = (1.0 - sx) * x1Graph + sx * x2Graph;
00307 } else {
00308 xIntGraph = qExp ((1.0 - sx) * qLn (x1Graph) + sx * qLn (x2Graph));
00309 }
00310 if (m_modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR) {
00311 yIntGraph = (1.0 - sy) * y3Graph + sy * y4Graph;
00312 } else {
00313 yIntGraph = qExp ((1.0 - sy) * qLn (y3Graph) + sy * qLn (y4Graph));
00314 }
00315
00316
00317 double distance1 = qSqrt ((x1Screen - xIntScreen) * (x1Screen - xIntScreen) +
00318 (y1Screen - yIntScreen) * (y1Screen - yIntScreen));
00319 double distance2 = qSqrt ((x2Screen - xIntScreen) * (x2Screen - xIntScreen) +
00320 (y2Screen - yIntScreen) * (y2Screen - yIntScreen));
00321 double distance3 = qSqrt ((x3Screen - xIntScreen) * (x3Screen - xIntScreen) +
00322 (y3Screen - yIntScreen) * (y3Screen - yIntScreen));
00323 double distance4 = qSqrt ((x4Screen - xIntScreen) * (x4Screen - xIntScreen) +
00324 (y4Screen - yIntScreen) * (y4Screen - yIntScreen));
00325
00326
00327
00328
00329
00330 double xFurthestXAxisScreen, yFurthestXAxisScreen, xFurthestYAxisScreen, yFurthestYAxisScreen;
00331 double xFurthestXAxisGraph, yFurthestXAxisGraph, xFurthestYAxisGraph, yFurthestYAxisGraph;
00332 if (distance1 < distance2) {
00333 xFurthestXAxisScreen = x2Screen;
00334 yFurthestXAxisScreen = y2Screen;
00335 xFurthestXAxisGraph = x2Graph;
00336 yFurthestXAxisGraph = yIntGraph;
00337 } else {
00338 xFurthestXAxisScreen = x1Screen;
00339 yFurthestXAxisScreen = y1Screen;
00340 xFurthestXAxisGraph = x1Graph;
00341 yFurthestXAxisGraph = yIntGraph;
00342 }
00343 if (distance3 < distance4) {
00344 xFurthestYAxisScreen = x4Screen;
00345 yFurthestYAxisScreen = y4Screen;
00346 xFurthestYAxisGraph = xIntGraph;
00347 yFurthestYAxisGraph = y4Graph;
00348 } else {
00349 xFurthestYAxisScreen = x3Screen;
00350 yFurthestYAxisScreen = y3Screen;
00351 xFurthestYAxisGraph = xIntGraph;
00352 yFurthestYAxisGraph = y3Graph;
00353 }
00354
00355
00356 m_screenInputsTransform = QTransform (xIntScreen, xFurthestXAxisScreen, xFurthestYAxisScreen,
00357 yIntScreen, yFurthestXAxisScreen, yFurthestYAxisScreen,
00358 1.0 , 1.0 , 1.0 );
00359
00360
00361 m_graphOutputsTransform = QTransform (xIntGraph, xFurthestXAxisGraph, xFurthestYAxisGraph,
00362 yIntGraph, yFurthestXAxisGraph, yFurthestYAxisGraph,
00363 1.0 , 1.0 , 1.0 );
00364 }
00365
00366 QTransform CallbackAxisPointsAbstract::matrixGraph () const
00367 {
00368 return m_graphOutputsTransform;
00369 }
00370
00371 QTransform CallbackAxisPointsAbstract::matrixScreen () const
00372 {
00373 return m_screenInputsTransform;
00374 }
00375
00376 unsigned int CallbackAxisPointsAbstract::numberAxisPoints () const
00377 {
00378 if (m_documentAxesPointsRequired == DOCUMENT_AXES_POINTS_REQUIRED_3) {
00379 return m_screenInputs.count();
00380 } else {
00381 return m_screenInputsX.count() + m_screenInputsY.count();
00382 }
00383 }
00384
00385 bool CallbackAxisPointsAbstract::threePointsAreCollinear (const QTransform &transform)
00386 {
00387 return (transform.determinant() == 0);
00388 }