Engauge Digitizer  2
GraphicsPoint.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 "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 (0),
41  m_shadowZeroWidthEllipse (0),
42  m_graphicsItemPolygon (0),
43  m_shadowZeroWidthPolygon (0),
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 (0),
68  m_shadowZeroWidthEllipse (0),
69  m_graphicsItemPolygon (0),
70  m_shadowZeroWidthPolygon (0),
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 == 0) {
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 = 0;
97  m_shadowZeroWidthPolygon = 0;
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 = 0;
108  m_shadowZeroWidthEllipse = 0;
109 
110  }
111 }
112 
113 void GraphicsPoint::createPointEllipse (unsigned int radius)
114 {
115  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::createPointEllipse";
116 
117  const int radiusSigned = radius; // Radius must be signed before multiplying by -1 below, for Visual Studio
118  m_graphicsItemEllipse = new GraphicsPointEllipse (*this,
119  QRect (- radiusSigned,
120  - radiusSigned,
121  2 * radiusSigned + 1,
122  2 * radiusSigned + 1));
123  m_scene.addItem (m_graphicsItemEllipse);
124 
125  m_graphicsItemEllipse->setZValue (Z_VALUE_POINT);
126  m_graphicsItemEllipse->setData (DATA_KEY_IDENTIFIER, m_identifier);
127  m_graphicsItemEllipse->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
128  m_graphicsItemEllipse->setPos (m_posScreen.x (),
129  m_posScreen.y ());
130  m_graphicsItemEllipse->setPen (QPen (QBrush (m_color), m_lineWidth));
131  m_graphicsItemEllipse->setEnabled (true);
132  m_graphicsItemEllipse->setFlags (QGraphicsItem::ItemIsSelectable |
133  QGraphicsItem::ItemIsMovable |
134  QGraphicsItem::ItemSendsGeometryChanges);
135  m_graphicsItemEllipse->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
136  if (m_geometryWindow != 0) {
137  QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString)));
138  QObject::connect (m_graphicsItemEllipse, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString)));
139  }
140 
141  // Shadow item is not selectable so it needs no stored data. Do NOT
142  // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item
143  m_shadowZeroWidthEllipse = new GraphicsPointEllipse (*this,
144  QRect (- radiusSigned,
145  - radiusSigned,
146  2 * radiusSigned + 1,
147  2 * radiusSigned + 1));
148  m_shadowZeroWidthEllipse->setParentItem(m_graphicsItemPolygon); // Dragging parent also drags child
149 
150  m_shadowZeroWidthEllipse->setPen (QPen (QBrush (m_color), ZERO_WIDTH));
151  m_shadowZeroWidthEllipse->setEnabled (true);
152 
153  m_graphicsItemEllipse->setShadow (m_shadowZeroWidthEllipse);
154 }
155 
156 void GraphicsPoint::createPointPolygon (const QPolygonF &polygon)
157 {
158  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::createPointPolygon";
159 
160  m_graphicsItemPolygon = new GraphicsPointPolygon (*this,
161  polygon);
162  m_scene.addItem (m_graphicsItemPolygon);
163 
164  m_graphicsItemPolygon->setZValue (Z_VALUE_POINT);
165  m_graphicsItemPolygon->setData (DATA_KEY_IDENTIFIER, m_identifier);
166  m_graphicsItemPolygon->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
167  m_graphicsItemPolygon->setPos (m_posScreen.x (),
168  m_posScreen.y ());
169  m_graphicsItemPolygon->setPen (QPen (QBrush (m_color), m_lineWidth));
170  m_graphicsItemPolygon->setEnabled (true);
171  m_graphicsItemPolygon->setFlags (QGraphicsItem::ItemIsSelectable |
172  QGraphicsItem::ItemIsMovable |
173  QGraphicsItem::ItemSendsGeometryChanges);
174  m_graphicsItemPolygon->setData (DATA_KEY_GRAPHICS_ITEM_TYPE, GRAPHICS_ITEM_TYPE_POINT);
175  if (m_geometryWindow != 0) {
176  QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverEnter (QString)), m_geometryWindow, SLOT (slotPointHoverEnter (QString)));
177  QObject::connect (m_graphicsItemPolygon, SIGNAL (signalPointHoverLeave (QString)), m_geometryWindow, SLOT (slotPointHoverLeave (QString)));
178  }
179 
180  // Shadow item is not selectable so it needs no stored data. Do NOT
181  // call QGraphicsScene::addItem since the QGraphicsItem::setParentItem call adds the item
182  m_shadowZeroWidthPolygon = new GraphicsPointPolygon (*this,
183  polygon);
184  m_shadowZeroWidthPolygon->setParentItem(m_graphicsItemPolygon); // Dragging parent also drags child
185 
186  m_shadowZeroWidthPolygon->setPen (QPen (QBrush (m_color), ZERO_WIDTH));
187  m_shadowZeroWidthPolygon->setEnabled (true);
188 
189  m_graphicsItemPolygon->setShadow (m_shadowZeroWidthPolygon);
190 }
191 
192 QVariant GraphicsPoint::data (int key) const
193 {
194  if (m_graphicsItemEllipse == 0) {
195  return m_graphicsItemPolygon->data (key);
196  } else {
197  return m_graphicsItemEllipse->data (key);
198  }
199 }
200 
202 {
203  return m_highlightOpacity;
204 }
205 
206 QPointF GraphicsPoint::pos () const
207 {
208  if (m_graphicsItemEllipse == 0) {
209  return m_graphicsItemPolygon->pos ();
210  } else {
211  return m_graphicsItemEllipse->pos ();
212  }
213 }
214 
215 void GraphicsPoint::printStream (QString indentation,
216  QTextStream &str,
217  double ordinalKey) const
218 {
219  str << indentation << "GraphicsPoint\n";
220 
221  indentation += INDENTATION_DELTA;
222 
223  QString identifier;
224  QString pointType;
225  QPointF pos;
226  if (m_graphicsItemEllipse == 0) {
227  identifier = m_graphicsItemPolygon->data (DATA_KEY_IDENTIFIER).toString ();
228  pointType = "polygon";
229  pos = m_graphicsItemPolygon->pos();
230  } else {
231  identifier = m_graphicsItemEllipse->data (DATA_KEY_IDENTIFIER).toString ();
232  pointType = "ellipse";
233  pos = m_graphicsItemEllipse->pos();
234  }
235 
236  DataKey type = (DataKey) data (DATA_KEY_GRAPHICS_ITEM_TYPE).toInt();
237 
238  str << indentation << identifier
239  << " ordinalKey=" << ordinalKey
240  << " dataIdentifier=" << data (DATA_KEY_IDENTIFIER).toString().toLatin1().data()
241  << " dataType=" << dataKeyToString (type).toLatin1().data()
242  << " " << pointType << "Pos=" << QPointFToString (pos) << "\n";
243 }
244 
246 {
247  m_wanted = false;
248 }
249 
250 void GraphicsPoint::setData (int key, const QVariant &data)
251 {
252  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::setData"
253  << " key=" << dataKeyToString ((DataKey) key).toLatin1().data()
254  << " data=" << data.toString().toLatin1().data();
255 
256  if (m_graphicsItemEllipse == 0) {
257  m_graphicsItemPolygon->setData (key, data);
258  } else {
259  m_graphicsItemEllipse->setData (key, data);
260  }
261 }
262 
264 {
265  LOG4CPP_DEBUG_S ((*mainCat)) << "GraphicsPoint::setHighlightOpacity"
266  << " identifier=" << m_identifier.toLatin1().data()
267  << " highlightOpacity=" << highlightOpacity;
268 
269  m_highlightOpacity = highlightOpacity;
270 }
271 
273 {
274  // Setting pen and radius of parent graphics items below also affects the child shadows
275  // (m_shadowItemPolygon and m_shadowItemEllipse)
276  if (m_graphicsItemEllipse == 0) {
277  if (pointStyle.shape() == POINT_SHAPE_CIRCLE) {
278 
279  // Transition from non-circle to circle. Deleting parent also deletes child shadow
280  delete m_graphicsItemPolygon;
281  m_graphicsItemPolygon = 0;
282  m_shadowZeroWidthPolygon = 0;
283 
284  createPointEllipse (pointStyle.radius());
285 
286  } else {
287 
288  // Update polygon
289  m_graphicsItemPolygon->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
290  pointStyle.lineWidth()));
291  m_shadowZeroWidthPolygon->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
292  pointStyle.lineWidth()));
293  m_graphicsItemPolygon->setPolygon (pointStyle.polygon());
294  m_shadowZeroWidthPolygon->setPolygon (pointStyle.polygon());
295 
296  }
297  } else {
298  if (pointStyle.shape() != POINT_SHAPE_CIRCLE) {
299 
300  // Transition from circle to non-circlee. Deleting parent also deletes child shadow
301  delete m_graphicsItemEllipse;
302  m_graphicsItemEllipse = 0;
303  m_shadowZeroWidthEllipse = 0;
304 
305  createPointPolygon (pointStyle.polygon());
306 
307  } else {
308 
309  // Update circle
310  m_graphicsItemEllipse->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
311  pointStyle.lineWidth()));
312  m_shadowZeroWidthEllipse->setPen (QPen (ColorPaletteToQColor(pointStyle.paletteColor()),
313  pointStyle.lineWidth()));
314  m_graphicsItemEllipse->setRadius (pointStyle.radius());
315  m_shadowZeroWidthEllipse->setRadius (pointStyle.radius());
316  }
317  }
318 }
319 
320 void GraphicsPoint::setPos (const QPointF pos)
321 {
322  if (m_graphicsItemEllipse == 0) {
323  return m_graphicsItemPolygon->setPos (pos);
324  } else {
325  return m_graphicsItemEllipse->setPos (pos);
326  }
327 }
328 
330 {
331  m_wanted = true;
332 }
333 
335 {
336  setPointStyle (curveStyle.pointStyle()); // This point
337 }
338 
340 {
341  return m_wanted;
342 }
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.
QVariant data(int key) const
Proxy method for QGraphicsItem::data.
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
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.
void setPointStyle(const PointStyle &pointStyle)
Update the point style.
QPolygonF polygon() const
Return the polygon for creating a QGraphicsPolygonItem. The size is determined by the radius...
Definition: PointStyle.cpp:155
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.
This class add event handling to QGraphicsEllipseItem.
int radius() const
Radius of point. For a circle this is all that is needed to draw a circle. For a polygon, the radius determines the size of the polygon.
Definition: PointStyle.cpp:253
Details for a specific Point.
Definition: PointStyle.h:20
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:292
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.
ColorPalette paletteColor() const
Get method for point color.
Definition: PointStyle.cpp:150
int lineWidth() const
Get method for line width.
Definition: PointStyle.cpp:119
void setShadow(GraphicsPointPolygon *shadow)
Bind this graphics item to its shadow.
void setRadius(int radius)
Update the radius.
void reset()
Mark point as unwanted, and unbind any bound lines.