Engauge Digitizer 2
Loading...
Searching...
No Matches
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"
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
39void 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
70GraphicsPoint *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
94QString 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
127const 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
179void GraphicsScene::printStream (QString indentation,
180 QTextStream &str)
181{
182 m_graphicsLinesForCurves.printStream (indentation,
183 str);
184}
185
186void 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
293void 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
306void 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
338void 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
355void 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}
const QString AXIS_CURVE_NAME
@ DATA_KEY_POSITION_HAS_CHANGED
‍Item type (i.e. image versus point)
Definition: DataKey.h:16
@ DATA_KEY_GRAPHICS_ITEM_TYPE
‍Unique identifier for QGraphicsItem object
Definition: DataKey.h:15
@ DATA_KEY_IDENTIFIER
Definition: DataKey.h:14
@ GRAPHICS_ITEM_TYPE_IMAGE
@ GRAPHICS_ITEM_TYPE_LINE
@ GRAPHICS_ITEM_TYPE_POINT
log4cpp::Category * mainCat
Definition: Logger.cpp:14
QString QtCursorToString(Qt::CursorShape cursorShape)
Definition: QtToString.cpp:37
Callback for updating the QGraphicsItems in the scene after a command may have modified Points in Cur...
CallbackSearchReturn callback(const QString &, const Point &point)
Callback method.
Command queue stack.
Definition: CmdMediator.h:24
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
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Definition: CmdMediator.cpp:72
Model for DlgSettingsCurveProperties and CmdSettingsCurveProperties.
Definition: CurveStyles.h:23
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:349
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:702
Window that displays the geometry information, as a table, for the current curve.
void updateHighlightOpacity(double highlightOpacity)
Update the highlight opacity value. This may or may not affect the current display immediately depend...
void updatePointOrdinalsAfterDrag(const CurveStyles &curveStyles, const Transformation &transformation)
See GraphicsScene::updateOrdinalsAfterDrag.
void removePoint(const QString &identifier)
Remove the specified point. The act of deleting it will automatically remove it from the GraphicsScen...
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update the curve style for every curve.
void printStream(QString indentation, QTextStream &str) const
Debugging method that supports print method of this class and printStream method of some other class(...
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded.
void removeTemporaryPointIfExists()
Remove temporary point if it exists.
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...
void addRemoveCurves(GraphicsScene &scene, const QStringList &curveNames)
Add new curves and remove expired curves to match the specified list.
void addPoint(const QString &curveName, const QString &pointIdentifier, double ordinal, GraphicsPoint &point)
Add new point.
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &curveStyles, SplineDrawer &splineDrawer, QPainterPath &pathMultiValued, LineStyle &lineMultiValued)
Calls to moveLinesWithDraggedPoint have finished so update the lines correspondingly.
void lineMembershipReset()
Mark points as unwanted. Afterwards, lineMembershipPurge gets called.
Factor for generating GraphicsPointAbstractBase class objects.
GraphicsPoint * createPoint(QGraphicsScene &scene, const QString &identifier, const QPointF &posScreen, const PointStyle &pointStyle, GeometryWindow *geometryWindow)
Create circle or polygon point according to the PointStyle.
Graphics item for drawing a circular or polygonal Point.
Definition: GraphicsPoint.h:44
void setData(int key, const QVariant &data)
Proxy method for QGraphicsItem::setData.
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...
void updateGraphicsLinesToMatchGraphicsPoints(const CurveStyles &modelCurveStyles, const Transformation &transformation)
A mouse move has just occurred so move the selected points, since they were dragged.
void resetOnLoad()
Reset, when loading a document after the first, to same state that first document was at when loaded.
void removeTemporaryScaleBarIfExists()
Remove temporary scale bar, composed of two points and the line between them.
GraphicsScene(MainWindow *mainWindow)
Single constructor.
virtual ~GraphicsScene()
Virtual destructor needed since using Q_OBJECT.
void updateAfterCommand(CmdMediator &cmdMediator, double highlightOpacity, GeometryWindow *geometryWindow, const Transformation &transformation)
Update the Points and their Curves after executing a command.
void hideAllItemsExceptImage()
Hide all graphics items, except background image, in preparation for preview during IMPORT_TYPE_ADVAN...
void addTemporaryPoint(const QString &identifier, GraphicsPoint *point)
Add one temporary point to m_graphicsLinesForCurves. Non-temporary points are handled by the updateLi...
void addTemporaryScaleBar(GraphicsPoint *point0, GraphicsPoint *point1, const QString &pointIdentifier0, const QString &pointIdentifier1)
Add temporary scale bar to scene.
QStringList positionHasChangedPointIdentifiers() const
Return a list of identifiers for the points that have moved since the last call to resetPositionHasCh...
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 resetPositionHasChangedFlags()
Reset positionHasChanged flag for all items. Typically this is done as part of mousePressEvent.
void printStream(QString indentation, QTextStream &str)
Debugging method that supports print method of this class and printStream method of some other class(...
void removeTemporaryPointIfExists()
Remove temporary point if it exists.
void removePoint(const QString &identifier)
Remove specified point. This aborts if the point does not exist.
void updateCurveStyles(const CurveStyles &modelCurveStyles)
Update curve styles after settings changed.
Details for a specific Line.
Definition: LineStyle.h:20
unsigned int width() const
Width of line.
Definition: LineStyle.cpp:173
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition: MainWindow.h:92
Details for a specific Point.
Definition: PointStyle.h:21
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
static double UNDEFINED_ORDINAL()
Get method for undefined ordinal constant.
Definition: Point.h:134
This class takes the output from Spline and uses that to draw the curve in the graphics window,...
Definition: SplineDrawer.h:36
Affine transformation between screen and graph coordinates, based on digitized axis points.
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
#define LOG4CPP_INFO_S(logger)
Definition: convenience.h:18
#define LOG4CPP_DEBUG_S(logger)
Definition: convenience.h:20