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

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:29:25