Engauge Digitizer  2
GraphicsScene.cpp
Go to the documentation of this file.
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 
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 (nullptr)
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 
90 
91  return point;
92 }
93 
94 QString GraphicsScene::dumpCursors () const
95 {
96  QString cursorOverride = (QApplication::overrideCursor () != nullptr) ?
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 dynamic_cast<QGraphicsPixmapItem *> (item);
138  }
139  }
140 
141  return nullptr;
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 = signed (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.
#define LOG4CPP_INFO_S(logger)
Definition: convenience.h:18
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.
Unique identifier for QGraphicsItem object
Definition: DataKey.h:15
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.
QString QtCursorToString(Qt::CursorShape cursorShape)
Definition: QtToString.cpp:37
Item type (i.e. image versus point)
Definition: DataKey.h:16
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.
log4cpp::Category * mainCat
Definition: Logger.cpp:14
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:702
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:349
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:91
const QString AXIS_CURVE_NAME
#define LOG4CPP_DEBUG_S(logger)
Definition: convenience.h:20