Engauge Digitizer  2
GraphicsScene.cpp
1 /******************************************************************************************************
2  * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3  * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4  * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5  ******************************************************************************************************/
6 
7 #include "CallbackSceneUpdateAfterCommand.h"
8 #include "Curve.h"
9 #include "CurvesGraphs.h"
10 #include "CurveStyles.h"
11 #include "DataKey.h"
12 #include "EngaugeAssert.h"
13 #include "EnumsToQt.h"
14 #include "GeometryWindow.h"
15 #include "GraphicsItemType.h"
16 #include "GraphicsPoint.h"
17 #include "GraphicsPointFactory.h"
18 #include "GraphicsScene.h"
19 #include "Logger.h"
20 #include "MainWindow.h"
21 #include "Point.h"
22 #include "PointStyle.h"
23 #include <QApplication>
24 #include <QGraphicsItem>
25 #include "QtToString.h"
26 #include "SplineDrawer.h"
27 #include "Transformation.h"
28 
30  QGraphicsScene(mainWindow),
31  m_pathItemMultiValued (0)
32 {
33 }
34 
36 {
37 }
38 
39 void GraphicsScene::addTemporaryPoint (const QString &identifier,
40  GraphicsPoint *point)
41 {
42  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::addTemporaryPoint"
43  << " identifer=" << identifier.toLatin1().data();
44 
45  m_graphicsLinesForCurves.addPoint (AXIS_CURVE_NAME,
46  identifier,
48  *point);
49 }
50 
52  GraphicsPoint *point1,
53  const QString &pointIdentifier0,
54  const QString &pointIdentifier1)
55 {
56  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::addTemporaryScaleBar";
57 
58  const double ORDINAL_0 = 0, ORDINAL_1 = 1;
59 
60  m_graphicsLinesForCurves.addPoint (AXIS_CURVE_NAME,
61  pointIdentifier0,
62  ORDINAL_0,
63  *point0);
64  m_graphicsLinesForCurves.addPoint (AXIS_CURVE_NAME,
65  pointIdentifier1,
66  ORDINAL_1,
67  *point1);
68 }
69 
70 GraphicsPoint *GraphicsScene::createPoint (const QString &identifier,
71  const PointStyle &pointStyle,
72  const QPointF &posScreen,
73  GeometryWindow *geometryWindow)
74 {
75  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::createPoint"
76  << " identifier=" << identifier.toLatin1().data();
77 
78  // Ordinal value is initially computed as one plus the max ordinal seen so far. This initial ordinal value will be overridden if the
79  // cordinates determine the ordinal values.
80  //
81  // This is an N-squared algorithm and may be worth replacing later
82  GraphicsPointFactory pointFactory;
83  GraphicsPoint *point = pointFactory.createPoint (*this,
84  identifier,
85  posScreen,
86  pointStyle,
87  geometryWindow);
88 
89  point->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
90 
91  return point;
92 }
93 
94 QString GraphicsScene::dumpCursors () const
95 {
96  QString cursorOverride = (QApplication::overrideCursor () != 0) ?
97  QtCursorToString (QApplication::overrideCursor ()->shape ()) :
98  "<null>";
99  QString cursorImage = QtCursorToString (image()->cursor().shape ());
100 
101  QString dump = QString ("overrideCursor=%1 imageCursor=%2")
102  .arg (cursorOverride)
103  .arg (cursorImage);
104 
105  return dump;
106 }
107 
109 {
110  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::hideAllItemsExceptImage";
111 
112  for (int index = 0; index < QGraphicsScene::items().count(); index++) {
113  QGraphicsItem *item = QGraphicsScene::items().at(index);
114 
115  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt() == GRAPHICS_ITEM_TYPE_IMAGE) {
116 
117  item->show();
118 
119  } else {
120 
121  item->hide();
122 
123  }
124  }
125 }
126 
127 const QGraphicsPixmapItem *GraphicsScene::image () const
128 {
129  // Loop through items in scene to find the image
130  QList<QGraphicsItem*> items = QGraphicsScene::items();
131  QList<QGraphicsItem*>::iterator itr;
132  for (itr = items.begin(); itr != items.end(); itr++) {
133 
134  QGraphicsItem* item = *itr;
135  if (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_IMAGE) {
136 
137  return (QGraphicsPixmapItem *) item;
138  }
139  }
140 
141  return 0;
142 }
143 
145 {
146  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::positionHasChangedPointIdentifiers";
147 
148  QStringList movedIds;
149 
150  const QList<QGraphicsItem*> &items = QGraphicsScene::items();
151  QList<QGraphicsItem*>::const_iterator itr;
152  for (itr = items.begin(); itr != items.end(); itr++) {
153 
154  const QGraphicsItem *item = *itr;
155 
156  // Skip the image and only keep the Points
157  bool isPoint = (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_POINT);
158  if (isPoint) {
159 
160  QString identifier = item->data (DATA_KEY_IDENTIFIER).toString ();
161  bool positionHasChanged = item->data (DATA_KEY_POSITION_HAS_CHANGED).toBool ();
162 
163  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsScene::positionHasChangedPointIdentifiers"
164  << " identifier=" << identifier.toLatin1().data()
165  << " positionHasChanged=" << (positionHasChanged ? "yes" : "no");
166 
167  if (isPoint && positionHasChanged) {
168 
169  // Add Point to the list
170  movedIds << item->data(DATA_KEY_IDENTIFIER).toString ();
171 
172  }
173  }
174  }
175 
176  return movedIds;
177 }
178 
179 void GraphicsScene::printStream (QString indentation,
180  QTextStream &str)
181 {
182  m_graphicsLinesForCurves.printStream (indentation,
183  str);
184 }
185 
186 void GraphicsScene::removePoint (const QString &identifier)
187 {
188  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::removePoint identifier=" << identifier.toLatin1().data();
189 
190  m_graphicsLinesForCurves.removePoint (identifier);
191 }
192 
194 {
195  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::removeTemporaryPointIfExists";
196 
197  m_graphicsLinesForCurves.removeTemporaryPointIfExists ();
198 }
199 
201 {
202  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::removeTemporaryScaleBarIfExists";
203 }
204 
206 {
207  // LOG4CPP_INFO_S is below
208 
209  int itemsBefore = items().count();
210 
211  m_graphicsLinesForCurves.resetOnLoad();
212 
213  int itemsAfter = items().count();
214 
215  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::resetOnLoad"
216  << " itemsBefore=" << itemsBefore
217  << " itemsAfter=" << itemsAfter;
218 }
219 
221 {
222  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::resetPositionHasChangedFlags";
223 
224  QList<QGraphicsItem*> itms = items ();
225  QList<QGraphicsItem*>::const_iterator itr;
226  for (itr = itms.begin (); itr != itms.end (); itr++) {
227 
228  QGraphicsItem *item = *itr;
229  item->setData (DATA_KEY_POSITION_HAS_CHANGED, false);
230  }
231 }
232 
234  bool showAll,
235  const QString &curveNameWanted)
236 {
237  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::showCurves"
238  << " show=" << (show ? "true" : "false")
239  << " showAll=" << (showAll ? "true" : "false")
240  << " curve=" << curveNameWanted.toLatin1().data();
241 
242  const QList<QGraphicsItem*> &items = QGraphicsScene::items();
243  QList<QGraphicsItem*>::const_iterator itr;
244  for (itr = items.begin(); itr != items.end(); itr++) {
245 
246  QGraphicsItem* item = *itr;
247 
248  // Skip the image and only process the Points
249  bool isPoint = (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_POINT);
250  bool isCurve = (item->data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt () == GRAPHICS_ITEM_TYPE_LINE);
251 
252  if (isPoint || isCurve) {
253 
254  bool showThis = show;
255  if (show && !showAll) {
256  QString identifier = item->data (DATA_KEY_IDENTIFIER).toString ();
257 
258  if (isPoint) {
259 
260  QString curveNameGot = Point::curveNameFromPointIdentifier (identifier);
261  showThis = (curveNameWanted == curveNameGot);
262 
263  } else {
264 
265  showThis = (curveNameWanted == identifier);
266 
267  }
268  }
269 
270  item->setVisible (showThis);
271 
272  }
273  }
274 }
275 
277  double highlightOpacity,
278  GeometryWindow *geometryWindow,
279  const Transformation &transformation)
280 {
281  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updateAfterCommand";
282 
283  m_graphicsLinesForCurves.updateHighlightOpacity (highlightOpacity);
284 
285  updateCurves (cmdMediator);
286 
287  // Update the points
288  updatePointMembership (cmdMediator,
289  geometryWindow,
290  transformation);
291 }
292 
293 void GraphicsScene::updateCurves (CmdMediator &cmdMediator)
294 {
295  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updateCurves";
296 
297  // Desired curve names include both axes and graph curve names
298  QStringList curveNames;
299  curveNames << AXIS_CURVE_NAME;
300  curveNames << cmdMediator.document().curvesGraphsNames();
301 
302  m_graphicsLinesForCurves.addRemoveCurves (*this,
303  curveNames);
304 }
305 
306 void GraphicsScene::updateCurveStyles (const CurveStyles &modelCurveStyles)
307 {
308  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updateCurveStyles";
309 
310  m_graphicsLinesForCurves.updateCurveStyles (modelCurveStyles);
311 }
312 
314  const Transformation &transformation)
315 {
316  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updateGraphicsLinesToMatchGraphicsPoints";
317 
318  if (transformation.transformIsDefined()) {
319 
320  // Ordinals must be updated to reflect reordering that may have resulted from dragging points
321  m_graphicsLinesForCurves.updatePointOrdinalsAfterDrag (curveStyles,
322  transformation);
323 
324  // Recompute the lines one time for efficiency
325  SplineDrawer splineDrawer (transformation);
326  QPainterPath pathMultiValued;
327  LineStyle lineMultiValued;
328  m_graphicsLinesForCurves.updateGraphicsLinesToMatchGraphicsPoints (curveStyles,
329  splineDrawer,
330  pathMultiValued,
331  lineMultiValued);
332 
333  updatePathItemMultiValued (pathMultiValued,
334  lineMultiValued);
335  }
336 }
337 
338 void GraphicsScene::updatePathItemMultiValued (const QPainterPath &pathMultiValued,
339  const LineStyle &lineMultiValued)
340 {
341  // It looks much better to use a consistent line width
342  int lineWidth = lineMultiValued.width();
343 
344  // Draw m_curveMultiValued. If empty then nothing will appear
345  delete m_pathItemMultiValued;
346  m_pathItemMultiValued = this->addPath (pathMultiValued);
347  m_pathItemMultiValued->setPen (QPen (QBrush (QColor (Qt::red)),
348  lineWidth,
349  Qt::DotLine));
350  m_pathItemMultiValued->setAcceptHoverEvents (true);
351  m_pathItemMultiValued->setToolTip (tr ("Function currently has multiple Y values for one X value. Please adjust nearby points, "
352  "or change the curve type in Curve Properties"));
353 }
354 
355 void GraphicsScene::updatePointMembership (CmdMediator &cmdMediator,
356  GeometryWindow *geometryWindow,
357  const Transformation &transformation)
358 {
359  LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::updatePointMembership";
360 
361  CallbackSceneUpdateAfterCommand ftor (m_graphicsLinesForCurves,
362  *this,
363  cmdMediator.document (),
364  geometryWindow);
365  Functor2wRet<const QString &, const Point &, CallbackSearchReturn> ftorWithCallback = functor_ret (ftor,
367 
368  // First pass:
369  // 1) Mark all points as Not Wanted (this is done while creating the map)
370  m_graphicsLinesForCurves.lineMembershipReset ();
371 
372  // Next pass:
373  // 1) Existing points that are found in the map are marked as Wanted
374  // 2) Add new points that were just created in the Document. The new points are marked as Wanted
375  cmdMediator.iterateThroughCurvePointsAxes (ftorWithCallback);
376  cmdMediator.iterateThroughCurvesPointsGraphs (ftorWithCallback);
377 
378  // Next pass:
379  // 1) Remove points that were just removed from the Document
380  SplineDrawer splineDrawer (transformation);
381  QPainterPath pathMultiValued;
382  LineStyle lineMultiValued;
383  m_graphicsLinesForCurves.lineMembershipPurge (cmdMediator.document().modelCurveStyles(),
384  splineDrawer,
385  pathMultiValued,
386  lineMultiValued);
387  updatePathItemMultiValued (pathMultiValued,
388  lineMultiValued);
389 }
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &curveStyles, SplineDrawer &splineDrawer, QPainterPath &pathMultiValued, LineStyle &lineMultiValued)
Calls to moveLinesWithDraggedPoint have finished so update the lines correspondingly.
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &modelCurveStyles, const Transformation &transformation)
A mouse move has just occurred so move the selected points, since they were dragged.
void removePoint(const QString &identifier)
Remove the specified point. The act of deleting it will automatically remove it from the GraphicsScen...
static QString curveNameFromPointIdentifier(const QString &pointIdentifier)
Parse the curve name from the specified point identifier. This does the opposite of uniqueIdentifierG...
Definition: Point.cpp:227
Factor for generating GraphicsPointAbstractBase class objects.
Callback for updating the QGraphicsItems in the scene after a command may have modified Points in Cur...
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
void printStream(QString indentation, QTextStream &str)
Debugging method that supports print method of this class and printStream method of some other class(...
void removePoint(const QString &identifier)
Remove specified point. This aborts if the point does not exist.
unsigned int width() const
Width of line.
Definition: LineStyle.cpp:173
GraphicsScene(MainWindow *mainWindow)
Single constructor.
Model for DlgSettingsCurveProperties and CmdSettingsCurveProperties.
Definition: CurveStyles.h:22
void addPoint(const QString &curveName, const QString &pointIdentifier, double ordinal, GraphicsPoint &point)
Add new point.
void lineMembershipReset()
Mark points as unwanted. Afterwards, lineMembershipPurge gets called.
void addTemporaryScaleBar(GraphicsPoint *point0, GraphicsPoint *point1, const QString &pointIdentifier0, const QString &pointIdentifier1)
Add temporary scale bar to scene.
void removeTemporaryScaleBarIfExists()
Remove temporary scale bar, composed of two points and the line between them.
void removeTemporaryPointIfExists()
Remove temporary point if it exists.
Window that displays the geometry information, as a table, for the current curve.
QStringList positionHasChangedPointIdentifiers() const
Return a list of identifiers for the points that have moved since the last call to resetPositionHasCh...
void setData(int key, const QVariant &data)
Proxy method for QGraphicsItem::setData.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
CallbackSearchReturn callback(const QString &, const Point &point)
Callback method.
void updateAfterCommand(CmdMediator &cmdMediator, double highlightOpacity, GeometryWindow *geometryWindow, const Transformation &transformation)
Update the Points and their Curves after executing a command.
GraphicsPoint * createPoint(QGraphicsScene &scene, const QString &identifier, const QPointF &posScreen, const PointStyle &pointStyle, GeometryWindow *geometryWindow)
Create circle or polygon point according to the PointStyle.
void updatePointOrdinalsAfterDrag(const CurveStyles &curveStyles, const Transformation &transformation)
See GraphicsScene::updateOrdinalsAfterDrag.
GraphicsPoint * createPoint(const QString &identifier, const PointStyle &pointStyle, const QPointF &posScreen, GeometryWindow *geometryWindow)
Create one QGraphicsItem-based object that represents one Point. It is NOT added to m_graphicsLinesFo...
Affine transformation between screen and graph coordinates, based on digitized axis points.
Details for a specific Point.
Definition: PointStyle.h:20
virtual ~GraphicsScene()
Virtual destructor needed since using Q_OBJECT.
static double UNDEFINED_ORDINAL()
Get method for undefined ordinal constant.
Definition: Point.h:134
void resetPositionHasChangedFlags()
Reset positionHasChanged flag for all items. Typically this is done as part of mousePressEvent.
Details for a specific Line.
Definition: LineStyle.h:19
void lineMembershipPurge(const CurveStyles &curveStyles, SplineDrawer &splineDrawer, QPainterPath &pathMultiValued, LineStyle &lineMultiValued)
Mark the end of addPoint calls. Remove stale lines, insert missing lines, and draw the graphics lines...
Graphics item for drawing a circular or polygonal Point.
Definition: GraphicsPoint.h:43
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update curve styles after settings changed.
void removeTemporaryPointIfExists()
Remove temporary point if it exists.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded.
Command queue stack.
Definition: CmdMediator.h:23
void addTemporaryPoint(const QString &identifier, GraphicsPoint *point)
Add one temporary point to m_graphicsLinesForCurves. Non-temporary points are handled by the updateLi...
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update the curve style for every curve.
void iterateThroughCurvesPointsGraphs(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for all the graphs curves.
Definition: CmdMediator.cpp:97
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Definition: CmdMediator.cpp:87
This class takes the output from Spline and uses that to draw the curve in the graphics window,...
Definition: SplineDrawer.h:35
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:698
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded.
void hideAllItemsExceptImage()
Hide all graphics items, except background image, in preparation for preview during IMPORT_TYPE_ADVAN...
void addRemoveCurves(GraphicsScene &scene, const QStringList &curveNames)
Add new curves and remove expired curves to match the specified list.
void showCurves(bool show, bool showAll=false, const QString &curveName="")
Show or hide all Curves (if showAll is true) or just the selected Curve (if showAll is false);.
void updateHighlightOpacity(double highlightOpacity)
Update the highlight opacity value. This may or may not affect the current display immediately depend...
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:345
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:91