USGS

Isis 3.0 Object Programmers' Reference

Home

StereoTool.cpp
1 #include "StereoTool.h"
2 #include <QtGui>
3 
4 #include <iomanip>
5 #include <cmath>
6 #include <vector>
7 
8 #include "AbstractPlotTool.h"
9 #include "Application.h"
10 #include "AutoReg.h"
11 #include "AutoRegFactory.h"
12 #include "BundleAdjust.h"
13 #include "ControlMeasure.h"
14 #include "ControlNet.h"
15 #include "ControlPoint.h"
16 #include "ControlPointEdit.h"
17 #include "CubePlotCurve.h"
18 #include "Distance.h"
19 #include "FileName.h"
20 #include "History.h"
21 #include "IException.h"
22 #include "IString.h"
23 #include "iTime.h"
24 #include "Latitude.h"
25 #include "Longitude.h"
26 #include "MainWindow.h"
27 #include "MdiCubeViewport.h"
28 #include "PlotCurve.h"
29 #include "PlotWindow.h"
30 #include "ProfileDialog.h"
31 #include "PvlEditDialog.h"
32 #include "PvlObject.h"
33 #include "Projection.h"
34 #include "QIsisApplication.h"
35 #include "RubberBandTool.h"
36 #include "SerialNumber.h"
37 #include "Stereo.h"
38 #include "SurfacePoint.h"
39 #include "Target.h"
40 #include "ToolPad.h"
41 #include "UniversalGroundMap.h"
42 
43 
44 using namespace std;
45 
46 
47 namespace Isis {
48  // initialize static
49 /* !!!! TODOS !!!!
50 
51 1. If DEM radius comboBox, update to DEM , when?
52 
53 
54 */
55 
56 
57 
58  QString StereoTool::lastPtIdValue = "";
59 
66  StereoTool::StereoTool(QWidget *parent) : AbstractPlotTool(parent) {
67 
68  m_editPoint = NULL;
69  m_startPoint = NULL;
70  m_endPoint = NULL;
71 
72  m_serialNumberList = NULL;
73  m_controlNet = NULL;
74  m_leftCube = NULL;
75  m_rightCube = NULL;
76  m_leftGM = NULL;
77  m_rightGM = NULL;
78 
79  m_profileDialog = NULL;
80 
81  m_showWarning = true;
82 
83  m_targetRadius = Distance(0., Distance::Meters);
84  m_baseRadius = Distance(0., Distance::Meters);
85 
86  createStereoTool(parent);
87  connect( this, SIGNAL( toolActivated() ), this, SLOT( activateTool() ) );
88  }
89 
90 
96 
97  m_stereoTool = new QMainWindow(parent);
98  m_stereoTool->setWindowTitle("Elevation Calculator (via stereo pairs)");
99 
100  createMenus();
101 
102  // Place everything in a grid
103  QGridLayout *gridLayout = new QGridLayout();
104  //gridLayout->setSizeConstraint(QLayout::SetFixedSize);
105  // ??? Very tacky-hardcoded to ChipViewport size of ControlPointEdit + xtra.
106  // Is there a better way to do this?
107  gridLayout->setColumnMinimumWidth(0, 310);
108  gridLayout->setColumnMinimumWidth(1, 310);
109  // grid row
110  int row = 0;
111 
112  m_ptIdValue = new QLabel();
113  gridLayout->addWidget(m_ptIdValue, row++, 0);
114 
115  m_leftCubeLabel = new QLabel();
116  m_rightCubeLabel = new QLabel();
117  gridLayout->addWidget(m_leftCubeLabel, row, 0);
118  gridLayout->addWidget(m_rightCubeLabel, row++, 1);
119 
120  m_pointEditor = new ControlPointEdit(NULL, parent, true);
121  gridLayout->addWidget(m_pointEditor, row++, 0, 1, 3);
122  connect( m_pointEditor, SIGNAL( measureSaved() ), this, SLOT( measureSaved() ) );
123  m_pointEditor->show();
124  connect(this,
125  SIGNAL( stretchChipViewport(Stretch *, CubeViewport *) ),
126  m_pointEditor,
127  SIGNAL( stretchChipViewport(Stretch *, CubeViewport *) ) );
128 
129  m_elevationLabel = new QLabel;
130  m_elevationLabel->setToolTip("Calculated elevation in meters.");
131  m_elevationLabel->setWhatsThis("Calculated elevation based on parallax.");
132  m_elevationErrorLabel = new QLabel;
133  m_elevationErrorLabel->setToolTip(
134  "Error in calculated elevation in meters.");
135  m_elevationErrorLabel->setWhatsThis("Error in calculated elevation.");
136  gridLayout->addWidget(m_elevationLabel, row, 0);
137  gridLayout->addWidget(m_elevationErrorLabel, row++, 1);
138 
139  m_baseRadiiLabel = new QLabel;
140  m_baseRadiiLabel->setToolTip("Subtracted from the calculated radius to "
141  "determine elevation.");
142 // m_baseRadiiLabel->setToolTip("Local Radius");
143  m_leftDemRadiiLabel = new QLabel;
144  m_leftDemRadiiLabel->setToolTip("Left Cube DEM Radius");
145  m_rightDemRadiiLabel = new QLabel;
146  m_rightDemRadiiLabel->setToolTip("Right Cube DEM Radius");
147  gridLayout->addWidget(m_baseRadiiLabel, row, 0);
148  gridLayout->addWidget(m_leftDemRadiiLabel, row, 1);
149  gridLayout->addWidget(m_rightDemRadiiLabel, row++, 2);
150 
151 // QPushButton *elevationButton = new QPushButton("Calculate Elevation");
152 // connect(elevationButton, SIGNAL(clicked() ),
153 // this, SLOT(calculateElevation() ));
154 // gridLayout->addWidget(elevationButton, row++, 1);
155 
156  QWidget *cw = new QWidget();
157  cw->setLayout(gridLayout);
158  m_stereoTool->setCentralWidget(cw);
159 
160  connect( this, SIGNAL( editPointChanged() ), this, SLOT( paintAllViewports() ) );
161 
162  }
163 
164 
171 
172  m_save = new QAction(m_stereoTool);
173  m_save->setText("Save Elevation Data...");
174  QString whatsThis =
175  "<b>Function:</b> Saves the elevation calulations to current file.";
176  m_save->setWhatsThis(whatsThis);
177  connect( m_save, SIGNAL( activated() ), this, SLOT( saveElevations() ) );
178  m_save->setDisabled(true);
179 
180  QAction *saveAs = new QAction(m_stereoTool);
181  saveAs->setText("Save Elevation Data As...");
182  whatsThis =
183  "<b>Function:</b> Saves the elevation calulations to a file.";
184  saveAs->setWhatsThis(whatsThis);
185  connect( saveAs, SIGNAL( activated() ), this, SLOT( saveAsElevations() ) );
186 
187  QAction *closeStereoTool = new QAction(m_stereoTool);
188  closeStereoTool->setText("&Close");
189  closeStereoTool->setShortcut(Qt::ALT + Qt::Key_F4);
190  whatsThis =
191  "<b>Function:</b> Closes the Stereo Tool window for this point \
192  <p><b>Shortcut:</b> Alt+F4 </p>";
193  closeStereoTool->setWhatsThis(whatsThis);
194  connect( closeStereoTool, SIGNAL( activated() ), m_stereoTool, SLOT( close() ) );
195 
196  QMenu *fileMenu = m_stereoTool->menuBar()->addMenu("&File");
197  fileMenu->addAction(m_save);
198  fileMenu->addAction(saveAs);
199  fileMenu->addAction(closeStereoTool);
200 
201  QAction *templateFile = new QAction(m_stereoTool);
202  templateFile->setText("&Set registration template");
203  whatsThis =
204  "<b>Function:</b> Allows user to select a new file to set as the registration template";
205  templateFile->setWhatsThis(whatsThis);
206  connect( templateFile, SIGNAL( activated() ), this, SLOT( setTemplateFile() ) );
207 
208  QAction *viewTemplate = new QAction(m_stereoTool);
209  viewTemplate->setText("&View/edit registration template");
210  whatsThis =
211  "<b>Function:</b> Displays the curent registration template. \
212  The user may edit and save changes under a chosen filename.";
213  viewTemplate->setWhatsThis(whatsThis);
214  connect( viewTemplate, SIGNAL( activated() ), this, SLOT( viewTemplateFile() ) );
215 
216 
217  QMenu *optionMenu = m_stereoTool->menuBar()->addMenu("&Options");
218  QMenu *regMenu = optionMenu->addMenu("&Registration");
219 
220  regMenu->addAction(templateFile);
221  regMenu->addAction(viewTemplate);
222  // registrationMenu->addAction(interestOp);
223 
224  QAction *showHelpAct = new QAction("stereo tool &Help", m_stereoTool);
225  showHelpAct->setIcon(QPixmap(toolIconDir() + "/help-contents.png") );
226  connect( showHelpAct, SIGNAL( activated() ), this, SLOT( showHelp() ));
227 
228  QMenu *helpMenu = m_stereoTool->menuBar()->addMenu("&Help");
229  helpMenu->addAction(showHelpAct);
230 
231  }
232 
233 
234 
243  QAction *action = new QAction(pad);
244  action->setIcon( QPixmap(toolIconDir() + "/3d-glasses-icon.png") );
245  action->setToolTip("Stereo");
246  action->setWhatsThis("<strong>Functionality:</strong> "
247  "<ul>"
248  "<li>Calculate elevation at a single point by creating a "
249  "control point between the image pair. "
250  "<ul>"
251  "<h4><strong>Control Point mouse Button Functions:</strong></h4>"
252  "<li>Left: Edit closest point.</li>"
253  "<li>Middle: Delete closest point.</li>"
254  "<li>Right: Create new point at cursor position.</li></ul>"
255  "<li>Left click and drag will create an elevation profile "
256  "after you create the start and end control points. A dialog "
257  "box will be shown to assist.</li>"
258  "<li>Right click and drag will create an elevation profile "
259  "between previously created control points.</li></ul>");
260  return action;
261  }
262 
263 
264 
272  QWidget *StereoTool::createToolBarWidget(QStackedWidget *parent) {
273  QWidget *hbox = new QWidget(parent);
274 
275  QLabel *boxLabel = new QLabel("Local Radius:");
276  m_radiusBox = new QComboBox(hbox);
277  m_radiusBox->addItem("Ellipsoid Equitorial Radius");
278  m_radiusBox->addItem("DEM Radius");
279  m_radiusBox->addItem("Custom Radius");
280  m_radiusBox->setToolTip("Source for local radius");
281  QString text =
282  "<b>Function: </b>Source for the local radius used for elevation "
283  "calculations.";
284  m_radiusBox->setWhatsThis(text);
285  connect( m_radiusBox, SIGNAL( activated(int) ),
286  this, SLOT( updateRadiusLineEdit() ));
287 
288  m_radiusLineEdit = new QLineEdit(hbox);
289  QDoubleValidator *dval = new QDoubleValidator(hbox);
290  m_radiusLineEdit->setValidator(dval);
291  m_radiusLineEdit->setReadOnly(true);
292  m_radiusLineEdit->setToolTip("Custom local radius used for elevation "
293  "calculations. To enter a value, set box to "
294  "the left to \"Custom Radius\"");
295  text =
296  "<b>Function: </b>Custom local radius used to calculate elevations. "
297  "This can be changed by selecting \"Custom Radius\" in the box to "
298  "the left.";
299  m_radiusLineEdit->setWhatsThis(text);
300 // connect(m_radiusLineEdit, SIGNAL(textEdited(QString) ),
301 // this, SLOT(userBaseRadius(QString) ));
302  connect( m_radiusLineEdit, SIGNAL( editingFinished() ),
303  this, SLOT( userBaseRadius() ));
304  // Do not enable unless radius box set to Custom Radius
305  m_radiusLineEdit->setEnabled(false);
306 
307  QLabel *radiusUnit = new QLabel("Meters");
308 
309  QToolButton *helpButton = new QToolButton(hbox);
310  helpButton->setIcon( QPixmap(toolIconDir() + "/help-contents.png") );
311  helpButton->setToolTip("Help");
312  helpButton->setIconSize( QSize(22, 22) );
313  connect( helpButton, SIGNAL( clicked() ), this, SLOT( showHelp() ));
314 
315  QHBoxLayout *layout = new QHBoxLayout;
316  layout->setMargin(0);
317  layout->addWidget(AbstractPlotTool::createToolBarWidget(parent) );
318  layout->addWidget(boxLabel);
319  layout->addWidget(m_radiusBox);
320  layout->addWidget(m_radiusLineEdit);
321  layout->addWidget(radiusUnit);
322  layout->addStretch();
323  layout->addWidget(helpButton);
324  hbox->setLayout(layout);
325 
326  readSettings();
327 
328  return hbox;
329  }
330 
331 
332 
333  void StereoTool::activateTool() {
334 
335  warningDialog();
336  }
337 
338 
339 
341  return new PlotWindow("Elevation Profile", PlotCurve::PixelNumber,
343  qobject_cast<QWidget *>( parent() ) );
344 
345  }
346 
347 
348 
350  }
351 
352 
353 
354  void StereoTool::warningDialog() {
355 
356  if (m_showWarning) {
357  QDialog *warningDialog = new QDialog(m_stereoTool);
358 
359  QVBoxLayout *mainLayout = new QVBoxLayout;
360  warningDialog->setLayout(mainLayout);
361 
362  QLabel *warningsText = new QLabel("<p><strong>Warning:</strong> "
363  "The camera orientations are very critical for correct results. "
364  "Poor orientations will result in bad elevation measurements. The "
365  "camera orientations can be corrected with the programs "
366  "<i>jigsaw, deltack, or qtie.");
367  warningsText->setWordWrap(true);
368  mainLayout->addWidget(warningsText);
369  QCheckBox *showWarning = new QCheckBox("Do not show this message again");
370  showWarning->setChecked(false);
371  mainLayout->addWidget(showWarning);
372 
373  QPushButton *okButton = new QPushButton("OK");
374  mainLayout->addStretch();
375  mainLayout->addWidget(okButton);
376  connect( okButton, SIGNAL( clicked() ), warningDialog, SLOT( accept() ));
377 
378  if ( warningDialog->exec() ) {
379  if ( showWarning->isChecked() ) m_showWarning = false;
380  }
381  writeSettings();
382  }
383 
384  }
385 
386 
387 
388  void StereoTool::showHelp() {
389 
390  QDialog *helpDialog = new QDialog(m_stereoTool);
391  helpDialog->setWindowTitle("Stereo Tool Help");
392 
393  QVBoxLayout *mainLayout = new QVBoxLayout;
394  helpDialog->setLayout(mainLayout);
395 
396  QLabel *stereoTitle = new QLabel("<h2>Stereo Tool</h2>");
397  mainLayout->addWidget(stereoTitle);
398 
399  QLabel *stereoSubtitle = new QLabel("A tool for calculating point elevations "
400  "and elevation profiles using stereo pairs "
401  "of cubes.");
402  stereoSubtitle->setWordWrap(true);
403  mainLayout->addWidget(stereoSubtitle);
404 
405  QTabWidget *tabArea = new QTabWidget;
406  tabArea->setDocumentMode(true);
407  mainLayout->addWidget(tabArea);
408 
409  // TAB 1 - Overview
410  QScrollArea *overviewTab = new QScrollArea;
411  overviewTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
412  overviewTab->setWidgetResizable(true);
413  QWidget *overviewContainer = new QWidget;
414  QVBoxLayout *overviewLayout = new QVBoxLayout;
415  overviewContainer->setLayout(overviewLayout);
416 
417  QLabel *purposeTitle = new QLabel("<h2>Purpose</h2>");
418  overviewLayout->addWidget(purposeTitle);
419 
420  QLabel *purposeText = new QLabel("<p>This tool will use parallax from a "
421  "stereo pair of cubes to calculate elevations at chosen control points "
422  "or create elevation profiles between two chosen control points. "
423  "Elevations are computed from points between the left and right cubes. "
424  "Vectors from the target (planet center) to the spacecraft and target "
425  "to the surface registration points are computed for each point. From "
426  "these points, the elevation is computed.");
427  purposeText->setWordWrap(true);
428  overviewLayout->addWidget(purposeText);
429 
430  QLabel *warningsTitle = new QLabel("<h2>Warnings</h2>");
431  overviewLayout->addWidget(warningsTitle);
432 
433  QLabel *warningsText = new QLabel("<p>The camera orientations are very "
434  "critical for correct results. Poor orientations will result in "
435  "bad elevation measurements. The camera orientations can be corrected "
436  "with the programs <i>jigsaw, deltack, or qtie.");
437  warningsText->setWordWrap(true);
438  overviewLayout->addWidget(warningsText);
439 
440  overviewTab->setWidget(overviewContainer);
441 
442  // TAB 2 - Quick Start
443  QScrollArea *quickTab = new QScrollArea;
444  quickTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
445  quickTab->setWidgetResizable(true);
446  QWidget *quickContainer = new QWidget;
447  QVBoxLayout *quickLayout = new QVBoxLayout;
448  quickContainer->setLayout(quickLayout);
449 
450  QLabel *quickTitle = new QLabel("<h2>Quick Start</h2>");
451  quickLayout->addWidget(quickTitle);
452 
453  QLabel *quickSubTitle = new QLabel("<h3>Preparation:</h3>");
454  quickLayout->addWidget(quickSubTitle);
455 
456  QLabel *quickPrep = new QLabel("<p><ul>"
457  "<li>Open the two cubes of a stereo pair</li>"
458  "<li>Link the two displayed cube windows</li>");
459  quickPrep->setWordWrap(true);
460  quickLayout->addWidget(quickPrep);
461 
462  QLabel *quickFunctionTitle = new QLabel("<h3>Cube Viewport Functions:</h3>");
463  quickLayout->addWidget(quickFunctionTitle);
464 
465  QLabel *quickFunction = new QLabel(
466  "The stereo tool window will be shown once "
467  "you click on a cube viewport window using one of the following "
468  "cube viewport functions.");
469  quickFunction->setWordWrap(true);
470  quickLayout->addWidget(quickFunction);
471 
472  QLabel *quickDesc = new QLabel("<p><ul>"
473  "<li>Calculate elevation at a single point by creating a "
474  "control point between the image pair by right clicking in the cube "
475  "viewport window on the location you are interested in. Once the "
476  "control point is refined, click the \"Save Measure\" button in "
477  "the Stereo Tool window and the elevation will be calculated. The elevation "
478  "reported is relative to the radius which is defined on the toolbar.</li>"
479  "<li>Left click and drag will create an elevation profile "
480  "after you create the start and end control points. A dialog "
481  "box will be shown to assist in creating the control points.</li>"
482  "<li>Right click and drag will create an elevation profile "
483  "between two previously created control points.</li></ul>"
484  "<p><strong>Note:</strong> The quality of the profiles is dependent on the registration "
485  "between the two images at each point along the profile. Registration "
486  "parameters can be changed under Options->Registration mentu of the "
487  "Elevation Calculator window. A discussion of these parameters can be found at: "
488  "<a href=\"http://isis.astrogeology.usgs.gov/documents/PatternMatch/PatternMatch.html\">"
489  "Pattern Matching</a>");
490  quickDesc->setWordWrap(true);
491  quickDesc->setOpenExternalLinks(true);
492  quickLayout->addWidget(quickDesc);
493 
494  quickTab->setWidget(quickContainer);
495 
496  // TAB 3 - Control Point Editing
497  QScrollArea *controlPointTab = new QScrollArea;
498  controlPointTab->setWidgetResizable(true);
499  controlPointTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
500  QWidget *controlPointContainer = new QWidget;
501  QVBoxLayout *controlPointLayout = new QVBoxLayout;
502  controlPointContainer->setLayout(controlPointLayout);
503 
504  QLabel *controlPointTitle = new QLabel("<h2>Control Point Editing</h2>");
505  controlPointLayout->addWidget(controlPointTitle);
506 
507  QLabel *mouseLabel = new QLabel("<p><h3>When the \"Stereo\" tool "
508  "is activated, the mouse buttons have the following function in the "
509  "cube viewports of the main qview window:</h3>");
510  mouseLabel->setWordWrap(true);
511  mouseLabel->setScaledContents(true);
512  controlPointLayout->addWidget(mouseLabel);
513 
514  QLabel *controlPointDesc = new QLabel("<ul>"
515  "<li>Left click - Edit the closest control point</li>"
516  "<li>Middle click - Delete the closest control point</li>"
517  "<li>Right click - Create new control point at cursor location</li>"
518  "<li>Left click and drag - Create an elevation profile "
519  "after you create the start and end control points. A dialog "
520  "box will be shown to assist in creating the control points.</li>"
521  "<li>Right click and drag - Create an elevation profile "
522  "between two previously created control points.</li></ul>");
523  controlPointDesc->setWordWrap(true);
524  controlPointLayout->addWidget(controlPointDesc);
525 
526  QLabel *controlPointEditing = new QLabel(
527  "<h4>Changing Measure Locations</h4>"
528  "<p>The measure location can be adjusted by:"
529  "<ul>"
530  "<li>Move the cursor location under the crosshair by clicking the left mouse "
531  "button</li>"
532  "<li>Move 1 pixel at a time by using arrow keys on the keyboard</li>"
533  "<li>Move 1 pixel at a time by using arrow buttons above the right view</li>"
534  "</ul></p>"
535  "<h4>Other Point Editor Functions</h4>"
536  "<p>Along the right border of the window:</p>"
537  "<ul>"
538  "<li><strong>Geom:</strong> Geometrically match the right view to the left"
539  "view</li>"
540  "<li><strong>Rotate:</strong> Rotate the right view using either the dial"
541  "or entering degrees </li>"
542  "<li><strong>Show control points:</strong> Draw crosshairs at all control"
543  "point locations visible within the view</li>"
544  "<li><strong>Show crosshair:</strong> Show a red crosshair across the entire"
545  "view</li>"
546  "<li><strong>Circle:</strong> Draw circle which may help center measure"
547  "on a crater</li></ul"
548  "<p>Below the left view:</p>"
549  "<ul><li><strong>Blink controls:</strong> Blink the left and right view in the"
550  "left view window using the \"Blink Start\" button (with play icon) and "
551  "\"Blink Stop\" button (with stop icon). Both arrow keys above the right view "
552  "and the keyboard arrow keys may be used to move the right view while"
553  "blinking.</li>"
554  "<li><strong>Find:</strong> Center the right view so that the same latitude "
555  "longitude is under the crosshair as the left view.</li></ul"
556  "<p>Below the right view:</p>"
557  "<ul><li><strong>Register:</strong> Sub-pixel register the the right view to"
558  "the left view.</li>"
559  "<li><strong>Save Measure:</strong> Save the control point under the"
560  "crosshairs and calculated elevation.</li></ul>");
561  controlPointEditing->setWordWrap(true);
562  controlPointLayout->addWidget(controlPointEditing);
563 
564  controlPointTab->setWidget(controlPointContainer);
565 
566 
567 
568  tabArea->addTab(overviewTab, "&Overview");
569  tabArea->addTab(quickTab, "&Quick Start");
570  tabArea->addTab(controlPointTab, "&Control Point Editing");
571 
572  QHBoxLayout *buttonsLayout = new QHBoxLayout;
573  // Flush the buttons to the right
574  buttonsLayout->addStretch();
575 
576  QPushButton *closeButton = new QPushButton("&Close");
577  closeButton->setIcon( QPixmap( toolIconDir() + "/guiStop.png" ) );
578  closeButton->setDefault(true);
579  connect( closeButton, SIGNAL( clicked() ),
580  helpDialog, SLOT( close() ) );
581  buttonsLayout->addWidget(closeButton);
582 
583  mainLayout->addLayout(buttonsLayout);
584 
585  helpDialog->show();
586 
587 
588  }
589 
590 
591 
592  void StereoTool::userBaseRadius() {
593  // TODO test validity
594  try {
595  m_baseRadius = Distance(m_radiusLineEdit->text().toDouble(),
597 
598  // If stereo Tool visible and has valid point, update elevation and
599  // save new elevation to point
600  if (m_stereoTool->isVisible() && m_editPoint != NULL) {
601  calculateElevation();
602  }
603  }
604  catch (IException &e) {
605  QString message = "Invalid base radius entered.";
606  message += e.toString();
607  m_radiusLineEdit->setText("");
608  QMessageBox::critical(m_stereoTool, "Error", message);
609  m_baseRadius = Distance(0., Distance::Meters);
610  return;
611  }
612 
613  }
614 
615 
616 
617  void StereoTool::updateRadiusLineEdit() {
618 
619 
620  if ( m_radiusBox->currentText() == "Ellipsoid Equitorial Radius" ) {
621  if ( m_targetRadius.isValid() ) {
622  m_radiusLineEdit->setText( QString::number( m_targetRadius.meters(), 'f',
623  6) );
624  m_baseRadius = m_targetRadius;
625  }
626  else {
627  m_radiusLineEdit->setText("");
628  }
629  m_radiusLineEdit->setReadOnly(true);
630  m_radiusLineEdit->setEnabled(false);
631  }
632  else if ( m_radiusBox->currentText() == "DEM Radius" ) {
633  // If cubes set, make sure they have an elevation model
634  if (m_leftCube) {
635  m_leftCube->camera()->IgnoreElevationModel(false);
636  if ( m_leftCube->camera()->target()->shape()->name() == "Ellipsoid" ) {
637  QString message = "No valid Dem on cube. Run <i>spicinit</i> using a "
638  "dem shape model. The local radius will default back to the ellipsoid.";
639  QMessageBox::warning(m_stereoTool, "Warning", message);
640  m_radiusBox->setCurrentIndex(0);
641 
642  m_radiusLineEdit->setReadOnly(true);
643  m_radiusLineEdit->setEnabled(false);
644  return;
645  }
646  }
647  m_radiusLineEdit->setText("");
648  m_radiusLineEdit->setReadOnly(true);
649  m_radiusLineEdit->setEnabled(false);
650  m_baseRadius = Distance(0., Distance::Meters);
651  }
652  else { // "Custom Radius"
653  m_radiusLineEdit->setReadOnly(false);
654  m_radiusLineEdit->setEnabled(true);
655  }
656 
657  // If stereo Tool visible and has valid point, update elevation
658  if ( m_stereoTool->isVisible() && m_editPoint != NULL ) {
659  calculateElevation();
660  }
661  }
662 
663 
664 
665  void StereoTool::setupFiles() {
666 
667  /* TODO
668  .5 Get vector of all linked viewports
669  1. If no files linked or > 2 linked, print errror & return
670  2. Check if new files
671  if yes: clear old
672  if no: return
673 
674  */
675  m_linkedViewports.clear();
676  for (int i = 0; i < (int) cubeViewportList()->size(); i++) {
677  if ( (*( cubeViewportList() ) )[i]->isLinked() )
678  m_linkedViewports.push_back( (*( cubeViewportList() ) )[i]);
679  }
680 
681  if ( m_linkedViewports.size() < 2 ) {
682  IString message = "Two cube viewports containing a stereo pair "
683  "need to be linked.";
684  throw IException(IException::User, message, _FILEINFO_);
685  }
686  if ( m_linkedViewports.size() > 2 ) {
687  IString message = "Only two cube viewports containing a stereo pair "
688  "may be linked.";
689  throw IException(IException::User, message, _FILEINFO_);
690  }
691 
692  // If linked viewports contain the same cubes, simply return,
693  // all data should be retained.
694  if ( m_linkedViewports.at(0)->cube() == m_leftCube ||
695  m_linkedViewports.at(0)->cube() == m_rightCube ) {
696  if ( m_linkedViewports.at(1)->cube() == m_leftCube ||
697  m_linkedViewports.at(1)->cube() == m_rightCube ) {
698  return;
699  }
700  }
701 
702  // Control net already exists, make sure new cubes are the same target
703  // as the current control net.
704  if (m_controlNet) {
705  if ( m_controlNet->GetTarget() !=
706  m_linkedViewports.at(0)->cube()->camera()->target()->name() ) {
707  // Allow opportunity to save current data before clearing for new
708  // target.
709  QString message = "You have changed targets. All data must be re-set";
710  message += " for new target. Would you like to save your current";
711  message += " points before resetting?";
712  int response = QMessageBox::question(m_stereoTool,
713  "Save current points", message,
714  QMessageBox::Yes | QMessageBox::No,
715  QMessageBox::Yes);
716  if (response == QMessageBox::Yes) {
718  }
719  m_stereoTool->setShown(false);
720  clearNetData();
721  m_controlNet = new ControlNet();
722  m_controlNet->SetTarget(
723  m_linkedViewports.at(0)->cube()->camera()->target()->name() );
724  m_serialNumberList = new SerialNumberList(false);
725  }
726  }
727  else {
728  m_controlNet = new ControlNet();
729  m_controlNet->SetTarget(
730  m_linkedViewports.at(0)->cube()->camera()->target()->name() );
731  m_serialNumberList = new SerialNumberList(false);
732  }
733 
734 
735  // TODO: For now simply clear & set always, but should check if cubes are
736  // not new.
737  clearFiles();
738  setFiles( m_linkedViewports.at(0)->cube(), m_linkedViewports.at(1)->cube() );
739 
740  }
741 
742 
743 
754  m_stereoTool->setShown(false);
755 
756  if (m_leftGM) {
757  delete m_leftGM;
758  m_leftGM = NULL;
759  }
760  if (m_rightGM) {
761  delete m_rightGM;
762  m_rightGM = NULL;
763  }
764 
765  }
766 
767 
768 
776  void StereoTool::setFiles(Cube *leftCube, Cube *rightCube) {
777 
778  // Save off base map cube, but add matchCube to serial number list
779  m_leftCube = leftCube;
780  m_rightCube = rightCube;
781 
782  QString leftName = FileName( m_leftCube->fileName() ).name();
783  QString rightName = FileName( m_rightCube->fileName() ).name();
784  // Update cube name labels
785  m_leftCubeLabel->setText(leftName);
786  m_rightCubeLabel->setText(rightName);
787 
788  m_leftSN = SerialNumber::Compose(*m_leftCube);
789  m_rightSN = SerialNumber::Compose(*m_rightCube);
790 
791  // TODO Do I need list?
792  if ( !m_serialNumberList->hasSerialNumber(m_leftSN) ) {
793  m_serialNumberList->add( m_leftCube->fileName() );
794  }
795  if ( !m_serialNumberList->hasSerialNumber(m_rightSN) ) {
796  m_serialNumberList->add( m_rightCube->fileName() );
797  }
798 
799  vector<Distance> targetRadius = m_controlNet->GetTargetRadii();
800  m_targetRadius = Distance(targetRadius[0]);
801  // If radius combo box set to ellipsoid, update the radius line edit
802  if ( !m_targetRadius.isValid() ) {
803  QString message = "Could not determine target radius.";
804  QMessageBox::critical(m_stereoTool,"Error",message);
805  m_baseRadius = Distance(0., Distance::Meters);
806  updateRadiusLineEdit();
807  return;
808  }
809  updateRadiusLineEdit();
810 
811  // Save off universal ground maps
812  try {
813  m_leftGM = new UniversalGroundMap(*m_leftCube);
814  }
815  catch (IException &e) {
816  QString message = "Cannot initialize universal ground map for " +
817  m_leftCube->fileName() + ".\n";
818  message += e.toString();
819  QMessageBox::critical(m_stereoTool, "Error", message);
820  return;
821  }
822  try {
823  m_rightGM = new UniversalGroundMap(*m_rightCube);
824  }
825  catch (IException &e) {
826  QString message = "Cannot initialize universal ground map for" +
827  m_rightCube->fileName() + ".\n";
828  message += e.toString();
829  QMessageBox::critical(m_stereoTool, "Error", message);
830  return;
831  }
832 
833 
834  }
835 
836 
837 
843 
844  double samp = m_editPoint->GetMeasure(Left)->GetSample();
845  double line = m_editPoint->GetMeasure(Left)->GetLine();
846  m_leftGM->SetImage(samp, line);
847  double lat = m_leftGM->UniversalLatitude();
848  double lon = m_leftGM->UniversalLongitude();
849 
850  m_rightGM->SetGround(
852  try {
853  m_editPoint->SetAprioriSurfacePoint(SurfacePoint (
855  m_targetRadius ) );
856  }
857  catch (IException &e) {
858  QString message = "Unable to set Apriori Surface Point.\n";
859  message += "Latitude = " + QString::number(lat);
860  message += " Longitude = " + QString::number(lon);
861  message += " Radius = " + QString::number(m_targetRadius.meters(), 'f',
862  6) + "\n";
863  message += e.toString();
864  QMessageBox::critical(m_stereoTool, "Error", message);
865  }
866 
867  calculateElevation();
868  emit editPointChanged();
869  }
870 
871 
872 
879  rubberBandTool()->enable(RubberBandTool::LineMode);
880  rubberBandTool()->enablePoints();
881  rubberBandTool()->enableAllClicks();
882  rubberBandTool()->setDrawActiveViewportOnly(true);
883  }
884 
885 
886 
887  void StereoTool::rubberBandComplete() {
888 
889 // clearProfile();
890 
891  try {
892  setupFiles();
893  }
894  catch (IException &e) {
895  QString message = e.toString();
896  QMessageBox::critical(m_stereoTool, "Error setting stereo pair", message);
897  rubberBandTool()->clear();
898  return;
899  }
900 
901  MdiCubeViewport *cvp = cubeViewport();
902  if (cvp == NULL)
903  return;
904 
905  QString file = cvp->cube()->fileName();
906  QString sn;
907  try {
908  sn = m_serialNumberList->serialNumber(file);
909  }
910  catch (IException &e) {
911  QString message = "This cube is not linked as a stereo pair. Make ";
912  message += "sure you have two stereo pair cube viewports linked.";
913  QMessageBox::critical(m_stereoTool,"Viewport not linked", message);
914  return;
915  }
916 
917  if ( rubberBandTool()->figureIsPoint() ) {
918  double samp, line;
919  cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
920  rubberBandTool()->vertices()[0].ry(),
921  samp, line );
922  if ( rubberBandTool()->mouseButton() & Qt::LeftButton ) {
923  if ( !m_controlNet || m_controlNet->GetNumMeasures() == 0 ) {
924  QString message = "No points exist for editing. Create points ";
925  message += "using the right mouse button.";
926  QMessageBox::information(m_stereoTool, "Warning", message);
927  return;
928  }
929  // Find closest control point in network
930  ControlPoint *point;
931  try {
932  point = m_controlNet->FindClosest(sn, samp, line);
933  }
934  catch (IException &e) {
935  QString message = "No points found for editing. Create points ";
936  message += "using the right mouse button.";
937  message += e.toString();
938  QMessageBox::critical(m_stereoTool, "Error", message);
939  return;
940  }
941  modifyPoint(point);
942  }
943  else if ( rubberBandTool()->mouseButton() & Qt::MidButton ) {
944  if ( !m_controlNet || m_controlNet->GetNumPoints() == 0 ) {
945  QString message = "No points exist for deleting. Create points ";
946  message += "using the right mouse button.";
947  QMessageBox::warning(m_stereoTool, "Warning", message);
948  return;
949  }
950 
951  // Find closest control point in network
952  ControlPoint *point =
953  m_controlNet->FindClosest(sn, samp, line);
954  // TODO: test for errors and reality
955  if (point == NULL) {
956  QString message = "No points exist for deleting. Create points ";
957  message += "using the right mouse button.";
958  QMessageBox::information(m_stereoTool, "Warning", message);
959  return;
960  }
961  deletePoint(point);
962  }
963  else if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
964  double lat, lon;
965  if (cvp->cube() == m_leftCube) {
966  m_leftGM->SetImage(samp, line);
967  lat = m_leftGM->UniversalLatitude();
968  lon = m_leftGM->UniversalLongitude();
969  }
970  else {
971  m_rightGM->SetImage(samp, line);
972  lat = m_rightGM->UniversalLatitude();
973  lon = m_rightGM->UniversalLongitude();
974  }
975  try {
976  createPoint(lat, lon);
977  }
978  catch (IException &e) {
979  QString message = "Cannot create control point.\n\n";
980  message += e.toString();
981  QMessageBox::critical(m_stereoTool, "Error", message);
982  m_startPoint = NULL;
983  rubberBandTool()->clear();
984  return;
985  }
986  }
987  }
988  // RubberBand line drawn:
989  else {
990  m_startPoint = NULL;
991  m_endPoint = NULL;
992  // Right click/drag: Find closest end points
993  if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
994  double samp, line;
995  cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
996  rubberBandTool()->vertices()[0].ry(),
997  samp, line );
998  try {
999  m_startPoint = m_controlNet->FindClosest(sn, samp, line);
1000  }
1001  catch (IException &e) {
1002  QString message = "Cannot find start point for profile. Either ";
1003  message += "create end points individually using the right mouse ";
1004  message += "button. Or, create profile end points by clicking and ";
1005  message += "dragging with the right mouse button.\n\n";
1006  message += e.toString();
1007  QMessageBox::critical(m_stereoTool, "Error", message);
1008  m_startPoint = NULL;
1009  rubberBandTool()->clear();
1010  return;
1011  }
1012  cvp->viewportToCube( rubberBandTool()->vertices()[1].rx(),
1013  rubberBandTool()->vertices()[1].ry(),
1014  samp, line );
1015  try {
1016  m_endPoint = m_controlNet->FindClosest(sn, samp, line);
1017  if ( m_startPoint->GetId() == m_endPoint->GetId() ) {
1018  throw IException(IException::User, "No End Point",
1019  _FILEINFO_);
1020  }
1021  }
1022  catch (IException &e) {
1023  QString message = "Cannot find end point for profile. Either ";
1024  message += "create end points individually using the right mouse ";
1025  message += "button. Or, create profile end points by clicking and ";
1026  message += "dragging with the right mouse button.\n\n";
1027  message += e.toString();
1028  QMessageBox::critical(m_stereoTool, "Error", message);
1029  m_startPoint = NULL;
1030  m_endPoint = NULL;
1031  rubberBandTool()->clear();
1032  return;
1033  }
1034  profile();
1035  }
1036  else {
1037  // Left click/drag: Create control points at the line endpoints.
1038  m_profileDialog = new ProfileDialog();
1039  connect( m_profileDialog, SIGNAL( createStart() ),
1040  this, SLOT( createStartPoint() ) );
1041  connect( m_profileDialog, SIGNAL( createEnd() ),
1042  this, SLOT( createEndPoint() ) );
1043  connect( m_profileDialog, SIGNAL( accepted() ),
1044  this, SLOT( profile() ) );
1045  connect( m_profileDialog, SIGNAL( accepted() ),
1046  this, SLOT( profile() ) );
1047  connect( m_profileDialog, SIGNAL( rejected() ),
1048  this, SLOT( clearProfile() ) );
1049  m_profileDialog->show();
1050  m_profileDialog->activateWindow();
1051  }
1052  }
1053  }
1054 
1055 
1056 
1057  void StereoTool::clearProfile() {
1058  m_startPoint = NULL;
1059  m_endPoint = NULL;
1060  rubberBandTool()->clear();
1061  delete m_profileDialog;
1062  m_profileDialog = NULL;
1063  }
1064 
1065 
1066 
1067  void StereoTool::createStartPoint() {
1068  MdiCubeViewport *cvp = cubeViewport();
1069  if (cvp == NULL)
1070  return;
1071 
1072  double samp, line;
1073  double lat, lon;
1074  cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
1075  rubberBandTool()->vertices()[0].ry(),
1076  samp, line );
1077  if ( cvp->cube() == m_leftCube ) {
1078  m_leftGM->SetImage(samp, line);
1079  lat = m_leftGM->UniversalLatitude();
1080  lon = m_leftGM->UniversalLongitude();
1081  }
1082  else {
1083  m_rightGM->SetImage(samp, line);
1084  lat = m_rightGM->UniversalLatitude();
1085  lon = m_rightGM->UniversalLongitude();
1086  }
1087  try {
1088  createPoint(lat, lon);
1089  }
1090  catch (IException &e) {
1091  QString message = "Cannot create control point.\n\n";
1092  message += e.toString();
1093  QMessageBox::critical(m_stereoTool, "Error", message);
1094  delete m_profileDialog;
1095  m_profileDialog = NULL;
1096  rubberBandTool()->clear();
1097  return;
1098  }
1099  m_startPoint = m_editPoint;
1100  }
1101 
1102 
1103 
1104  void StereoTool::createEndPoint() {
1105  MdiCubeViewport *cvp = cubeViewport();
1106  if (cvp == NULL)
1107  return;
1108 
1109  double samp, line;
1110  double lat, lon;
1111  cvp->viewportToCube( rubberBandTool()->vertices()[1].rx(),
1112  rubberBandTool()->vertices()[1].ry(),
1113  samp, line );
1114  if ( cvp->cube() == m_leftCube ) {
1115  m_leftGM->SetImage(samp, line);
1116  lat = m_leftGM->UniversalLatitude();
1117  lon = m_leftGM->UniversalLongitude();
1118  }
1119  else {
1120  m_rightGM->SetImage(samp, line);
1121  lat = m_rightGM->UniversalLatitude();
1122  lon = m_rightGM->UniversalLongitude();
1123  }
1124  try {
1125  createPoint(lat, lon);
1126  }
1127  catch (IException &e) {
1128  QString message = "Cannot create control point.\n\n";
1129  message += e.toString();
1130  QMessageBox::critical(m_stereoTool, "Error", message);
1131  m_startPoint = NULL;
1132  delete m_profileDialog;
1133  m_profileDialog = NULL;
1134  rubberBandTool()->clear();
1135  return;
1136  }
1137  m_endPoint = m_editPoint;
1138 
1139  }
1140 
1141 
1142 
1155  void StereoTool::createPoint(double lat, double lon) {
1156 
1157  // TODO: ADD AUTOSEED OPTION (CHECKBOX?)
1158 
1159  double leftSamp = 0, leftLine = 0;
1160  double rightSamp = 0, rightLine = 0;
1161 
1162  // Make sure point exists on both linked cubes
1163  if ( m_leftGM->SetUniversalGround(lat, lon) ) {
1164  leftSamp = m_leftGM->Sample();
1165  leftLine = m_leftGM->Line();
1166 
1167  // Make sure point is on Right cube
1168  if ( m_rightGM->SetUniversalGround(lat, lon) ) {
1169  // Make sure point on Right cube
1170  rightSamp = m_rightGM->Sample();
1171  rightLine = m_rightGM->Line();
1172  if ( rightSamp < 1 || rightSamp > m_rightCube->sampleCount() ||
1173  rightLine < 1 || rightLine > m_rightCube->lineCount() ) {
1174  IString message = "Point does not exist on cube, " +
1175  m_rightCube->fileName() + ".";
1176  throw IException(IException::User, message, _FILEINFO_);
1177 // QString message = "Point does not exist on cube, " +
1178 // QString(m_rightCube->fileName().c_str() ) + ".";
1179 // QMessageBox::critical(m_stereoTool, "Error", message);
1180 // return;
1181  }
1182  }
1183  else {
1184  IString message = "Point does not exist on cube, " +
1185  m_rightCube->fileName() + ".";
1186  throw IException(IException::User, message, _FILEINFO_);
1187 // QString message = "Point does not exist on cube, " +
1188 // QString(m_rightCube->fileName().c_str() ) + ".";
1189 // QMessageBox::critical(m_stereoTool, "Error", message);
1190 // return;
1191  }
1192  }
1193  else {
1194  IString message = "Point does not exist on cube, " +
1195  m_leftCube->fileName() + ".";
1196  throw IException(IException::User, message, _FILEINFO_);
1197 // QString message = "Point does not exist on cube, " +
1198 // QString(m_leftCube->fileName().c_str() ) + ".";
1199 // QMessageBox::critical(m_stereoTool, "Error", message);
1200 // return;
1201  }
1202 
1203  // Point is on both Left and Right cubes, create new control point
1204  ControlPoint *newPoint = NULL;
1205  // Prompt for point Id
1206  bool goodId = false;
1207  while (!goodId) {
1208  bool ok = false;
1209  QString id = QInputDialog::getText(m_stereoTool,
1210  "Point ID", "Enter Point ID:",
1211  QLineEdit::Normal, lastPtIdValue,
1212  &ok);
1213  if (!ok)
1214  // user clicked "Cancel"
1215  {
1216  return;
1217  }
1218  if ( ok && id.isEmpty() ) {
1219  // user clicked "Ok" but did not enter a point ID
1220  QString message = "You must enter a point Id.";
1221  QMessageBox::warning(m_stereoTool, "Warning", message);
1222  }
1223  else {
1224  // Make sure Id doesn't already exist
1225  newPoint = new ControlPoint(id);
1226  if ( m_controlNet->GetNumPoints() > 0 &&
1227  m_controlNet->ContainsPoint(newPoint->GetId() ) ) {
1228  QString message = "A ControlPoint with Point Id = [" +
1229  newPoint->GetId() +
1230  "] already exists. Re-enter unique Point Id.";
1231  QMessageBox::warning(m_stereoTool, "Unique Point Id", message);
1232  }
1233  else {
1234  goodId = true;
1235  lastPtIdValue = id;
1236  }
1237  }
1238  }
1239 
1240  newPoint->SetType(ControlPoint::Free);
1243  m_targetRadius) );
1244 
1245  // Set first measure to Left
1246  ControlMeasure *mLeft = new ControlMeasure;
1247  mLeft->SetCubeSerialNumber(m_leftSN);
1248  mLeft->SetCoordinate(leftSamp, leftLine);
1250  mLeft->SetDateTime();
1252  newPoint->Add(mLeft);
1253  // Second measure is Right measure
1254  ControlMeasure *mRight = new ControlMeasure;
1255  mRight->SetCubeSerialNumber(m_rightSN);
1256  mRight->SetCoordinate(rightSamp, rightLine);
1258  mRight->SetDateTime();
1260  newPoint->Add(mRight);
1261 
1262  // Add new control point to control network
1263  m_controlNet->AddPoint(newPoint);
1264  // Read newly added point
1265  m_editPoint = m_controlNet->GetPoint( (QString) newPoint->GetId() );
1266  // Load new point in StereoTool
1267  loadPoint();
1268  m_stereoTool->setShown(true);
1269  m_stereoTool->raise();
1270 
1271  emit editPointChanged();
1272  }
1273 
1274 
1287 
1288  m_editPoint = point;
1289  // Change point in viewport to red so user can see what point they are
1290  // about to delete.
1291  emit editPointChanged();
1292 
1293  //loadPoint();
1294 
1295  m_controlNet->DeletePoint( m_editPoint->GetId() );
1296  m_stereoTool->setShown(false);
1297  m_editPoint = NULL;
1298 
1299  emit editPointChanged();
1300  }
1301 
1302 
1310 
1311  m_editPoint = point;
1312  loadPoint();
1313  m_stereoTool->setShown(true);
1314  m_stereoTool->raise();
1315  emit editPointChanged();
1316  }
1317 
1318 
1325 
1326  // Initialize pointEditor with measures
1327  m_pointEditor->setLeftMeasure( m_editPoint->GetMeasure(Left), m_leftCube,
1328  m_editPoint->GetId() );
1329  m_pointEditor->setRightMeasure( m_editPoint->GetMeasure(Right),
1330  m_rightCube, m_editPoint->GetId() );
1331 
1332  // Write pointId
1333  QString ptId = "Point ID: " + m_editPoint->GetId();
1334  m_ptIdValue->setText(ptId);
1335 
1336  updateLabels();
1337  }
1338 
1339 
1340 
1341  void StereoTool::paintProfile(MdiCubeViewport *vp, QPainter *painter,
1342  QString serialNumber) {
1343 
1344  // Draw profile
1345  int x1, y1, x2, y2;
1346  //MdiCubeViewport *cvp = cubeViewport();
1347  vp->cubeToViewport( m_startPoint->GetMeasure(serialNumber)->GetSample(),
1348  m_startPoint->GetMeasure(serialNumber)->GetLine(),
1349  x1, y1 );
1350  vp->cubeToViewport( m_endPoint->GetMeasure(serialNumber)->GetSample(),
1351  m_endPoint->GetMeasure(serialNumber)->GetLine(),
1352  x2, y2 );
1353  painter->setPen(Qt::green); // set all other point markers green
1354  painter->drawLine(x1, y1, x2, y2);
1355 
1356  }
1357 
1358 
1359 
1367  void StereoTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) {
1368 
1369  AbstractPlotTool::paintViewport(vp, painter);
1370 
1371  // Make sure we have points to draw
1372  if ( m_controlNet == NULL || m_controlNet->GetNumPoints() == 0 )
1373  return;
1374 
1375  QString serialNumber = SerialNumber::Compose(*vp->cube(), true);
1376 
1377  // If viewport serial number not found in control net, return
1378  if ( !m_controlNet->GetCubeSerials().contains(
1379  serialNumber) ) return;
1380 
1381  // Draw profile if it exists
1382 // if (m_startPoint != NULL && m_endPoint != NULL) {
1383 // paintProfile(vp, painter, serialNumber);
1384 // }
1385 
1386  // Get all measures for this viewport
1387  QList<ControlMeasure *> measures =
1388  m_controlNet->GetMeasuresInCube(serialNumber);
1389  // loop through all measures contained in this cube
1390  for (int i = 0; i < measures.count(); i++) {
1391  ControlMeasure *m = measures[i];
1392  // Find the measurments on the viewport
1393  double samp = m->GetSample();
1394  double line = m->GetLine();
1395  int x, y;
1396  vp->cubeToViewport(samp, line, x, y);
1397  // if the point is ignored,
1398  if ( m->Parent()->IsIgnored() ) {
1399  painter->setPen( QColor(255, 255, 0) ); // set point marker yellow
1400  }
1401  // point is not ignored, but measure matching this image is ignored,
1402  else if ( m->IsIgnored() ) {
1403  painter->setPen( QColor(255, 255, 0) ); // set point marker yellow
1404  }
1405  // Neither point nor measure is not ignored and the measure is fixed,
1406  else if ( m->Parent()->GetType() != ControlPoint::Free) {
1407  painter->setPen(Qt::magenta);// set point marker magenta
1408  }
1409  else {
1410  painter->setPen(Qt::green); // set all other point markers green
1411  }
1412  // draw points
1413  painter->drawLine(x - 5, y, x + 5, y);
1414  painter->drawLine(x, y - 5, x, y + 5);
1415  }
1416 
1417  // if StereoTool is open,
1418  if ( m_editPoint != NULL ) {
1419  // and the selected point is in the image,
1420  if ( m_editPoint->HasSerialNumber(serialNumber) ) {
1421  // find the measurement
1422  double samp = (*m_editPoint)[serialNumber]->GetSample();
1423  double line = (*m_editPoint)[serialNumber]->GetLine();
1424  int x, y;
1425  vp->cubeToViewport(samp, line, x, y);
1426  // set point marker red
1427  QBrush brush(Qt::red);
1428  // set point marker bold - line width 2
1429  QPen pen(brush, 2);
1430  // draw the selected point in each image last so it's on top of the rest of the points
1431  painter->setPen(pen);
1432  painter->drawLine(x - 5, y, x + 5, y);
1433  painter->drawLine(x, y - 5, x, y + 5);
1434  }
1435  }
1436 
1437  }
1438 
1439 
1440 
1446 
1447  // Take care of drawing things on all viewPorts.
1448  // Calling update will cause the Tool class to call all registered tools
1449  // if point has been deleted, this will remove it from the main window
1450  MdiCubeViewport *vp;
1451  for (int i = 0; i < (int) cubeViewportList()->size(); i++) {
1452  vp = (*( cubeViewportList() ) )[i];
1453  vp->viewport()->update();
1454  }
1455  }
1456 
1457 
1458 
1459  void StereoTool::calculateElevation() {
1460  calculateElevation(m_editPoint);
1461  }
1462 
1463 
1464 
1469  void StereoTool::calculateElevation(ControlPoint *point) {
1470 
1471  double elevation=0., elevationError=0.;
1472  Camera *leftCamera = m_leftCube->camera();
1473 
1474  // If the local radius combo box is set to DEM, get the dem radius
1475  // First, SetImage using the Elevation model, before turning off
1476  // to get camera angles.
1477  if ( m_radiusBox->currentText() == "DEM Radius" ) {
1478  leftCamera->IgnoreElevationModel(false);
1479  leftCamera->SetImage( (*point)[Left]->GetSample(),
1480  (*point)[Left]->GetLine() );
1481  m_baseRadius = leftCamera->LocalRadius( leftCamera->GetLatitude(),
1482  leftCamera->GetLongitude() );
1483  if ( !m_baseRadius.isValid() ) {
1484  QString message = "Invalid Dem radius, defaulting to ellipsoidal.";
1485  QMessageBox::warning(m_stereoTool, "Invalid Dem radius", message);
1486  m_baseRadius = m_targetRadius;
1487  }
1488  }
1489 
1490  leftCamera->IgnoreElevationModel(true);
1491  leftCamera->SetImage( (*point)[Left]->GetSample(),
1492  (*point)[Left]->GetLine() );
1493  Camera *rightCamera = m_rightCube->camera();
1494  rightCamera->IgnoreElevationModel(true);
1495  rightCamera->SetImage( (*point)[Right]->GetSample(),
1496  (*point)[Right]->GetLine() );
1497 
1498  double radius, lat, lon, sepang;
1499  if ( Stereo::elevation( *leftCamera, *rightCamera, radius, lat, lon, sepang,
1500  elevationError ) ) {
1501  elevation = radius - m_baseRadius.meters();
1502 // cout<<setprecision(15)<<"radius = "<<radius<<" baseRadius = "<<m_baseRadius.meters()<<" elevation = "<<elevation<<endl;
1503  }
1504  leftCamera->IgnoreElevationModel(false);
1505  rightCamera->IgnoreElevationModel(false);
1506 
1507  // Save elevation and error info to the left ControlMeasure FocalPlaneComputeX/Y.
1508  // TODO: Find better way - This is not a good way to do this, using
1509  // ControlMeasure to save other values. Save The baseRadius in Diameter
1510  point->GetMeasure(Left)->SetFocalPlaneMeasured(elevation, elevationError);
1511  point->GetMeasure(Left)->SetDiameter(m_baseRadius.meters() );
1512  updateLabels();
1513 
1514  return;
1515  }
1516 
1517 
1518 
1527  QString filename = QFileDialog::getOpenFileName( m_stereoTool,
1528  "Select a registration template", ".",
1529  "Registration template files (*.def *.pvl);;All files (*)" );
1530 
1531  if ( filename.isEmpty() )
1532  return;
1533 
1534  m_pointEditor->setTemplateFile(filename);
1535  }
1536 
1537 
1551  try {
1552  // Get the template file from the ControlPointEditor object
1553  Pvl templatePvl( m_pointEditor->templateFileName() );
1554  // Create registration dialog window using PvlEditDialog class
1555  // to view and/or edit the template
1556  PvlEditDialog registrationDialog(templatePvl);
1557  registrationDialog.setWindowTitle( "View or Edit Template File: "
1558  + templatePvl.fileName() );
1559  registrationDialog.resize(550, 360);
1560  registrationDialog.exec();
1561  }
1562  catch (IException &e) {
1563  QString message = e.toString();
1564  QMessageBox::warning(m_stereoTool, "Error", message);
1565  }
1566  }
1567 
1568 
1575 
1576  QString fn = QFileDialog::getSaveFileName( m_stereoTool,
1577  "Choose filename to save under",
1578  ".",
1579  "CSV Files (*.csv)" );
1580  QString filename;
1581 
1582  //Make sure the filename is valid
1583  if( !fn.isEmpty() ) {
1584  if( !fn.endsWith(".csv") ) {
1585  filename = fn + ".csv";
1586  }
1587  else {
1588  filename = fn;
1589  }
1590  }
1591  //The user cancelled, or the filename is empty
1592  else {
1593  return;
1594  }
1595 
1596  m_currentFile.setFileName(filename);
1597 
1598  m_save->setEnabled(true);
1599  saveElevations();
1600  }
1601 
1602 
1603 
1604  void StereoTool::saveElevations() {
1605 
1606  if ( m_currentFile.fileName().isEmpty() ) return;
1607 
1608  bool success = m_currentFile.open(QIODevice::WriteOnly);
1609  if(!success) {
1610  QMessageBox::critical(m_stereoTool, "Error",
1611  "Cannot open file, please check permissions");
1612  m_currentFile.setFileName("");
1613  m_save->setDisabled(true);
1614  return;
1615  }
1616 
1617  QTextStream text(&m_currentFile);
1618  QString header = "Point ID, Latitude, Longitude, Radius, ";
1619  header += "Elevation, Elevation Error, ";
1620  header += "Image 1, Sample, Line, Image 2, Sample, Line";
1621  text << header << endl;
1622 
1623  QString leftFile = FileName( m_leftCube->fileName() ).name();
1624  QString rightFile = FileName( m_rightCube->fileName() ).name();
1625  QString data;
1626  for (int i = 0; i < m_controlNet->GetNumPoints(); i++) {
1627  ControlPoint &p = *( (*m_controlNet)[i] );
1628  SurfacePoint apriori = p.GetAprioriSurfacePoint();
1629  data = p.GetId() + "," +
1630  QString::number( apriori.GetLatitude().degrees() ) + "," +
1631  QString::number( apriori.GetLongitude().degrees() ) + "," +
1632  QString::number( p.GetMeasure(Left)->GetDiameter(), 'f', 6 ) +
1633  "," +
1634  QString::number( p.GetMeasure(Left)->GetFocalPlaneMeasuredX(), 'f',
1635  6 ) + "," +
1636  QString::number( p.GetMeasure(Left)->GetFocalPlaneMeasuredY(), 'f',
1637  6 ) + "," + leftFile + "," +
1638  QString::number( p.GetMeasure(Left)->GetSample() ) + "," +
1639  QString::number( p.GetMeasure(Left)->GetLine() ) + "," +
1640  rightFile + "," +
1641  QString::number( p.GetMeasure(Right)->GetSample() ) + "," +
1642  QString::number( p.GetMeasure(Right)->GetLine() );
1643  text << data << endl;
1644  }
1645  m_currentFile.close();
1646 
1647  }
1648 
1649 
1650 
1651  void StereoTool::clearNetData() {
1652 
1653  delete m_controlNet;
1654  m_controlNet = NULL;
1655  delete m_serialNumberList;
1656  m_serialNumberList = NULL;
1657 
1658  }
1659 
1660 
1661 
1662  void StereoTool::profile() {
1663 
1664 // (*m_startPoint)[Left]->SetCoordinate(1361.92,1317.9433);
1665 // (*m_endPoint)[Left]->SetCoordinate(1188.43,2763.23);
1666 // (*m_startPoint)[Right]->SetCoordinate(867.04,2141.16);
1667 // (*m_endPoint)[Right]->SetCoordinate(731.82,2666.75);
1668 
1669  // Delete the profile dialog
1670  if (m_profileDialog) {
1671  delete m_profileDialog;
1672  m_profileDialog = NULL;
1673  }
1674 
1675 // calculateElevation(m_startPoint);
1676 // calculateElevation(m_endPoint);
1677 
1678  QPointF leftStart( (*m_startPoint)[Left]->GetSample(),
1679  (*m_startPoint)[Left]->GetLine() );
1680  QPointF leftEnd( (*m_endPoint)[Left]->GetSample(),
1681  (*m_endPoint)[Left]->GetLine() );
1682 
1683  QPointF rightStart( (*m_startPoint)[Right]->GetSample(),
1684  (*m_startPoint)[Right]->GetLine() );
1685  QPointF rightEnd( (*m_endPoint)[Right]->GetSample(),
1686  (*m_endPoint)[Right]->GetLine() );
1687 
1688  // Convert these to screen coordinates for updating the rubberband
1689  QList< QList<QPoint> > rubberBandVertices;
1690  QList<QPoint> rubberBand1;
1691  int sx, sy, ex, ey;
1692  m_linkedViewports.at(0)->cubeToViewport( (*m_startPoint)[Left]->GetSample(),
1693  (*m_startPoint)[Left]->GetLine(), sx, sy);
1694  m_linkedViewports.at(0)->cubeToViewport( (*m_endPoint)[Left]->GetSample(),
1695  (*m_endPoint)[Left]->GetLine(), ex, ey);
1696  rubberBand1.push_back( QPoint(sx, sy) );
1697  rubberBand1.push_back( QPoint(ex, ey) );
1698 
1699  rubberBandVertices.push_back(rubberBand1);
1700 
1701  QList<QPoint> rubberBand2;
1702  m_linkedViewports.at(1)->cubeToViewport( (*m_startPoint)[Right]->GetSample(),
1703  (*m_startPoint)[Right]->GetLine(), sx, sy);
1704  m_linkedViewports.at(1)->cubeToViewport( (*m_endPoint)[Right]->GetSample(),
1705  (*m_endPoint)[Right]->GetLine(), ex, ey);
1706  rubberBand2.push_back( QPoint(sx, sy) );
1707  rubberBand2.push_back( QPoint(ex, ey) );
1708 
1709  rubberBandVertices.push_back(rubberBand2);
1710 
1711  // Create line for left image
1712  QLineF leftProfile(leftStart,leftEnd);
1713  QLineF rightProfile(rightStart,rightEnd);
1714 
1715  // Determine shortest line, we will step through shortest line,
1716  // finding the matching position on the longer line.
1717  QLineF longProfile, shortProfile;
1718  Cube *longCube, *shortCube;
1719  if ( leftProfile.length() > rightProfile.length() ) {
1720  longProfile = leftProfile;
1721  longCube = m_leftCube;
1722  shortProfile = rightProfile;
1723  shortCube = m_rightCube;
1724  }
1725  else {
1726  longProfile = rightProfile;
1727  longCube = m_rightCube;
1728  shortProfile = leftProfile;
1729  shortCube = m_leftCube;
1730  }
1731 
1732  QVector<QPointF> profileData;
1733  double elevation = 0.;
1734  double elevationError = 0.;
1735 
1736  Pvl regDef = m_pointEditor->templateFileName();
1737  AutoReg *ar = AutoRegFactory::Create(regDef);
1738 
1739  int failureCount = 0;
1740  QApplication::setOverrideCursor(Qt::WaitCursor);
1741 
1742  for (int i = 0; i <= (int) shortProfile.length(); i++) {
1743  double shortSamp=0, shortLine=0, longSamp=0, longLine=0;
1744  try {
1745  shortSamp = shortProfile.pointAt( 1/shortProfile.length() * i ).x();
1746  shortLine = shortProfile.pointAt( 1/shortProfile.length() * i ).y();
1747 
1748  longSamp = longProfile.pointAt( 1/shortProfile.length() * i ).x();
1749  longLine = longProfile.pointAt( 1/shortProfile.length() * i ).y();
1750 
1751  // Coreg
1752  ar->PatternChip()->TackCube(shortSamp, shortLine);
1753  ar->PatternChip()->Load(*shortCube);
1754  ar->SearchChip()->TackCube(longSamp, longLine);
1755  ar->SearchChip()->Load( *longCube, *( ar->PatternChip() ), *shortCube );
1756  ar->Register();
1757 // AutoReg::RegisterStatus status = ar->Register();
1758  if ( ar->Success() ) {
1759  longSamp = ar->CubeSample();
1760  longLine = ar->CubeLine();
1761 
1762  // If the local radius combo box is set to DEM, get the dem radius
1763  // First, SetImage using the Elevation model, before turning off
1764  // to get camera angles.
1765  if ( m_radiusBox->currentText() == "DEM Radius" ) {
1766  shortCube->camera()->IgnoreElevationModel(false);
1767  shortCube->camera()->SetImage(shortSamp, shortLine);
1768  m_baseRadius = shortCube->camera()->LocalRadius(
1769  shortCube->camera()->GetLatitude(),
1770  shortCube->camera()->GetLongitude() );
1771  if ( !m_baseRadius.isValid() ) {
1772  QString message = "Invalid Dem radius, defaulting to ellipsoidal.";
1773  QMessageBox::warning(m_stereoTool, "Invalid Dem radius", message);
1774  m_baseRadius = m_targetRadius;
1775  }
1776  }
1777 
1778  shortCube->camera()->IgnoreElevationModel(true);
1779  longCube->camera()->IgnoreElevationModel(true);
1780 
1781  shortCube->camera()->SetImage(shortSamp, shortLine);
1782  longCube->camera()->SetImage(longSamp,longLine);
1783  double radius, lat, lon, sepang;
1784  if (Stereo::elevation( *shortCube->camera(), *longCube->camera(),
1785  radius, lat, lon, sepang, elevationError) )
1786  elevation = radius - m_baseRadius.meters();
1787  profileData.append( QPointF(i, elevation) );
1788 // elevations.push_back(elevation);
1789 // pixels.push_back(i);
1790  }
1791  else {
1792  failureCount++;
1793  }
1794  }
1795  catch (IException &e) {
1796  QString message = "Error registering cubes along profile line.\n";
1797  message += "Image 1 Sample = " + QString::number(shortSamp);
1798  message += " Line = " + QString::number(shortLine);
1799  message += "\nImage 2 Sample = " + QString::number(longSamp);
1800  message += " Line = " + QString::number(longLine) + "\n\n";
1801  message += e.toString();
1802  QMessageBox::critical(m_stereoTool, "Error", message);
1803  rubberBandTool()->clear();
1804  }
1805 
1806  }
1807  QApplication::restoreOverrideCursor();
1808 
1809 // cout<<"Registration attempts = "<<(int)shortLength<<" failures = "<<failureCount<<endl;
1810  QString message = "Registration attempts (pixels on line) = " +
1811  QString::number( (int)shortProfile.length() ) +
1812  "\n\nRegistration failures = " +
1813  QString::number(failureCount) +
1814  "\n\nYou can adjust registration parameters in the "
1815  "\"Options\" menu in the Elevation Calculator window. "
1816  "Select \"Options\", then \"Registration\", then either "
1817  "\"Select registration template\" or "
1818  "\"View/edit registration template\".";
1819  QMessageBox::information(m_stereoTool, "Registration Report", message);
1820 
1821  if ( ( (int)shortProfile.length() + 1 - failureCount ) < 2 ) {
1822  QString message = "Cannot create profile, all auto-registration between ";
1823  message += "the left and right cubes along the profile failed. Try ";
1824  message += "adjusting the registration parameters.";
1825  QMessageBox::critical(m_stereoTool, "Error", message);
1826  return;
1827  }
1828  PlotWindow *plotWindow = selectedWindow(true);
1829  plotWindow->setAxisLabel(0,"Elevation (meters)");
1830  CubePlotCurve *plotCurve = new CubePlotCurve(PlotCurve::PixelNumber,
1832 // plotCurve->setData(&pixels[0], &elevations[0], pixels.size() );
1833  plotCurve->setData( new QwtPointSeriesData(profileData) );
1834  plotCurve->setTitle("Elevations (Meters)");
1835  plotCurve->setPen( QPen(Qt::white) );
1836  plotCurve->setColor(Qt::white);
1837  // Create vertices for rubberband based on refined profile end points
1838 
1839  // TODO: This needs to be changed to band displayed???
1840  QList<int> bands;
1841  bands.push_back(1);
1842  bands.push_back(1);
1843  plotCurve->setSource(m_linkedViewports, rubberBandVertices, bands);
1844  plotWindow->add(plotCurve);
1845 
1846  delete m_profileDialog;
1847  m_profileDialog = NULL;
1848 // m_startPoint = NULL;
1849 // m_endPoint = NULL;
1850 // rubberBandTool()->clear();
1851 
1852  }
1853 
1854 
1855 
1856  void StereoTool::updateLabels() {
1857  // Empty elevation info if nothing there
1858  QString elevationLabel, elevationErrorLabel;
1859  QString baseRadiiLabel, leftDemRadiiLabel, rightDemRadiiLabel;
1860  if ( m_editPoint->GetMeasure(Left)->GetFocalPlaneMeasuredX() != Isis::Null ) {
1861  elevationLabel = "Elevation: " +
1862  QString::number( m_editPoint->GetMeasure(Left)->
1863  GetFocalPlaneMeasuredX(), 'f', 6 );
1864  elevationErrorLabel = "Elevation Error: " +
1865  QString::number( m_editPoint->GetMeasure(Left)->
1866  GetFocalPlaneMeasuredY(), 'f', 6 );
1867  baseRadiiLabel = "Local Radii: " + QString::number(
1868  m_baseRadius.meters(), 'f', 6 );
1869 
1870  Camera *leftCamera = m_leftCube->camera();
1871  leftCamera->SetImage( (*m_editPoint)[Left]->GetSample(),
1872  (*m_editPoint)[Left]->GetLine() );
1873  double leftDemRadii =
1874  leftCamera->GetSurfacePoint().GetLocalRadius().meters();
1875  leftDemRadiiLabel = "Left DEM Radii: " +
1876  QString::number(leftDemRadii, 'f', 6);
1877 
1878  Camera *rightCamera = m_rightCube->camera();
1879  rightCamera->SetImage( (*m_editPoint)[Right]->GetSample(),
1880  (*m_editPoint)[Right]->GetLine() );
1881  double rightDemRadii =
1882  rightCamera->GetSurfacePoint().GetLocalRadius().meters();
1883  rightDemRadiiLabel = "Right DEM Radii: " +
1884  QString::number(rightDemRadii, 'f', 6);
1885  }
1886  else {
1887  elevationLabel = "Elevation: ";
1888  elevationErrorLabel = "Elevation Error: ";
1889  baseRadiiLabel = "Local Radii: ";
1890  leftDemRadiiLabel = "Left DEM Radii: ";
1891  rightDemRadiiLabel = "Right DEM Radii: ";
1892  }
1893  m_elevationLabel->setText(elevationLabel);
1894  m_elevationErrorLabel->setText(elevationErrorLabel);
1895  m_baseRadiiLabel->setText(baseRadiiLabel);
1896  m_leftDemRadiiLabel->setText(leftDemRadiiLabel);
1897  m_rightDemRadiiLabel->setText(rightDemRadiiLabel);
1898  }
1899 
1900 
1901 
1902  void StereoTool::readSettings() {
1903  FileName config("$HOME/.Isis/qview/Stereo Tool.config");
1904  QSettings settings(config.expanded(),
1905  QSettings::NativeFormat);
1906  m_showWarning = settings.value("showWarning", true).toBool();
1907 
1908  }
1909 
1910 
1911 
1912  void StereoTool::writeSettings() {
1913  FileName config("$HOME/.Isis/qview/Stereo Tool.config");
1914  QSettings settings(config.expanded(),
1915  QSettings::NativeFormat);
1916  settings.setValue("showWarning", m_showWarning);
1917 
1918  }
1919 }
1920