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
26using namespace std;
27
28namespace Isis {
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;
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
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}
a control measurement
bool m_colorByResidualMagnitude
Are we coloring the movement arrow based on max CM residual magnitude.
int m_measureCount
Measure count threshold for colored vs. black.
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *widget=0)
This virtual paint method is called anytime an update() or paintEvent() is called.
ControlPointGraphicsItem(QPointF center, QPointF apriori, ControlPoint *cp, SerialNumberList *snList, MosaicSceneWidget *scene, QGraphicsItem *parent)
Create a CP graphics item.
double m_residualMagnitude
Residual magnitude threshold for colored vs. black.
bool m_colorByMeasureCount
Are we coloring the movement arrow based on CP measure count.
A single control point.
QList< QString > getCubeSerialNumbers() const
@ Constrained
A Constrained point is a Control Point whose lat/lon/radius is somewhat established and should not be...
@ Fixed
A Fixed point is a Control Point whose lat/lon is well established and should not be changed.
const ControlMeasure * GetMeasure(QString serialNumber) const
Get a control measure based on its cube's serial number.
QString GetPointTypeString() const
Obtain a string representation of the PointType.
QString GetId() const
Return the Id of the control point.
QList< ControlMeasure * > getMeasures(bool excludeIgnored=false) const
QString editPointId()
Return the current control point id loaded in the ControlPointEditWidget.
This widget encompasses the entire mosaic scene.
Serial Number list generator.
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:94
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
const double Null
Value for an Isis Null pixel.
bool IsSpecial(const double d)
Returns if the input pixel is special.
const double PI
The mathematical constant PI.
Definition Constants.h:40
Namespace for the standard library.