Engauge Digitizer  2
GraphicsPoint.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 
7 #include "CurveStyle.h"
8 #include "DataKey.h"
9 #include "EnumsToQt.h"
10 #include "GeometryWindow.h"
11 #include "GraphicsItemType.h"
12 #include "GraphicsPoint.h"
13 #include "GraphicsPointEllipse.h"
14 #include "GraphicsPointPolygon.h"
15 #include "Logger.h"
16 #include "PointStyle.h"
17 #include <QGraphicsEllipseItem>
18 #include <QGraphicsPolygonItem>
19 #include <QGraphicsScene>
20 #include <QGraphicsSceneContextMenuEvent>
21 #include <QObject>
22 #include <QPen>
23 #include <QTextStream>
24 #include "QtToString.h"
25 #include "ZValues.h"
26 
27 const double DEFAULT_HIGHLIGHT_OPACITY = 0.35; // 0=transparent to 1=opaque. Values above 0.5 are very hard to notice
28 const double MAX_OPACITY = 1.0;
29 const double ZERO_WIDTH = 0.0;
30 
31 GraphicsPoint::GraphicsPoint(QGraphicsScene &scene,
32  const QString &identifier,
33  const QPointF &posScreen,
34  const QColor &color,
35  unsigned int radius,
36  double lineWidth,
37  GeometryWindow *geometryWindow) :
39  m_scene (scene),
40  m_graphicsItemEllipse (nullptr),
41  m_shadowZeroWidthEllipse (nullptr),
42  m_graphicsItemPolygon (nullptr),
43  m_shadowZeroWidthPolygon (nullptr),
44  m_identifier (identifier),
45  m_posScreen (posScreen),
46  m_color (color),
47  m_lineWidth (lineWidth),
48  m_wanted (true),
49  m_highlightOpacity (DEFAULT_HIGHLIGHT_OPACITY),
50  m_geometryWindow (geometryWindow)
51 {
52  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::GraphicsPoint"
53  << " identifier=" << identifier.toLatin1 ().data ();
54 
55  createPointEllipse (radius);
56 }
57 
58 GraphicsPoint::GraphicsPoint(QGraphicsScene &scene,
59  const QString &identifier,
60  const QPointF &posScreen,
61  const QColor &color,
62  const QPolygonF &polygon,
63  double lineWidth,
64  GeometryWindow *geometryWindow) :
66  m_scene (scene),
67  m_graphicsItemEllipse (nullptr),
68  m_shadowZeroWidthEllipse (nullptr),
69  m_graphicsItemPolygon (nullptr),
70  m_shadowZeroWidthPolygon (nullptr),
71  m_identifier (identifier),
72  m_posScreen (posScreen),
73  m_color (color),
74  m_lineWidth (lineWidth),
75  m_wanted (true),
76  m_highlightOpacity (DEFAULT_HIGHLIGHT_OPACITY),
77  m_geometryWindow (geometryWindow)
78 {
79  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::GraphicsPoint "
80  << " identifier=" << identifier.toLatin1 ().data ();
81 
82  createPointPolygon (polygon);
83 }
84 
86 {
87  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::~GraphicsPoint";
88 
89  if (m_graphicsItemEllipse == nullptr) {
90 
91  QGraphicsScene *scene = m_graphicsItemPolygon->scene();
92 
93  // Since m_shadowZeroWidthPolygon is a child of m_graphicsItemPolygon, removing the parent removes both
94  scene->removeItem (m_graphicsItemPolygon);
95  delete m_graphicsItemPolygon;
96  m_graphicsItemPolygon = nullptr;
97  m_shadowZeroWidthPolygon = nullptr;
98 
99 
100  } else {
101 
102  QGraphicsScene *scene = m_graphicsItemEllipse->scene();
103 
104  // Since m_shadowZeroWidthEllipse is a child of m_graphicsItemEllipse, removing the parent removes both
105  scene->removeItem (m_graphicsItemEllipse);
106  delete m_graphicsItemEllipse;
107  m_graphicsItemEllipse = nullptr;
108  m_shadowZeroWidthEllipse = nullptr;
109 
110  }
111 }
112 
114 {
115  if (m_graphicsItemEllipse == nullptr) {
116  return m_graphicsItemPolygon->boundingRect ();
117  } else {
118  return m_graphicsItemEllipse->boundingRect ();
119  }
120 }
121 
122 void GraphicsPoint::createPointEllipse (unsigned int radius)
123 {
124  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::createPointEllipse";
125 
126  const int radiusSigned = signed (radius); // Radius must be signed before multiplying by -1 below, for Visual Studio
127  m_graphicsItemEllipse = new GraphicsPointEllipse (*this,
128  QRect (- radiusSigned,
129  - radiusSigned,
130  2 * radiusSigned + 1,
131  2 * radiusSigned + 1));
132  m_scene.addItem (m_graphicsItemEllipse);
133 
134  m_graphicsItemEllipse->setZValue (Z_VALUE_POINT);
135  m_graphicsItemEllipse->setData (DATA_KEY_IDENTIFIER, m_identifier);
136  m_graphicsItemEllipse->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
137  m_graphicsItemEllipse->setPos (m_posScreen.x (),
138  m_posScreen.y ());
139  m_graphicsItemEllipse->setPen (QPen (QBrush (m_color), m_lineWidth));
140  m_graphicsItemEllipse->setEnabled (true);
141  m_graphicsItemEllipse->setFlags (QGraphicsItem::ItemIsSelectable |
142  QGraphicsItem::ItemIsMovable |
143  QGraphicsItem::ItemSendsGeometryChanges);
144  m_graphicsItemEllipse->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
145  if (m_geometryWindow != nullptr) {
146  QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString)));
147  QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString)));
148  }
149 
150  // Shadow item is not selectable so it needs no stored data. Do NOT
151  // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item
152  m_shadowZeroWidthEllipse = new GraphicsPointEllipse (*this,
153  QRect (- radiusSigned,
154  - radiusSigned,
155  2 * radiusSigned + 1,
156  2 * radiusSigned + 1));
157  m_shadowZeroWidthEllipse->setParentItem(m_graphicsItemPolygon); // Dragging parent also drags child
158 
159  m_shadowZeroWidthEllipse->setPen (QPen (QBrush (m_color), ZERO_WIDTH));
160  m_shadowZeroWidthEllipse->setEnabled (true);
161 
162  m_graphicsItemEllipse->setShadow (m_shadowZeroWidthEllipse);
163 }
164 
165 void GraphicsPoint::createPointPolygon (const QPolygonF &polygon)
166 {
167  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::createPointPolygon";
168 
169  m_graphicsItemPolygon = new GraphicsPointPolygon (*this,
170  polygon);
171  m_scene.addItem (m_graphicsItemPolygon);
172 
173  m_graphicsItemPolygon->setZValue (Z_VALUE_POINT);
174  m_graphicsItemPolygon->setData (DATA_KEY_IDENTIFIER, m_identifier);
175  m_graphicsItemPolygon->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
176  m_graphicsItemPolygon->setPos (m_posScreen.x (),
177  m_posScreen.y ());
178  m_graphicsItemPolygon->setPen (QPen (QBrush (m_color), m_lineWidth));
179  m_graphicsItemPolygon->setEnabled (true);
180  m_graphicsItemPolygon->setFlags (QGraphicsItem::ItemIsSelectable |
181  QGraphicsItem::ItemIsMovable |
182  QGraphicsItem::ItemSendsGeometryChanges);
183  m_graphicsItemPolygon->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
184  if (m_geometryWindow != nullptr) {
185  QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString)));
186  QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString)));
187  }
188 
189  // Shadow item is not selectable so it needs no stored data. Do NOT
190  // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item
191  m_shadowZeroWidthPolygon = new GraphicsPointPolygon (*this,
192  polygon);
193  m_shadowZeroWidthPolygon->setParentItem(m_graphicsItemPolygon); // Dragging parent also drags child
194 
195  m_shadowZeroWidthPolygon->setPen (QPen (QBrush (m_color), ZERO_WIDTH));
196  m_shadowZeroWidthPolygon->setEnabled (true);
197 
198  m_graphicsItemPolygon->setShadow (m_shadowZeroWidthPolygon);
199 }
200 
201 QVariant GraphicsPoint::data (int key) const
202 {
203  if (m_graphicsItemEllipse == nullptr) {
204  return m_graphicsItemPolygon->data (key);
205  } else {
206  return m_graphicsItemEllipse->data (key);
207  }
208 }
209 
211 {
212  return m_highlightOpacity;
213 }
214 
215 QPointF GraphicsPoint::pos () const
216 {
217  if (m_graphicsItemEllipse == nullptr) {
218  return m_graphicsItemPolygon->pos ();
219  } else {
220  return m_graphicsItemEllipse->pos ();
221  }
222 }
223 
224 void GraphicsPoint::printStream (QString indentation,
225  QTextStream &str,
226  double ordinalKey) const
227 {
228  str << indentation << "GraphicsPoint\n";
229 
230  indentation += INDENTATION_DELTA;
231 
232  QString identifier;
233  QString pointType;
234  QPointF pos;
235  if (m_graphicsItemEllipse == nullptr) {
236  identifier = m_graphicsItemPolygon->data (DATA_KEY_IDENTIFIER).toString ();
237  pointType = "polygon";
238  pos = m_graphicsItemPolygon->pos();
239  } else {
240  identifier = m_graphicsItemEllipse->data (DATA_KEY_IDENTIFIER).toString ();
241  pointType = "ellipse";
242  pos = m_graphicsItemEllipse->pos();
243  }
244 
245  DataKey type = static_cast<DataKey> (data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt());
246 
247  str << indentation << identifier
248  << " ordinalKey=" << ordinalKey
249  << " dataIdentifier=" << data (DATA_KEY_IDENTIFIER).toString().toLatin1().data()
250  << " dataType=" << dataKeyToString (type).toLatin1().data()
251  << " " << pointType << "Pos=" << QPointFToString (pos) << "\n";
252 }
253 
255 {
256  m_wanted = false;
257 }
258 
259 void GraphicsPoint::setData (int key, const QVariant &data)
260 {
261  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::setData"
262  << " key=" << dataKeyToString (static_cast<DataKey> (key)).toLatin1().data()
263  << " data=" << data.toString().toLatin1().data();
264 
265  if (m_graphicsItemEllipse == nullptr) {
266  m_graphicsItemPolygon->setData (key, data);
267  } else {
268  m_graphicsItemEllipse->setData (key, data);
269  }
270 }
271 
272 void GraphicsPoint::setHighlightOpacity (double highlightOpacity)
273 {
274  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::setHighlightOpacity"
275  << " identifier=" << m_identifier.toLatin1().data()
276  << " highlightOpacity=" << highlightOpacity;
277 
278  m_highlightOpacity = highlightOpacity;
279 }
280 
282 {
283  if (m_graphicsItemEllipse == nullptr) {
284  m_graphicsItemPolygon->setFlag (QGraphicsItem::ItemIsFocusable, false);
285  m_graphicsItemPolygon->setFlag (QGraphicsItem::ItemIsMovable, false);
286  m_graphicsItemPolygon->setFlag (QGraphicsItem::ItemIsSelectable, false);
287  } else {
288  m_graphicsItemEllipse->setFlag (QGraphicsItem::ItemIsFocusable, false);
289  m_graphicsItemEllipse->setFlag (QGraphicsItem::ItemIsMovable, false);
290  m_graphicsItemEllipse->setFlag (QGraphicsItem::ItemIsSelectable, false);
291  }
292 }
293 
295 {
296  // Setting pen and radius of parent graphics items below also affects the child shadows
297  // (m_shadowItemPolygon and m_shadowItemEllipse)
298  if (m_graphicsItemEllipse == nullptr) {
299  if (pointStyle.shape() == POINT_SHAPE_CIRCLE) {
300 
301  // Transition from non-circle to circle. Deleting parent also deletes child shadow
302  delete m_graphicsItemPolygon;
303  m_graphicsItemPolygon = nullptr;
304  m_shadowZeroWidthPolygon = nullptr;
305 
306  createPointEllipse (unsigned (pointStyle.radius()));
307 
308  } else {
309 
310  // Update polygon
311  m_graphicsItemPolygon->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
312  pointStyle.lineWidth()));
313  m_shadowZeroWidthPolygon->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
314  pointStyle.lineWidth()));
315  m_graphicsItemPolygon->setPolygon (pointStyle.polygon());
316  m_shadowZeroWidthPolygon->setPolygon (pointStyle.polygon());
317 
318  }
319  } else {
320  if (pointStyle.shape() != POINT_SHAPE_CIRCLE) {
321 
322  // Transition from circle to non-circlee. Deleting parent also deletes child shadow
323  delete m_graphicsItemEllipse;
324  m_graphicsItemEllipse = nullptr;
325  m_shadowZeroWidthEllipse = nullptr;
326 
327  createPointPolygon (pointStyle.polygon());
328 
329  } else {
330 
331  // Update circle
332  m_graphicsItemEllipse->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
333  pointStyle.lineWidth()));
334  m_shadowZeroWidthEllipse->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
335  pointStyle.lineWidth()));
336  m_graphicsItemEllipse->setRadius (pointStyle.radius());
337  m_shadowZeroWidthEllipse->setRadius (pointStyle.radius());
338  }
339  }
340 }
341 
342 void GraphicsPoint::setPos (const QPointF pos)
343 {
344  if (m_graphicsItemEllipse == nullptr) {
345  m_graphicsItemPolygon->setPos (pos);
346  } else {
347  m_graphicsItemEllipse->setPos (pos);
348  }
349 }
350 
352 {
353  m_wanted = true;
354 }
355 
357 {
358  setPointStyle (curveStyle.pointStyle()); // This point
359 }
360 
362 {
363  return m_wanted;
364 }
void setPassive()
Prevent automatic focus on point (=make it passive) for scale bar so drags can be made to work proper...
QString dataKeyToString(DataKey dataKey)
Definition: DataKey.cpp:9
void setWanted()
Mark point as wanted. Marking as unwanted is done by the reset function.
QPointF pos() const
Proxy method for QGraphicsItem::pos.
void setHighlightOpacity(double highlightOpacity)
Set method for highlight opacity.
const QString INDENTATION_DELTA
const double MAX_OPACITY
QVariant data(int key) const
Proxy method for QGraphicsItem::data.
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
const double DEFAULT_HIGHLIGHT_OPACITY
Base class for adding identifiers to graphics items that represent Points.
Window that displays the geometry information, as a table, for the current curve.
void setData(int key, const QVariant &data)
Proxy method for QGraphicsItem::setData.
void setPos(const QPointF pos)
Update the position.
Unique identifier for QGraphicsItem object
Definition: DataKey.h:15
void setPointStyle(const PointStyle &pointStyle)
Update the point style.
DataKey
Index values for storing item details in QGraphicsItem using setData/data.
Definition: DataKey.h:13
QPolygonF polygon() const
Return the polygon for creating a QGraphicsPolygonItem. The size is determined by the radius.
Definition: PointStyle.cpp:160
void updateCurveStyle(const CurveStyle &curveStyle)
Update point and line styles that comprise the curve style.
GraphicsPoint(QGraphicsScene &scene, const QString &identifier, const QPointF &posScreen, const QColor &color, unsigned int radius, double lineWidth, GeometryWindow *geometryWindow)
Constructor of circular point.
QString QPointFToString(const QPointF &pos)
Definition: QtToString.cpp:17
const int Z_VALUE_POINT
Definition: ZValues.cpp:12
This class add event handling to QGraphicsEllipseItem.
Details for a specific Point.
Definition: PointStyle.h:20
QColor ColorPaletteToQColor(ColorPalette color)
Definition: EnumsToQt.cpp:15
QRectF boundingRect() const
Proxy method for QGraphicsItem::boundingRect.
double highlightOpacity() const
Get method for highlight opacity.
~GraphicsPoint()
Destructor. This remove the graphics item from the scene.
void printStream(QString indentation, QTextStream &str, double ordinalKey) const
Debugging method that supports print method of this class and printStream method of some other class(...
Container for LineStyle and PointStyle for one Curve.
Definition: CurveStyle.h:18
PointShape shape() const
Get method for point shape.
Definition: PointStyle.cpp:315
bool wanted() const
Identify point as wanted//unwanted.
void setShadow(GraphicsPointEllipse *shadow)
Bind this graphics item to its shadow.
This class add event handling to QGraphicsPolygonItem.
const double ZERO_WIDTH
log4cpp::Category * mainCat
Definition: Logger.cpp:14
ColorPalette paletteColor() const
Get method for point color.
Definition: PointStyle.cpp:155
int lineWidth() const
Get method for line width.
Definition: PointStyle.cpp:124
unsigned int radius() const
Radius of point. For a circle this is all that is needed to draw a circle. For a polygon,...
Definition: PointStyle.cpp:276
void setShadow(GraphicsPointPolygon *shadow)
Bind this graphics item to its shadow.
#define LOG4CPP_DEBUG_S(logger)
Definition: convenience.h:20
void setRadius(int radius)
Update the radius.
void reset()
Mark point as unwanted, and unbind any bound lines.