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 
114 {
115  if (m_graphicsItemEllipse == 0) {
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 = 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 != 0) {
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 != 0) {
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 == 0) {
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 == 0) {
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 == 0) {
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 = (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 ((DataKey) key).toLatin1().data()
263  << " data=" << data.toString().toLatin1().data();
264 
265  if (m_graphicsItemEllipse == 0) {
266  m_graphicsItemPolygon->setData (key, data);
267  } else {
268  m_graphicsItemEllipse->setData (key, data);
269  }
270 }
271 
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 == 0) {
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 == 0) {
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 = 0;
304  m_shadowZeroWidthPolygon = 0;
305 
306  createPointEllipse (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 = 0;
325  m_shadowZeroWidthEllipse = 0;
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 == 0) {
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...
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
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: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.