Isis 3 Programmer Reference
ControlPointGraphicsItem.cpp
1 #include "ControlPointGraphicsItem.h"
2 
3 #include <float.h>
4 #include <iostream>
5 
6 #include <QDebug>
7 #include <QEvent>
8 #include <QGraphicsScene>
9 #include <QGraphicsSceneContextMenuEvent>
10 #include <QMenu>
11 #include <QMessageBox>
12 #include <QBrush>
13 #include <QPainterPath>
14 #include <QPen>
15 
16 #include "Constants.h"
17 #include "ControlMeasure.h"
18 #include "ControlPoint.h"
19 #include "Directory.h"
20 #include "FileName.h"
21 #include "MosaicGraphicsView.h"
22 #include "MosaicSceneWidget.h"
23 #include "SerialNumberList.h"
24 #include "Statistics.h"
25 
26 using namespace std;
27 
28 namespace Isis {
33  ControlPointGraphicsItem::ControlPointGraphicsItem(QPointF center,
34  QPointF apriori, ControlPoint *cp, SerialNumberList *snList,
35  MosaicSceneWidget *boundingRectSrc, QGraphicsItem *parent) :
36  QGraphicsRectItem(parent) {
37  m_centerPoint = new QPointF(center);
38  m_mosaicScene = boundingRectSrc;
39  m_controlPoint = cp;
40  m_showArrow = false;
41  m_colorByMeasureCount = false;
43 
44  m_measureCount = -1;
46 
47  setZValue(DBL_MAX);
48 
49  m_origPoint = new QPointF(apriori);
50 
51  // Providing a width of 0 makes pens cosmetic (i.e. always appear as 1 pixel on screen)
52  if (cp->IsIgnored()) {
53  setPen(QPen(Qt::yellow, 0.0));
54  }
55  else if ( (cp->GetType() == ControlPoint::Fixed)
56  || (cp->GetType() == ControlPoint::Constrained) ) {
57  setPen(QPen(Qt::magenta, 0.0));
58  }
59  else { // Free and editLocked
60  setPen(QPen(Qt::darkGreen, 0.0));
61  }
62 
63  setBrush(Qt::NoBrush);
64 
65  setToolTip(makeToolTip(snList));
66 
67  setRect(calcRect());
68 
69  setFlag(QGraphicsItem::ItemIsSelectable, true);
70  setFlag(QGraphicsItem::ItemIsFocusable, true);
71 
72 // setFiltersChildEvents(true);
73 // installEventFilter(this);
74  }
75 
76 
77  ControlPointGraphicsItem::~ControlPointGraphicsItem() {
78  if (m_centerPoint) {
79  delete m_centerPoint;
80  m_centerPoint = NULL;
81  }
82 
83  if (m_origPoint) {
84  delete m_origPoint;
85  m_origPoint = NULL;
86  }
87 
88  m_mosaicScene = NULL;
89  }
90 
91 
99  void ControlPointGraphicsItem::paint(QPainter *painter,
100  const QStyleOptionGraphicsItem *style, QWidget * widget) {
101 
102  QRectF fullRect = calcRect();
103  QRectF crosshairRect = calcCrosshairRect();
104 
105  if (crosshairRect.isNull()) {
106  return;
107  }
108 
109  if (rect() != fullRect) {
110  setRect(fullRect);
111  }
112  else {
113  painter->setPen(pen());
114  painter->setBrush(brush());
115 
116  QPointF center = crosshairRect.center();
117 
118  QPointF centerLeft(crosshairRect.left(), center.y());
119  QPointF centerRight(crosshairRect.right(), center.y());
120  QPointF centerTop(center.x(), crosshairRect.top());
121  QPointF centerBottom(center.x(), crosshairRect.bottom());
122 
123  if (m_mosaicScene->directory() &&
124  m_mosaicScene->directory()->editPointId() == m_controlPoint->GetId()) {
125  QPainterPath path;
126  // Draw circle, then crosshair inside circle
127  path.addEllipse(crosshairRect);
128  path.moveTo(centerTop);
129  path.lineTo(centerBottom);
130  path.moveTo(centerLeft);
131  path.lineTo(centerRight);
132 
133  painter->setPen(QPen(Qt::red, 0.0));
134  painter->drawPath(path);
135  }
136  else {
137  painter->drawLine(centerLeft, centerRight);
138  painter->drawLine(centerTop, centerBottom);
139  }
140 
141  if (!m_origPoint->isNull() && *m_origPoint != *m_centerPoint
142  && m_showArrow) {
143 
145  painter->setPen(Qt::black);
146  painter->setBrush(Qt::black);
147  }
148  else {
149  QColor zeroColor(Qt::black);
150  QColor fullColor(Qt::green);
151 
152  bool isColored = false;
153 
154  if (m_colorByMeasureCount) {
155  int fullColorMeasureCount = qMax(1, m_measureCount);
156  int measureCount = m_controlPoint->getMeasures(true).count();
157  isColored = (measureCount >= fullColorMeasureCount);
158  }
159  else {
160  fullColor = QColor(Qt::red);
161 
162  double fullColorErrorMag = 0.0;
163 
165  fullColorErrorMag = m_residualMagnitude;
166  }
167 
168  Statistics residualStats;
169  foreach (ControlMeasure *cm, m_controlPoint->getMeasures(true)) {
170  residualStats.AddData(cm->GetResidualMagnitude());
171  }
172 
173  if (residualStats.Average() != Null) {
174  double errorMag = residualStats.Maximum();
175  if (errorMag >= fullColorErrorMag) {
176  isColored = true;
177  }
178  }
179  }
180 
181  QColor finalColor = isColored? fullColor : zeroColor;
182 
183  painter->setPen(finalColor);
184  painter->setBrush(finalColor);
185  }
186  painter->drawLine(*m_origPoint, *m_centerPoint);
187 
188  QPolygonF arrowHead = calcArrowHead();
189  painter->drawPolygon(arrowHead);
190  }
191  }
192  }
193 
194 
195  ControlPoint *ControlPointGraphicsItem::controlPoint() {
196  return m_controlPoint;
197  }
198 
199  void ControlPointGraphicsItem::setArrowVisible(bool visible,
200  bool colorByMeasureCount,
201  int measureCount,
202  bool colorByResidualMagnitude,
203  double residualMagnitude) {
204  m_showArrow = visible;
205  m_colorByMeasureCount = colorByMeasureCount;
206  m_measureCount = measureCount;
207  m_colorByResidualMagnitude = colorByResidualMagnitude;
208  m_residualMagnitude = residualMagnitude;
209  setRect(calcRect());
210  update();
211  }
212 
213 
214  void ControlPointGraphicsItem::contextMenuEvent(
215  QGraphicsSceneContextMenuEvent * event) {
216  QMenu menu;
217 
218  QAction *title = menu.addAction(
219  m_controlPoint->GetId());
220  title->setEnabled(false);
221  menu.addSeparator();
222 
223  QAction *infoAction = menu.addAction("Show Point Info");
224 
225  QAction *selected = menu.exec(event->screenPos());
226 
227  if (selected == infoAction) {
228  QMessageBox::information(m_mosaicScene, "Control Point Information",
229  toolTip());
230  }
231  }
232 
233 
234  QRectF ControlPointGraphicsItem::calcRect() const {
235  QRectF pointRect(calcCrosshairRect());
236 
237  if (!m_origPoint->isNull() && pointRect.isValid()) {
238  // Make the rect contain the orig point
239  if (pointRect.left() > m_origPoint->x()) {
240  pointRect.setLeft(m_origPoint->x());
241  }
242  else if (pointRect.right() < m_origPoint->x()) {
243  pointRect.setRight(m_origPoint->x());
244  }
245 
246  if (pointRect.top() > m_origPoint->y()) {
247  pointRect.setTop(m_origPoint->y());
248  }
249  else if (pointRect.bottom() < m_origPoint->y()) {
250  pointRect.setBottom(m_origPoint->y());
251  }
252  }
253 
254  QPolygonF arrowHead = calcArrowHead();
255 
256  if (arrowHead.size() > 2) {
257  pointRect = pointRect.united(arrowHead.boundingRect());
258  }
259 
260  return pointRect;
261  }
262 
263 
264  QRectF ControlPointGraphicsItem::calcCrosshairRect() const {
265  QRectF pointRect;
266 
267  if (m_centerPoint && !m_centerPoint->isNull() && m_mosaicScene) {
268  static const int size = 12;
269  QPoint findSpotScreen =
270  m_mosaicScene->getView()->mapFromScene(*m_centerPoint);
271  QPoint findSpotTopLeftScreen =
272  findSpotScreen - QPoint(size / 2, size / 2);
273 
274  QRect pointRectScreen(findSpotTopLeftScreen, QSize(size, size));
275 
276  pointRect =
277  m_mosaicScene->getView()->mapToScene(pointRectScreen).boundingRect();
278  }
279 
280  return pointRect;
281  }
282 
283 
284  QPolygonF ControlPointGraphicsItem::calcArrowHead() const {
285  QPolygonF arrowHead;
286 
287  if (m_showArrow && !m_origPoint->isNull() &&
288  *m_origPoint != *m_centerPoint) {
289  QRectF crosshairRect = calcCrosshairRect();
290  double headSize = crosshairRect.width() * 4.0 / 5.0;
291 
292  double crosshairSize = headSize;
293 
294  // Draw arrow
295  QPointF lineVector = *m_centerPoint - *m_origPoint;
296  double lineVectorMag = sqrt(lineVector.x() * lineVector.x() +
297  lineVector.y() * lineVector.y());
298  double thetaPointOnLine = crosshairSize / (2 * (tanf(PI / 6) / 2) *
299  lineVectorMag);
300  QPointF pointOnLine = *m_centerPoint - thetaPointOnLine * lineVector;
301 
302  QPointF normalVector = QPointF(-lineVector.y(), lineVector.x());
303  double thetaNormal = crosshairSize / (2 * lineVectorMag);
304 
305  QPointF leftPoint = pointOnLine + thetaNormal * normalVector;
306  QPointF rightPoint = pointOnLine - thetaNormal * normalVector;
307 
308  arrowHead << leftPoint << crosshairRect.center() << rightPoint;
309  }
310 
311  return arrowHead;
312  }
313 
314 
315  QString ControlPointGraphicsItem::makeToolTip(SerialNumberList *snList) {
316  QString toolTip = "<div>Point ID: " +
317  m_controlPoint->GetId();
318  toolTip += "<br />Point Type: " +
319  m_controlPoint->GetPointTypeString();
320  toolTip += "<br />Number of Measures: ";
321  toolTip += toString(m_controlPoint->GetNumMeasures());
322  toolTip += "<br />Ignored: ";
323  toolTip += m_controlPoint->IsIgnored() ? "Yes" : "No";
324  toolTip += "<br />Edit Locked: ";
325  toolTip += m_controlPoint->IsEditLocked() ? "Yes" : "No";
326 
327  toolTip += "<br />";
328 
329  if (snList == NULL) {
330  toolTip += QStringList(m_controlPoint->getCubeSerialNumbers()).join("\n");
331  }
332  else {
333  QStringList serialNums(m_controlPoint->getCubeSerialNumbers());
334 
335  for(int snIndex = 0; snIndex < serialNums.size(); snIndex ++) {
336  QString serialNum = serialNums[snIndex];
337 
338  if (snIndex > 0) {
339  toolTip += "<br />";
340  }
341 
342  if (snList->hasSerialNumber(serialNum)) {
343  toolTip +=
344  FileName(snList->fileName(serialNum)).name();
345  toolTip += " (" + serialNum + ")";
346  }
347  else {
348  toolTip += serialNum;
349  }
350 
351  double residMag = m_controlPoint->GetMeasure(serialNum)->GetResidualMagnitude();
352  if (residMag != Null) {
353  toolTip += " [residual: <font color='red'>" + toString(residMag) + "</font>]";
354  }
355  }
356  }
357 
358  toolTip += "</div>";
359 
360  return toolTip;
361  }
362 
363 
364 //bool MosaicSceneWidget::
365 //(QObject *obj, QEvent *event) {
366 //
367 // switch(event->type()) {
368 // case QMouseEvent::GraphicsSceneMousePress: {
369 
370 
371 }
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:110
A Constrained point is a Control Point whose lat/lon/radius is somewhat established and should not be...
Definition: ControlPoint.h:391
A Fixed point is a Control Point whose lat/lon is well established and should not be changed...
Definition: ControlPoint.h:386
const double PI
The mathematical constant PI.
Definition: Constants.h:56
This widget encompasses the entire mosaic scene.
bool m_colorByMeasureCount
Are we coloring the movement arrow based on CP measure count.
const ControlMeasure * GetMeasure(QString serialNumber) const
Get a control measure based on its cube&#39;s serial number.
double GetResidualMagnitude() const
Return Residual magnitude.
Namespace for the standard library.
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *widget=0)
This virtual paint method is called anytime an update() or paintEvent() is called.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
QString editPointId()
Return the current control point id loaded in the ControlPointEditWidget.
Definition: Directory.cpp:1923
double Maximum() const
Returns the absolute maximum double found in all data passed through the AddData method.
Definition: Statistics.cpp:416
This class is used to accumulate statistics on double arrays.
Definition: Statistics.h:107
double m_residualMagnitude
Residual magnitude threshold for colored vs. black.
QString GetId() const
Return the Id of the control point.
QList< QString > getCubeSerialNumbers() const
QList< ControlMeasure *> getMeasures(bool excludeIgnored=false) const
bool IsSpecial(const double d)
Returns if the input pixel is special.
Definition: SpecialPixel.h:212
A single control point.
Definition: ControlPoint.h:369
QString GetPointTypeString() const
Obtain a string representation of the PointType.
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
a control measurement
int m_measureCount
Measure count threshold for colored vs. black.
PointType GetType() const
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
Definition: Statistics.cpp:154
Serial Number list generator.
double Average() const
Computes and returns the average.
Definition: Statistics.cpp:313
bool m_colorByResidualMagnitude
Are we coloring the movement arrow based on max CM residual magnitude.