Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
SpatialPlotTool.cpp
1#include "SpatialPlotTool.h"
2
3#include <iostream>
4
5#include <geos/geom/Polygon.h>
6#include <geos/geom/Point.h>
7
8#include <QHBoxLayout>
9#include <QLabel>
10#include <QMenu>
11#include <QMessageBox>
12#include <QStackedWidget>
13
14#include "Brick.h"
15#include "Camera.h"
16#include "Cube.h"
17#include "CubePlotCurve.h"
18#include "Distance.h"
19#include "InterestOperator.h"
20#include "Latitude.h"
21#include "Longitude.h"
22#include "MdiCubeViewport.h"
23#include "PlotWindow.h"
24#include "PolygonTools.h"
25#include "Projection.h"
26#include "RingPlaneProjection.h"
27#include "TProjection.h"
28#include "Pvl.h"
29#include "RubberBandComboBox.h"
30#include "RubberBandTool.h"
31#include "Statistics.h"
32#include "SurfacePoint.h"
33#include "ToolPad.h"
34#include "UniversalGroundMap.h"
35
36using std::cerr;
37
38namespace Isis {
46 //connect(m_toolPadAction, SIGNAL(activated()), this, SLOT(showPlotWindow()));
47 connect(this, SIGNAL(viewportChanged()), this, SLOT(viewportSelected()));
48
49 m_xUnitsCombo = new QComboBox;
50 }
51
52
59
60
68 m_rubberBandCombo->reset();
69 m_rubberBandCombo->setVisible(true);
70 m_rubberBandCombo->setEnabled(true);
71 rubberBandTool()->setDrawActiveViewportOnly(false);
72 }
73
74
83 m_toolPadAction = new QAction(toolpad);
84 m_toolPadAction->setText("Spatial Plot Tool");
85 m_toolPadAction->setIcon(QPixmap(toolIconDir() + "/spatial_plot.png"));
86 QString text = "<b>Function:</b> Create a spatial plot of the selected pixels' DN values.";
87 m_toolPadAction->setWhatsThis(text);
88 return m_toolPadAction;
89 }
90
91
101 QWidget *wrapper = new QWidget(parent);
102
107 true
108 );
109
111 m_interpolationCombo->addItem("Nearest Neighbor",
112 Interpolator::NearestNeighborType);
113 m_interpolationCombo->addItem("BiLinear",
114 Interpolator::BiLinearType);
115 m_interpolationCombo->addItem("Cubic Convolution",
116 Interpolator::CubicConvolutionType);
117 m_interpolationCombo->setCurrentIndex(
118 m_interpolationCombo->findText("Nearest Neighbor"));
119 connect(m_interpolationCombo, SIGNAL(currentIndexChanged(int)),
120 this, SLOT(refreshPlot()));
121
122 QWidget *abstractToolWidgets =
124
125 QHBoxLayout *layout = new QHBoxLayout(wrapper);
126 layout->setContentsMargins(0, 0, 0, 0);
127 layout->addWidget(m_rubberBandCombo);
128 layout->addWidget(new QLabel("Interpolation:"));
129 layout->addWidget(m_interpolationCombo);
130 layout->addWidget(abstractToolWidgets);
131 layout->addWidget(m_xUnitsCombo);
132 layout->addStretch(1);
133 wrapper->setLayout(layout);
134
135 return wrapper;
136 }
137
138
145
146 PlotCurve::Units preferredUnits =
147 (PlotCurve::Units)m_xUnitsCombo->itemData(
148 m_xUnitsCombo->currentIndex()).toInt();
149
150 while (m_xUnitsCombo->count())
151 m_xUnitsCombo->removeItem(0);
152
153 m_xUnitsCombo->addItem("Pixel Number", PlotCurve::PixelNumber);
154
155 bool haveGroundMaps = true;
156 foreach (MdiCubeViewport *cvp, viewportsToPlot()) {
157 haveGroundMaps = haveGroundMaps && cvp->universalGroundMap();
158 }
159
160 if (haveGroundMaps) {
161 m_xUnitsCombo->addItem("Meters", PlotCurve::Meters);
162 m_xUnitsCombo->addItem("Kilometers", PlotCurve::Kilometers);
163 }
164
165 if (m_xUnitsCombo->findData(preferredUnits) != -1) {
166 m_xUnitsCombo->setCurrentIndex(
167 m_xUnitsCombo->findData(preferredUnits));
168 }
169
170 m_xUnitsCombo->setVisible(m_xUnitsCombo->count() > 1);
171 }
172
173
180 PlotWindow *window = new PlotWindow(
181 "Spatial " + PlotWindow::defaultWindowTitle(),
182 (PlotCurve::Units)m_xUnitsCombo->itemData(
183 m_xUnitsCombo->currentIndex()).toInt(),
184 PlotCurve::CubeDN, qobject_cast<QWidget *>(parent()));
185 return window;
186 }
187
188
195 m_spatialCurves->clear();
196 }
197
198
206 if (selectedWindow()) {
207 selectedWindow()->raise();
208 }
209
210 if (rubberBandTool()->isValid()) {
211 refreshPlot();
212 }
213 else {
214 QMessageBox::information(NULL, "Error",
215 "The selected Area contains no valid pixels",
216 QMessageBox::Ok);
217 }
218 }
219
220
226 MdiCubeViewport *activeViewport = cubeViewport();
227
228 if (activeViewport && rubberBandTool()->isValid()) {
229 // Find which window we want to paste into
230 PlotWindow *targetWindow = selectedWindow(true);
231
232 // if the selected window won't work, create a new one
233 if (targetWindow->xAxisUnits() !=
234 m_xUnitsCombo->itemData(m_xUnitsCombo->currentIndex()).toInt()) {
235 targetWindow = addWindow();
236 }
237
238 // get curves for active viewport and also for any linked viewports
239 foreach (MdiCubeViewport *viewport, viewportsToPlot()) {
240 QVector<QPointF> data = getSpatialStatistics(viewport);
241
242 // load data into curve
243 if (data.size() > 0) {
244 QList<QPoint> rubberBandPoints = rubberBandTool()->vertices();
245
247 int band = ((viewport->isGray()) ? viewport->grayBand() :
248 viewport->redBand());
249 (*m_spatialCurves)[viewport]->setData(new QwtPointSeriesData(data));
250 (*m_spatialCurves)[viewport]->setSource(
251 viewport, rubberBandPoints, band);
252 }
253 }
254
255 targetWindow->replot();
256 updateTool();
257 }
258 }
259
260
266 PlotWindow *targetWindow = selectedWindow();
267
268 if (targetWindow) {
269 PlotCurve::Units targetUnits = (PlotCurve::Units)m_xUnitsCombo->itemData(
270 m_xUnitsCombo->currentIndex()).toInt();
271
272 QPen spatialPen(Qt::white);
273 spatialPen.setWidth(1);
274 spatialPen.setStyle(Qt::SolidLine);
275
276 foreach (MdiCubeViewport *viewport, viewportsToPlot()) {
277 if (!(*m_spatialCurves)[viewport] ||
278 (*m_spatialCurves)[viewport]->xUnits() != targetUnits) {
279 CubePlotCurve *plotCurve = createCurve("DN Values", spatialPen,
280 targetUnits, CubePlotCurve::CubeDN);
281 m_spatialCurves->insert(viewport, plotCurve);
282 targetWindow->add(plotCurve);
283 }
284 }
285 }
286 }
287
288
289 SurfacePoint SpatialPlotTool::resultToSurfacePoint(UniversalGroundMap *groundMap) {
290 SurfacePoint result;
291
292 if (groundMap) {
293 Distance radius(groundMap->LocalRadius(), Distance::Units::Meters);
295 Longitude(groundMap->UniversalLongitude(), Angle::Degrees), radius);
296 }
297
298 return result;
299 }
300
301
310 QList<QPoint> vertices = rubberBandTool()->vertices();
311
312 QVector<QPointF> data;
313
314 PlotCurve::Units targetUnits = (PlotCurve::Units)m_xUnitsCombo->itemData(
315 m_xUnitsCombo->currentIndex()).toInt();
316
317 if (cvp && vertices.size()) {
318 Interpolator interp;
319 interp.SetType(
321 m_interpolationCombo->currentIndex()).toInt());
322
323 Portal dataReader(interp.Samples(), interp.Lines(),
324 cvp->cube()->pixelType());
325
326 int band = ((cvp->isGray()) ? cvp->grayBand() : cvp->redBand());
327
328 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode) {
329 double startSample = Null;
330 double endSample = Null;
331 double startLine = Null;
332 double endLine = Null;
333
334 cvp->viewportToCube(vertices[0].x(), vertices[0].y(),
335 startSample, startLine);
336 cvp->viewportToCube(vertices[1].x(), vertices[1].y(),
337 endSample, endLine);
338
339 // round to the nearest pixel increment
340 int lineLength = qRound(sqrt(pow(startSample - endSample, 2) +
341 pow(startLine - endLine, 2)));
342
343 SurfacePoint startPoint;
344 UniversalGroundMap *groundMap = cvp->universalGroundMap();
345 if (targetUnits != PlotCurve::PixelNumber) {
346 if (groundMap->SetImage(startSample, startLine)) {
347 startPoint = resultToSurfacePoint(groundMap);
348 }
349 else {
350 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
351 tr("Failed to project points along line"),
352 tr("Failed to project (calculate a latitude, longitude, and radius) for the "
353 "starting point of the line (sample [%1], line [%2]).")
354 .arg(startSample).arg(startLine));
355 return data;
356 }
357 }
358
359 if (lineLength > 0) {
360 for(int index = 0; index <= lineLength; index++) {
361 // % across * delta x + initial = x position of point (sample)
362 double sample = (index / (double)lineLength) * (endSample - startSample) +
363 startSample;
364 // move back for interpolation
365 sample -= (interp.Samples() / 2.0 - 0.5);
366
367 double line = (index / (double)lineLength) * (endLine - startLine) +
368 startLine;
369 line -= (interp.Lines() / 2.0 - 0.5);
370
371 dataReader.SetPosition(sample, line, band);
372 cvp->cube()->read(dataReader);
373
374 double result = interp.Interpolate(sample + 0.5, line + 0.5, dataReader.DoubleBuffer());
375
376 if (!IsSpecial(result)) {
377 double plotXValue = index + 1;
378
379 if (targetUnits != PlotCurve::PixelNumber) {
380 plotXValue = sample;
381
382 if (groundMap->SetImage(sample, line)) {
383 Distance xDistance = startPoint.GetDistanceToPoint(resultToSurfacePoint(groundMap));
384
385 if (targetUnits == PlotCurve::Meters)
386 plotXValue = xDistance.meters();
387 else if (targetUnits == PlotCurve::Kilometers)
388 plotXValue = xDistance.kilometers();
389 }
390 else {
391 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
392 tr("Failed to project points along line"),
393 tr("Failed to project (calculate a latitude, longitude, and radius) for a "
394 "point along the line (sample [%1], line [%2]).")
395 .arg(startSample).arg(startLine));
396 return data;
397 }
398 }
399
400 data.append(QPointF(plotXValue, result));
401 }
402 }
403 }
404 else {
405 QMessageBox::information(NULL, "Error",
406 "The selected Area contains no valid pixels",
407 QMessageBox::Ok);
408 }
409 }
410 else if (rubberBandTool()->currentMode() == RubberBandTool::RotatedRectangleMode) {
411 /*
412 * We have a rotated rectangle:
413 *
414 * --acrossLength-->
415 * --------------------
416 * |A B|
417 * | | |
418 * | | |
419 * | | |
420 * | | |
421 * | | | rectangleLength
422 * | | |
423 * | | |
424 * | | |
425 * | | |
426 * | | V
427 * |D C|
428 * -------------------
429 *
430 * A is the point where the user initially clicked to start drawing the
431 * rectangle. A is clickSample, clickLine.
432 *
433 * B is the initial mouse release that defines the width and direction
434 * of the rectangle. B is acrossSample, acrossLine.
435 *
436 * C is not needed for our calculations.
437 *
438 * D is endSample, endLine.
439 */
440 double clickSample = Null;
441 double clickLine = Null;
442 double acrossSample = Null;
443 double acrossLine = Null;
444 double endSample = Null;
445 double endLine = Null;
446
447 cvp->viewportToCube(vertices[0].x(), vertices[0].y(),
448 clickSample, clickLine);
449 cvp->viewportToCube(vertices[1].x(), vertices[1].y(),
450 acrossSample, acrossLine);
451 cvp->viewportToCube(vertices[3].x(), vertices[3].y(),
452 endSample, endLine);
453
454 double acrossVectorX = acrossSample - clickSample;
455 double acrossVectorY = acrossLine - clickLine;
456
457 // Get length of "green" line on the screen
458 int acrossLength = qRound(sqrt(acrossVectorX * acrossVectorX +
459 acrossVectorY * acrossVectorY));
460
461 double sampleStepAcross = (1.0 / (double)acrossLength) * acrossVectorX;
462 double lineStepAcross = (1.0 / (double)acrossLength) * acrossVectorY;
463
464 double lengthVectorSample = endSample - clickSample;
465 double lengthVectorLine = endLine - clickLine;
466
467 // Get length of "red" line on the screen
468 int rectangleLength = qRound(sqrt(lengthVectorSample * lengthVectorSample +
469 lengthVectorLine * lengthVectorLine));
470
471 // Prevent length of zero for later calculations
472 if (rectangleLength == 0) {
473 rectangleLength = 1;
474 }
475
476 SurfacePoint startPoint;
477 UniversalGroundMap *groundMap = cvp->universalGroundMap();
478 if (targetUnits != PlotCurve::PixelNumber) {
479 double midStartSample = (clickSample + acrossSample) / 2.0;
480 double midStartLine = (clickLine + acrossLine) / 2.0;
481 if (groundMap->SetImage(midStartSample, midStartLine)) {
482 startPoint = resultToSurfacePoint(groundMap);
483 }
484 else {
485 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
486 tr("Failed to project points along line"),
487 tr("Failed to project (calculate a latitude, longitude, and radius) for the "
488 "starting point of the line (sample [%1], line [%2]).")
489 .arg(midStartSample).arg(midStartLine));
490 return data;
491 }
492 }
493
494 // walk the "red" line on the screen
495 for(int index = 0; index <= rectangleLength; index++) {
496 Statistics acrossStats;
497
498 // % along length * lengthVectorSample + clickSample = x position of point
499 double sample = (index / (double)rectangleLength) * lengthVectorSample +
500 clickSample;
501 // move back for interpolation
502 sample -= (interp.Samples() / 2.0 - 0.5);
503
504 double line = (index / (double)rectangleLength) * lengthVectorLine +
505 clickLine;
506 line -= (interp.Lines() / 2.0 - 0.5);
507
508 double sampleMid = sample + (acrossLength / 2.0) * sampleStepAcross;
509 double lineMid = line + (acrossLength / 2.0) * lineStepAcross;
510
511 // For each pixel length in the red line direction, we are now recursing through each
512 // pixel length in the green line's direction and adding the pixel values
513 for(int acrossPixel = 0;
514 acrossPixel <= acrossLength;
515 acrossPixel++) {
516 dataReader.SetPosition(sample, line, band);
517 cvp->cube()->read(dataReader);
518 double pixelValue = interp.Interpolate(sample + 0.5, line + 0.5,
519 dataReader.DoubleBuffer());
520
521 if (!IsSpecial(pixelValue)) {
522 acrossStats.AddData(pixelValue);
523 }
524
525 sample += sampleStepAcross;
526 line += lineStepAcross;
527 }
528
529 if (!IsSpecial(acrossStats.Average())) {
530 double plotXValue = index + 1;
531
532 if (targetUnits != PlotCurve::PixelNumber) {
533 if (groundMap->SetImage(sampleMid, lineMid)) {
534 Distance xDistance = startPoint.GetDistanceToPoint(resultToSurfacePoint(groundMap));
535
536 if (targetUnits == PlotCurve::Meters)
537 plotXValue = xDistance.meters();
538 else if (targetUnits == PlotCurve::Kilometers)
539 plotXValue = xDistance.kilometers();
540 }
541 else {
542 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
543 tr("Failed to project points along line"),
544 tr("Failed to project (calculate a latitude, longitude, and radius) for a "
545 "point along the line (sample [%1], line [%2]).")
546 .arg(sampleMid).arg(lineMid));
547 return data;
548 }
549 }
550
551 data.append(QPointF(plotXValue, acrossStats.Average()));
552 }
553 }
554 }
555 }
556
557 return data;
558 }
559}
560
PlotWindow * selectedWindow(bool createIfNeeded=true)
Get the 'active' plot window (the window selected by the user to contain new curves).
QWidget * createToolBarWidget(QStackedWidget *parent)
This provides the standard plot tool options, such as selecting an active plot window.
QList< MdiCubeViewport * > viewportsToPlot()
Get a list of linked viewports that should be plotting when a new plot is requested.
virtual void updateTool()
This forwards all update calls to the plot windows.
PlotWindow * addWindow()
This creates and initializes everything about a plot window.
static CubePlotCurve * createCurve(QString name, QPen pen, PlotCurve::Units xUnits, PlotCurve::Units yUnits)
This is a helper method for children.
AbstractPlotTool(QWidget *parent)
When you construct a plot tool, this initializes the common functionality between plot tools.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition Buffer.h:138
PixelType pixelType() const
Definition Cube.cpp:2032
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
Definition Cube.cpp:1043
This is a plot curve with information relating it to a particular cube or region of a cube.
int redBand() const
void viewportToCube(int x, int y, double &sample, double &line) const
Turns a viewport into a cube.
int grayBand() const
Cube * cube() const
bool isGray() const
UniversalGroundMap * universalGroundMap() const
Distance measurement, usually in meters.
Definition Distance.h:34
double kilometers() const
Get the distance in kilometers.
Definition Distance.cpp:106
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
double meters() const
Get the distance in meters.
Definition Distance.cpp:85
Pixel interpolator.
int Samples()
Returns the number of samples needed by the interpolator.
int Lines()
Returns the number of lines needed by the interpolator.
interpType
The interpolator type, including: None, Nearest Neighbor, BiLinear or Cubic Convultion.
void SetType(const interpType &type)
Sets the type of interpolation.
double Interpolate(const double isamp, const double iline, const double buf[])
Performs an interpolation on the data according to the parameters set in the constructor.
This class is designed to encapsulate the concept of a Latitude.
Definition Latitude.h:51
This class is designed to encapsulate the concept of a Longitude.
Definition Longitude.h:40
Cube display widget for certain Isis MDI applications.
Units
These are all the possible units for the x or y data in a plot curve.
Definition PlotCurve.h:54
@ CubeDN
The data is a Cube DN value.
Definition PlotCurve.h:67
@ Kilometers
The data is in kilometers.
Definition PlotCurve.h:87
@ PixelNumber
The data is a pixel #.
Definition PlotCurve.h:79
@ Meters
The data is in meters.
Definition PlotCurve.h:83
virtual void add(CubePlotCurve *pc)
This method adds the curves to the plot.
static QString defaultWindowTitle()
This is the typical suffix for plot windows, it's here in case we want to update all plot windows to ...
void replot()
Reset the scale of the plot, replot it and emit plot changed.
PlotCurve::Units xAxisUnits() const
This is the data-type of the curves' x data in this plot window.
Buffer for containing a two dimensional section of an image.
Definition Portal.h:36
void SetPosition(const double sample, const double line, const int band)
Sets the line and sample position of the buffer.
Definition Portal.h:93
Combo box for choosing a rubber band type.
@ RotatedRectangle
RotatedRectangle.
QAction * toolPadAction(ToolPad *pad)
This method configures the QAction for this tool.
SpatialPlotTool(QWidget *parent)
Create a spatial plot tool.
QPointer< QComboBox > m_interpolationCombo
Allows the user to choose the interpolation type.
QPointer< RubberBandComboBox > m_rubberBandCombo
Spatial plot rubber band combo box.
void validatePlotCurves()
This method sets up the names, line style, and color of the all the CubePlotCurves that will be used ...
QScopedPointer< QMap< MdiCubeViewport *, QPointer< CubePlotCurve > > > m_spatialCurves
Spatial curve.
void viewportSelected()
This protected slot is called when user selects a viewport.
virtual PlotWindow * createWindow()
Creates a new plot window compatible with the curves in this tool.
QPointer< QAction > m_toolPadAction
Plot tool's action.
void enableRubberBandTool()
This method is called when the tool is activated by the parent, or when the plot mode is changed.
void updateTool()
Updates plot tool.
QVector< QPointF > getSpatialStatistics(MdiCubeViewport *)
virtual void rubberBandComplete()
Called when the user has finished drawing with the rubber band.
void refreshPlot()
This method replots the data, with current settings and rubber band, in the plot window.
virtual void detachCurves()
Forget about all existing spatial plot curves.
QWidget * createToolBarWidget(QStackedWidget *parent)
Creates the widgets for the tool bar.
This class is used to accumulate statistics on double arrays.
Definition Statistics.h:93
double Average() const
Computes and returns the average.
void AddData(const double *data, const unsigned int count)
Add an array of doubles to the accumulators and counters.
This class defines a body-fixed surface point.
Distance GetDistanceToPoint(const SurfacePoint &other) const
Computes and returns the distance between two surface points.
MdiCubeViewport * cubeViewport() const
Return the current cubeviewport.
Definition Tool.h:195
QString toolIconDir() const
returns the path to the icon directory.
Definition Tool.h:111
Universal Ground Map.
double UniversalLongitude() const
Returns the universal longitude of the camera model or projection.
bool SetImage(double sample, double line)
Returns whether the sample/line postion was set successfully in the camera model or projection.
double UniversalLatitude() const
Returns the universal latitude of the camera model or projection.
double LocalRadius() const
Returns the radius of the camera model or projection.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16