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
38
39void GraphicsScene::addTemporaryPoint (const QString &identifier,
40 GraphicsPoint *point)
41{
42 LOG4CPP_INFO_S ((*mainCat)) << "GraphicsScene::addTemporaryPoint"
43 << " identifier=" << 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
Definition DataKey.h:16
@ DATA_KEY_GRAPHICS_ITEM_TYPE
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)
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.
void iterateThroughCurvePointsAxes(const Functor2wRet< const QString &, const Point &, CallbackSearchReturn > &ftorWithCallback)
See Curve::iterateThroughCurvePoints, for the single axes curve.
Document & document()
Provide the Document to commands, primarily for undo/redo processing.
Model for DlgSettingsCurveProperties and CmdSettingsCurveProperties.
Definition CurveStyles.h:23
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition Document.cpp:355
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition Document.cpp:714
Window that displays the geometry information, as a table, for the current curve.
void addRemoveCurves(GraphicsScene &scene, const QStringList &curveNames)
Add new curves and remove expired curves to match the specified list.
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.
void setData(int key, const QVariant &data)
Proxy method for QGraphicsItem::setData.
QVariant data(int key) const
Proxy method for QGraphicsItem::data.
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.
Main window consisting of menu, graphics scene, status bar and optional toolbars as a Single Document...
Definition MainWindow.h:95
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,...
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