Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
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 
263 void GraphicsPoint::setHighlightOpacity (double highlightOpacity)
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.
void setHighlightOpacity(double highlightOpacity)
Set method for highlight opacity.
int lineWidth() const
Get method for line width.
Definition: PointStyle.cpp:119
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(...
QPolygonF polygon() const
Return the polygon for creating a QGraphicsPolygonItem. The size is determined by the radius...
Definition: PointStyle.cpp:155
Base class for adding identifiers to graphics items that represent Points.
PointStyle pointStyle() const
Get method for PointStyle.
Definition: CurveStyle.cpp:75
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.
bool wanted() const
Identify point as wanted//unwanted.
void setPointStyle(const PointStyle &pointStyle)
Update the point style.
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.
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.
ColorPalette paletteColor() const
Get method for point color.
Definition: PointStyle.cpp:150
Container for LineStyle and PointStyle for one Curve.
Definition: CurveStyle.h:18
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
void setShadow(GraphicsPointEllipse *shadow)
Bind this graphics item to its shadow.
This class add event handling to QGraphicsPolygonItem.
QPointF pos() const
Proxy method for QGraphicsItem::pos.
QVariant data(int key) const
Proxy method for QGraphicsItem::data.
void setShadow(GraphicsPointPolygon *shadow)
Bind this graphics item to its shadow.
PointShape shape() const
Get method for point shape.
Definition: PointStyle.cpp:292
void setRadius(int radius)
Update the radius.
void reset()
Mark point as unwanted, and unbind any bound lines.