1 #include "StereoTool.h"
10 #include <QFileDialog>
11 #include <QInputDialog>
13 #include <QMessageBox>
14 #include <QStackedWidget>
16 #include "AbstractPlotTool.h"
17 #include "Application.h"
19 #include "AutoRegFactory.h"
20 #include "BundleAdjust.h"
21 #include "ControlMeasure.h"
22 #include "ControlNet.h"
23 #include "ControlPoint.h"
24 #include "ControlPointEdit.h"
25 #include "CubePlotCurve.h"
29 #include "IException.h"
33 #include "Longitude.h"
34 #include "MainWindow.h"
35 #include "MdiCubeViewport.h"
38 #include "ProfileDialog.h"
39 #include "PvlEditDialog.h"
40 #include "PvlObject.h"
41 #include "Projection.h"
42 #include "QIsisApplication.h"
43 #include "RubberBandTool.h"
44 #include "SerialNumber.h"
46 #include "SurfacePoint.h"
49 #include "UniversalGroundMap.h"
66 QString StereoTool::lastPtIdValue =
"";
80 m_serialNumberList = NULL;
87 m_profileDialog = NULL;
95 connect(
this, SIGNAL( toolActivated() ),
this, SLOT( activateTool() ) );
106 m_stereoTool->setWindowTitle(
"Elevation Calculator (via stereo pairs)");
111 QGridLayout *gridLayout =
new QGridLayout();
115 gridLayout->setColumnMinimumWidth(0, 310);
116 gridLayout->setColumnMinimumWidth(1, 310);
120 m_ptIdValue =
new QLabel();
121 gridLayout->addWidget(m_ptIdValue, row++, 0);
123 m_leftCubeLabel =
new QLabel();
124 m_rightCubeLabel =
new QLabel();
125 gridLayout->addWidget(m_leftCubeLabel, row, 0);
126 gridLayout->addWidget(m_rightCubeLabel, row++, 1);
129 gridLayout->addWidget(m_pointEditor, row++, 0, 1, 3);
131 m_pointEditor->show();
137 m_elevationLabel =
new QLabel;
138 m_elevationLabel->setToolTip(
"Calculated elevation in meters.");
139 m_elevationLabel->setWhatsThis(
"Calculated elevation based on parallax.");
140 m_elevationErrorLabel =
new QLabel;
141 m_elevationErrorLabel->setToolTip(
142 "Error in calculated elevation in meters.");
143 m_elevationErrorLabel->setWhatsThis(
"Error in calculated elevation.");
144 gridLayout->addWidget(m_elevationLabel, row, 0);
145 gridLayout->addWidget(m_elevationErrorLabel, row++, 1);
147 m_baseRadiiLabel =
new QLabel;
148 m_baseRadiiLabel->setToolTip(
"Subtracted from the calculated radius to "
149 "determine elevation.");
151 m_leftDemRadiiLabel =
new QLabel;
152 m_leftDemRadiiLabel->setToolTip(
"Left Cube DEM Radius");
153 m_rightDemRadiiLabel =
new QLabel;
154 m_rightDemRadiiLabel->setToolTip(
"Right Cube DEM Radius");
155 gridLayout->addWidget(m_baseRadiiLabel, row, 0);
156 gridLayout->addWidget(m_leftDemRadiiLabel, row, 1);
157 gridLayout->addWidget(m_rightDemRadiiLabel, row++, 2);
165 cw->setLayout(gridLayout);
166 m_stereoTool->setCentralWidget(cw);
168 connect(
this, SIGNAL( editPointChanged() ),
this, SLOT(
paintAllViewports() ) );
180 m_save =
new QAction(m_stereoTool);
181 m_save->setText(
"Save Elevation Data...");
183 "<b>Function:</b> Saves the elevation calulations to current file.";
184 m_save->setWhatsThis(whatsThis);
185 connect( m_save, SIGNAL( triggered() ),
this, SLOT( saveElevations() ) );
186 m_save->setDisabled(
true);
189 saveAs->setText(
"Save Elevation Data As...");
191 "<b>Function:</b> Saves the elevation calulations to a file.";
192 saveAs->setWhatsThis(whatsThis);
196 closeStereoTool->setText(
"&Close");
197 closeStereoTool->setShortcut(Qt::ALT + Qt::Key_F4);
199 "<b>Function:</b> Closes the Stereo Tool window for this point \
200 <p><b>Shortcut:</b> Alt+F4 </p>";
201 closeStereoTool->setWhatsThis(whatsThis);
202 connect( closeStereoTool, SIGNAL( triggered() ), m_stereoTool, SLOT( close() ) );
204 QMenu *fileMenu = m_stereoTool->menuBar()->addMenu(
"&File");
205 fileMenu->addAction(m_save);
206 fileMenu->addAction(saveAs);
207 fileMenu->addAction(closeStereoTool);
210 templateFile->setText(
"&Set registration template");
212 "<b>Function:</b> Allows user to select a new file to set as the registration template";
213 templateFile->setWhatsThis(whatsThis);
214 connect( templateFile, SIGNAL( triggered() ),
this, SLOT(
setTemplateFile() ) );
217 viewTemplate->setText(
"&View/edit registration template");
219 "<b>Function:</b> Displays the curent registration template. \
220 The user may edit and save changes under a chosen filename.";
221 viewTemplate->setWhatsThis(whatsThis);
222 connect( viewTemplate, SIGNAL( triggered() ),
this, SLOT(
viewTemplateFile() ) );
225 QMenu *optionMenu = m_stereoTool->menuBar()->addMenu(
"&Options");
226 QMenu *regMenu = optionMenu->addMenu(
"&Registration");
228 regMenu->addAction(templateFile);
229 regMenu->addAction(viewTemplate);
232 QAction *showHelpAct =
new QAction(
"stereo tool &Help", m_stereoTool);
233 showHelpAct->setIcon(QPixmap(
toolIconDir() +
"/help-contents.png") );
234 connect( showHelpAct, SIGNAL( triggered() ),
this, SLOT( showHelp() ));
236 QMenu *helpMenu = m_stereoTool->menuBar()->addMenu(
"&Help");
237 helpMenu->addAction(showHelpAct);
252 action->setIcon( QPixmap(
toolIconDir() +
"/3d-glasses-icon.png") );
253 action->setToolTip(
"Stereo");
254 action->setWhatsThis(
"<strong>Functionality:</strong> "
256 "<li>Calculate elevation at a single point by creating a "
257 "control point between the image pair. "
259 "<h4><strong>Control Point mouse Button Functions:</strong></h4>"
260 "<li>Left: Edit closest point.</li>"
261 "<li>Middle: Delete closest point.</li>"
262 "<li>Right: Create new point at cursor position.</li></ul>"
263 "<li>Left click and drag will create an elevation profile "
264 "after you create the start and end control points. A dialog "
265 "box will be shown to assist.</li>"
266 "<li>Right click and drag will create an elevation profile "
267 "between previously created control points.</li></ul>");
283 QLabel *boxLabel =
new QLabel(
"Local Radius:");
285 m_radiusBox->addItem(
"Ellipsoid Equitorial Radius");
286 m_radiusBox->addItem(
"DEM Radius");
287 m_radiusBox->addItem(
"Custom Radius");
288 m_radiusBox->setToolTip(
"Source for local radius");
290 "<b>Function: </b>Source for the local radius used for elevation "
292 m_radiusBox->setWhatsThis(text);
293 connect( m_radiusBox, SIGNAL( activated(
int) ),
294 this, SLOT( updateRadiusLineEdit() ));
296 m_radiusLineEdit =
new QLineEdit(hbox);
297 QDoubleValidator *dval =
new QDoubleValidator(hbox);
298 m_radiusLineEdit->setValidator(dval);
299 m_radiusLineEdit->setReadOnly(
true);
300 m_radiusLineEdit->setToolTip(
"Custom local radius used for elevation "
301 "calculations. To enter a value, set box to "
302 "the left to \"Custom Radius\"");
304 "<b>Function: </b>Custom local radius used to calculate elevations. "
305 "This can be changed by selecting \"Custom Radius\" in the box to "
307 m_radiusLineEdit->setWhatsThis(text);
310 connect( m_radiusLineEdit, SIGNAL( editingFinished() ),
311 this, SLOT( userBaseRadius() ));
313 m_radiusLineEdit->setEnabled(
false);
315 QLabel *radiusUnit =
new QLabel(
"Meters");
317 QToolButton *helpButton =
new QToolButton(hbox);
318 helpButton->setIcon( QPixmap(
toolIconDir() +
"/help-contents.png") );
319 helpButton->setToolTip(
"Help");
320 helpButton->setIconSize( QSize(22, 22) );
321 connect( helpButton, SIGNAL( clicked() ),
this, SLOT( showHelp() ));
323 QHBoxLayout *layout =
new QHBoxLayout;
324 layout->setMargin(0);
326 layout->addWidget(boxLabel);
327 layout->addWidget(m_radiusBox);
328 layout->addWidget(m_radiusLineEdit);
329 layout->addWidget(radiusUnit);
330 layout->addStretch();
331 layout->addWidget(helpButton);
332 hbox->setLayout(layout);
341 void StereoTool::activateTool() {
351 qobject_cast<QWidget *>( parent() ) );
362 void StereoTool::warningDialog() {
367 QVBoxLayout *mainLayout =
new QVBoxLayout;
368 warningDialog->setLayout(mainLayout);
370 QLabel *warningsText =
new QLabel(
"<p><strong>Warning:</strong> "
371 "The camera orientations are very critical for correct results. "
372 "Poor orientations will result in bad elevation measurements. The "
373 "camera orientations can be corrected with the programs "
374 "<i>jigsaw, deltack, or qtie.");
375 warningsText->setWordWrap(
true);
376 mainLayout->addWidget(warningsText);
377 QCheckBox *showWarning =
new QCheckBox(
"Do not show this message again");
378 showWarning->setChecked(
false);
379 mainLayout->addWidget(showWarning);
381 QPushButton *okButton =
new QPushButton(
"OK");
382 mainLayout->addStretch();
383 mainLayout->addWidget(okButton);
384 connect( okButton, SIGNAL( clicked() ), warningDialog, SLOT( accept() ));
386 if ( warningDialog->exec() ) {
387 if ( showWarning->isChecked() ) m_showWarning =
false;
396 void StereoTool::showHelp() {
399 helpDialog->setWindowTitle(
"Stereo Tool Help");
401 QVBoxLayout *mainLayout =
new QVBoxLayout;
402 helpDialog->setLayout(mainLayout);
404 QLabel *stereoTitle =
new QLabel(
"<h2>Stereo Tool</h2>");
405 mainLayout->addWidget(stereoTitle);
407 QLabel *stereoSubtitle =
new QLabel(
"A tool for calculating point elevations "
408 "and elevation profiles using stereo pairs "
410 stereoSubtitle->setWordWrap(
true);
411 mainLayout->addWidget(stereoSubtitle);
413 QTabWidget *tabArea =
new QTabWidget;
414 tabArea->setDocumentMode(
true);
415 mainLayout->addWidget(tabArea);
418 QScrollArea *overviewTab =
new QScrollArea;
419 overviewTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
420 overviewTab->setWidgetResizable(
true);
422 QVBoxLayout *overviewLayout =
new QVBoxLayout;
423 overviewContainer->setLayout(overviewLayout);
425 QLabel *purposeTitle =
new QLabel(
"<h2>Purpose</h2>");
426 overviewLayout->addWidget(purposeTitle);
428 QLabel *purposeText =
new QLabel(
"<p>This tool will use parallax from a "
429 "stereo pair of cubes to calculate elevations at chosen control points "
430 "or create elevation profiles between two chosen control points. "
431 "Elevations are computed from points between the left and right cubes. "
432 "Vectors from the target (planet center) to the spacecraft and target "
433 "to the surface registration points are computed for each point. From "
434 "these points, the elevation is computed.");
435 purposeText->setWordWrap(
true);
436 overviewLayout->addWidget(purposeText);
438 QLabel *warningsTitle =
new QLabel(
"<h2>Warnings</h2>");
439 overviewLayout->addWidget(warningsTitle);
441 QLabel *warningsText =
new QLabel(
"<p>The camera orientations are very "
442 "critical for correct results. Poor orientations will result in "
443 "bad elevation measurements. The camera orientations can be corrected "
444 "with the programs <i>jigsaw, deltack, or qtie.");
445 warningsText->setWordWrap(
true);
446 overviewLayout->addWidget(warningsText);
448 overviewTab->setWidget(overviewContainer);
451 QScrollArea *quickTab =
new QScrollArea;
452 quickTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
453 quickTab->setWidgetResizable(
true);
455 QVBoxLayout *quickLayout =
new QVBoxLayout;
456 quickContainer->setLayout(quickLayout);
458 QLabel *quickTitle =
new QLabel(
"<h2>Quick Start</h2>");
459 quickLayout->addWidget(quickTitle);
461 QLabel *quickSubTitle =
new QLabel(
"<h3>Preparation:</h3>");
462 quickLayout->addWidget(quickSubTitle);
464 QLabel *quickPrep =
new QLabel(
"<p><ul>"
465 "<li>Open the two cubes of a stereo pair</li>"
466 "<li>Link the two displayed cube windows</li>");
467 quickPrep->setWordWrap(
true);
468 quickLayout->addWidget(quickPrep);
470 QLabel *quickFunctionTitle =
new QLabel(
"<h3>Cube Viewport Functions:</h3>");
471 quickLayout->addWidget(quickFunctionTitle);
473 QLabel *quickFunction =
new QLabel(
474 "The stereo tool window will be shown once "
475 "you click on a cube viewport window using one of the following "
476 "cube viewport functions.");
477 quickFunction->setWordWrap(
true);
478 quickLayout->addWidget(quickFunction);
480 QLabel *quickDesc =
new QLabel(
"<p><ul>"
481 "<li>Calculate elevation at a single point by creating a "
482 "control point between the image pair by right clicking in the cube "
483 "viewport window on the location you are interested in. Once the "
484 "control point is refined, click the \"Save Measure\" button in "
485 "the Stereo Tool window and the elevation will be calculated. The elevation "
486 "reported is relative to the radius which is defined on the toolbar.</li>"
487 "<li>Left click and drag will create an elevation profile "
488 "after you create the start and end control points. A dialog "
489 "box will be shown to assist in creating the control points.</li>"
490 "<li>Right click and drag will create an elevation profile "
491 "between two previously created control points.</li></ul>"
492 "<p><strong>Note:</strong> The quality of the profiles is dependent on the registration "
493 "between the two images at each point along the profile. Registration "
494 "parameters can be changed under Options->Registration mentu of the "
495 "Elevation Calculator window. A discussion of these parameters can be found at: "
496 "<a href=\"http://isis.astrogeology.usgs.gov/documents/PatternMatch/PatternMatch.html\">"
497 "Pattern Matching</a>");
498 quickDesc->setWordWrap(
true);
499 quickDesc->setOpenExternalLinks(
true);
500 quickLayout->addWidget(quickDesc);
502 quickTab->setWidget(quickContainer);
505 QScrollArea *controlPointTab =
new QScrollArea;
506 controlPointTab->setWidgetResizable(
true);
507 controlPointTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
509 QVBoxLayout *controlPointLayout =
new QVBoxLayout;
510 controlPointContainer->setLayout(controlPointLayout);
512 QLabel *controlPointTitle =
new QLabel(
"<h2>Control Point Editing</h2>");
513 controlPointLayout->addWidget(controlPointTitle);
515 QLabel *mouseLabel =
new QLabel(
"<p><h3>When the \"Stereo\" tool "
516 "is activated, the mouse buttons have the following function in the "
517 "cube viewports of the main qview window:</h3>");
518 mouseLabel->setWordWrap(
true);
519 mouseLabel->setScaledContents(
true);
520 controlPointLayout->addWidget(mouseLabel);
522 QLabel *controlPointDesc =
new QLabel(
"<ul>"
523 "<li>Left click - Edit the closest control point</li>"
524 "<li>Middle click - Delete the closest control point</li>"
525 "<li>Right click - Create new control point at cursor location</li>"
526 "<li>Left click and drag - Create an elevation profile "
527 "after you create the start and end control points. A dialog "
528 "box will be shown to assist in creating the control points.</li>"
529 "<li>Right click and drag - Create an elevation profile "
530 "between two previously created control points.</li></ul>");
531 controlPointDesc->setWordWrap(
true);
532 controlPointLayout->addWidget(controlPointDesc);
534 QLabel *controlPointEditing =
new QLabel(
535 "<h4>Changing Measure Locations</h4>"
536 "<p>The measure location can be adjusted by:"
538 "<li>Move the cursor location under the crosshair by clicking the left mouse "
540 "<li>Move 1 pixel at a time by using arrow keys on the keyboard</li>"
541 "<li>Move 1 pixel at a time by using arrow buttons above the right view</li>"
543 "<h4>Other Point Editor Functions</h4>"
544 "<p>Along the right border of the window:</p>"
546 "<li><strong>Geom:</strong> Geometrically match the right view to the left"
548 "<li><strong>Rotate:</strong> Rotate the right view using either the dial"
549 "or entering degrees </li>"
550 "<li><strong>Show control points:</strong> Draw crosshairs at all control"
551 "point locations visible within the view</li>"
552 "<li><strong>Show crosshair:</strong> Show a red crosshair across the entire"
554 "<li><strong>Circle:</strong> Draw circle which may help center measure"
555 "on a crater</li></ul"
556 "<p>Below the left view:</p>"
557 "<ul><li><strong>Blink controls:</strong> Blink the left and right view in the"
558 "left view window using the \"Blink Start\" button (with play icon) and "
559 "\"Blink Stop\" button (with stop icon). Both arrow keys above the right view "
560 "and the keyboard arrow keys may be used to move the right view while"
562 "<li><strong>Find:</strong> Center the right view so that the same latitude "
563 "longitude is under the crosshair as the left view.</li></ul"
564 "<p>Below the right view:</p>"
565 "<ul><li><strong>Register:</strong> Sub-pixel register the the right view to"
566 "the left view.</li>"
567 "<li><strong>Save Measure:</strong> Save the control point under the"
568 "crosshairs and calculated elevation.</li></ul>");
569 controlPointEditing->setWordWrap(
true);
570 controlPointLayout->addWidget(controlPointEditing);
572 controlPointTab->setWidget(controlPointContainer);
576 tabArea->addTab(overviewTab,
"&Overview");
577 tabArea->addTab(quickTab,
"&Quick Start");
578 tabArea->addTab(controlPointTab,
"&Control Point Editing");
580 QHBoxLayout *buttonsLayout =
new QHBoxLayout;
582 buttonsLayout->addStretch();
584 QPushButton *closeButton =
new QPushButton(
"&Close");
585 closeButton->setIcon( QPixmap(
toolIconDir() +
"/guiStop.png" ) );
586 closeButton->setDefault(
true);
587 connect( closeButton, SIGNAL( clicked() ),
588 helpDialog, SLOT( close() ) );
589 buttonsLayout->addWidget(closeButton);
591 mainLayout->addLayout(buttonsLayout);
600 void StereoTool::userBaseRadius() {
603 m_baseRadius =
Distance(m_radiusLineEdit->text().toDouble(),
608 if (m_stereoTool->isVisible() && m_editPoint != NULL) {
609 calculateElevation();
613 QString message =
"Invalid base radius entered.";
615 m_radiusLineEdit->setText(
"");
616 QMessageBox::critical(m_stereoTool,
"Error", message);
625 void StereoTool::updateRadiusLineEdit() {
628 if ( m_radiusBox->currentText() ==
"Ellipsoid Equitorial Radius" ) {
629 if ( m_targetRadius.
isValid() ) {
630 m_radiusLineEdit->setText( QString::number( m_targetRadius.
meters(),
'f',
632 m_baseRadius = m_targetRadius;
635 m_radiusLineEdit->setText(
"");
637 m_radiusLineEdit->setReadOnly(
true);
638 m_radiusLineEdit->setEnabled(
false);
640 else if ( m_radiusBox->currentText() ==
"DEM Radius" ) {
645 QString message =
"No valid Dem on cube. Run <i>spicinit</i> using a "
646 "dem shape model. The local radius will default back to the ellipsoid.";
647 QMessageBox::warning(m_stereoTool,
"Warning", message);
648 m_radiusBox->setCurrentIndex(0);
650 m_radiusLineEdit->setReadOnly(
true);
651 m_radiusLineEdit->setEnabled(
false);
655 m_radiusLineEdit->setText(
"");
656 m_radiusLineEdit->setReadOnly(
true);
657 m_radiusLineEdit->setEnabled(
false);
661 m_radiusLineEdit->setReadOnly(
false);
662 m_radiusLineEdit->setEnabled(
true);
666 if ( m_stereoTool->isVisible() && m_editPoint != NULL ) {
667 calculateElevation();
673 void StereoTool::setupFiles() {
683 m_linkedViewports.clear();
689 if ( m_linkedViewports.size() < 2 ) {
690 IString message =
"Two cube viewports containing a stereo pair "
691 "need to be linked.";
694 if ( m_linkedViewports.size() > 2 ) {
695 IString message =
"Only two cube viewports containing a stereo pair "
702 if ( m_linkedViewports.at(0)->cube() == m_leftCube ||
703 m_linkedViewports.at(0)->cube() == m_rightCube ) {
704 if ( m_linkedViewports.at(1)->cube() == m_leftCube ||
705 m_linkedViewports.at(1)->cube() == m_rightCube ) {
713 if ( m_controlNet->GetTarget() !=
714 m_linkedViewports.at(0)->cube()->camera()->target()->name() ) {
717 QString message =
"You have changed targets. All data must be re-set";
718 message +=
" for new target. Would you like to save your current";
719 message +=
" points before resetting?";
720 int response = QMessageBox::question(m_stereoTool,
721 "Save current points", message,
722 QMessageBox::Yes | QMessageBox::No,
724 if (response == QMessageBox::Yes) {
727 m_stereoTool->setVisible(
false);
730 m_controlNet->SetTarget(*m_linkedViewports.at(0)->cube()->label());
736 m_controlNet->SetTarget(
737 m_linkedViewports.at(0)->cube()->camera()->target()->name() );
745 setFiles( m_linkedViewports.at(0)->cube(), m_linkedViewports.at(1)->cube() );
761 m_stereoTool->setVisible(
false);
786 m_leftCube = leftCube;
787 m_rightCube = rightCube;
792 m_leftCubeLabel->setText(leftName);
793 m_rightCubeLabel->setText(rightName);
803 m_serialNumberList->
add( m_rightCube->
fileName() );
811 QString message =
"Could not determine target radius.";
812 QMessageBox::critical(m_stereoTool,
"Error",message);
814 updateRadiusLineEdit();
817 updateRadiusLineEdit();
824 QString message =
"Cannot initialize universal ground map for " +
827 QMessageBox::critical(m_stereoTool,
"Error", message);
834 QString message =
"Cannot initialize universal ground map for" +
837 QMessageBox::critical(m_stereoTool,
"Error", message);
852 double samp = m_editPoint->
GetMeasure(Left)->GetSample();
853 double line = m_editPoint->
GetMeasure(Left)->GetLine();
866 QString message =
"Unable to set Apriori Surface Point.\n";
867 message +=
"Latitude = " + QString::number(lat);
868 message +=
" Longitude = " + QString::number(lon);
869 message +=
" Radius = " + QString::number(m_targetRadius.
meters(),
'f',
872 QMessageBox::critical(m_stereoTool,
"Error", message);
875 calculateElevation();
876 emit editPointChanged();
887 rubberBandTool()->
enable(RubberBandTool::LineMode);
888 rubberBandTool()->enablePoints();
889 rubberBandTool()->enableAllClicks();
895 void StereoTool::rubberBandComplete() {
904 QMessageBox::critical(m_stereoTool,
"Error setting stereo pair", message);
905 rubberBandTool()->
clear();
919 QString message =
"This cube is not linked as a stereo pair. Make ";
920 message +=
"sure you have two stereo pair cube viewports linked.";
921 QMessageBox::critical(m_stereoTool,
"Viewport not linked", message);
925 if ( rubberBandTool()->figureIsPoint() ) {
928 rubberBandTool()->vertices()[0].ry(),
930 if ( rubberBandTool()->mouseButton() & Qt::LeftButton ) {
931 if ( !m_controlNet || m_controlNet->GetNumMeasures() == 0 ) {
932 QString message =
"No points exist for editing. Create points ";
933 message +=
"using the right mouse button.";
934 QMessageBox::information(m_stereoTool,
"Warning", message);
940 point = m_controlNet->FindClosest(sn, samp, line);
943 QString message =
"No points found for editing. Create points ";
944 message +=
"using the right mouse button.";
946 QMessageBox::critical(m_stereoTool,
"Error", message);
951 else if ( rubberBandTool()->mouseButton() & Qt::MidButton ) {
952 if ( !m_controlNet || m_controlNet->GetNumPoints() == 0 ) {
953 QString message =
"No points exist for deleting. Create points ";
954 message +=
"using the right mouse button.";
955 QMessageBox::warning(m_stereoTool,
"Warning", message);
961 m_controlNet->FindClosest(sn, samp, line);
964 QString message =
"No points exist for deleting. Create points ";
965 message +=
"using the right mouse button.";
966 QMessageBox::information(m_stereoTool,
"Warning", message);
971 else if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
973 if (cvp->
cube() == m_leftCube) {
987 QString message =
"Cannot create control point.\n\n";
989 QMessageBox::critical(m_stereoTool,
"Error", message);
991 rubberBandTool()->
clear();
1001 if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
1004 rubberBandTool()->vertices()[0].ry(),
1007 m_startPoint = m_controlNet->FindClosest(sn, samp, line);
1010 QString message =
"Cannot find start point for profile. Either ";
1011 message +=
"create end points individually using the right mouse ";
1012 message +=
"button. Or, create profile end points by clicking and ";
1013 message +=
"dragging with the right mouse button.\n\n";
1015 QMessageBox::critical(m_stereoTool,
"Error", message);
1016 m_startPoint = NULL;
1017 rubberBandTool()->
clear();
1021 rubberBandTool()->vertices()[1].ry(),
1024 m_endPoint = m_controlNet->FindClosest(sn, samp, line);
1025 if ( m_startPoint->
GetId() == m_endPoint->
GetId() ) {
1031 QString message =
"Cannot find end point for profile. Either ";
1032 message +=
"create end points individually using the right mouse ";
1033 message +=
"button. Or, create profile end points by clicking and ";
1034 message +=
"dragging with the right mouse button.\n\n";
1036 QMessageBox::critical(m_stereoTool,
"Error", message);
1037 m_startPoint = NULL;
1039 rubberBandTool()->
clear();
1046 m_profileDialog =
new ProfileDialog();
1047 connect( m_profileDialog, SIGNAL( createStart() ),
1048 this, SLOT( createStartPoint() ) );
1049 connect( m_profileDialog, SIGNAL( createEnd() ),
1050 this, SLOT( createEndPoint() ) );
1051 connect( m_profileDialog, SIGNAL( accepted() ),
1052 this, SLOT( profile() ) );
1053 connect( m_profileDialog, SIGNAL( accepted() ),
1054 this, SLOT( profile() ) );
1055 connect( m_profileDialog, SIGNAL( rejected() ),
1056 this, SLOT( clearProfile() ) );
1057 m_profileDialog->show();
1058 m_profileDialog->activateWindow();
1065 void StereoTool::clearProfile() {
1066 m_startPoint = NULL;
1068 rubberBandTool()->
clear();
1069 delete m_profileDialog;
1070 m_profileDialog = NULL;
1075 void StereoTool::createStartPoint() {
1083 rubberBandTool()->vertices()[0].ry(),
1085 if ( cvp->
cube() == m_leftCube ) {
1099 QString message =
"Cannot create control point.\n\n";
1101 QMessageBox::critical(m_stereoTool,
"Error", message);
1102 delete m_profileDialog;
1103 m_profileDialog = NULL;
1104 rubberBandTool()->
clear();
1107 m_startPoint = m_editPoint;
1112 void StereoTool::createEndPoint() {
1120 rubberBandTool()->vertices()[1].ry(),
1122 if ( cvp->
cube() == m_leftCube ) {
1136 QString message =
"Cannot create control point.\n\n";
1138 QMessageBox::critical(m_stereoTool,
"Error", message);
1139 m_startPoint = NULL;
1140 delete m_profileDialog;
1141 m_profileDialog = NULL;
1142 rubberBandTool()->
clear();
1145 m_endPoint = m_editPoint;
1167 double leftSamp = 0, leftLine = 0;
1168 double rightSamp = 0, rightLine = 0;
1172 leftSamp = m_leftGM->
Sample();
1173 leftLine = m_leftGM->
Line();
1178 rightSamp = m_rightGM->
Sample();
1179 rightLine = m_rightGM->
Line();
1180 if ( rightSamp < 1 || rightSamp > m_rightCube->
sampleCount() ||
1181 rightLine < 1 || rightLine > m_rightCube->
lineCount() ) {
1182 IString message =
"Point does not exist on cube, " +
1192 IString message =
"Point does not exist on cube, " +
1202 IString message =
"Point does not exist on cube, " +
1214 bool goodId =
false;
1217 QString
id = QInputDialog::getText(m_stereoTool,
1218 "Point ID",
"Enter Point ID:",
1219 QLineEdit::Normal, lastPtIdValue,
1226 if ( ok &&
id.isEmpty() ) {
1228 QString message =
"You must enter a point Id.";
1229 QMessageBox::warning(m_stereoTool,
"Warning", message);
1234 if ( m_controlNet->GetNumPoints() > 0 &&
1235 m_controlNet->ContainsPoint(newPoint->
GetId() ) ) {
1236 QString message =
"A ControlPoint with Point Id = [" +
1238 "] already exists. Re-enter unique Point Id.";
1239 QMessageBox::warning(m_stereoTool,
"Unique Point Id", message);
1260 newPoint->
Add(mLeft);
1268 newPoint->
Add(mRight);
1271 m_controlNet->AddPoint(newPoint);
1273 m_editPoint = m_controlNet->GetPoint( (QString) newPoint->
GetId() );
1276 m_stereoTool->setVisible(
true);
1277 m_stereoTool->raise();
1279 emit editPointChanged();
1296 m_editPoint = point;
1299 emit editPointChanged();
1303 m_controlNet->DeletePoint( m_editPoint->
GetId() );
1304 m_stereoTool->setVisible(
false);
1307 emit editPointChanged();
1319 m_editPoint = point;
1321 m_stereoTool->setVisible(
true);
1322 m_stereoTool->raise();
1323 emit editPointChanged();
1336 m_editPoint->
GetId() );
1338 m_rightCube, m_editPoint->
GetId() );
1341 QString ptId =
"Point ID: " + m_editPoint->
GetId();
1342 m_ptIdValue->setText(ptId);
1350 QString serialNumber) {
1356 m_startPoint->
GetMeasure(serialNumber)->GetLine(),
1359 m_endPoint->
GetMeasure(serialNumber)->GetLine(),
1361 painter->setPen(Qt::green);
1362 painter->drawLine(x1, y1, x2, y2);
1380 if ( m_controlNet == NULL || m_controlNet->GetNumPoints() == 0 )
1386 if ( !m_controlNet->GetCubeSerials().contains(
1387 serialNumber) )
return;
1396 m_controlNet->GetMeasuresInCube(serialNumber);
1398 for (
int i = 0; i < measures.count(); i++) {
1401 double samp = m->GetSample();
1402 double line = m->GetLine();
1406 if ( m->Parent()->IsIgnored() ) {
1407 painter->setPen( QColor(255, 255, 0) );
1410 else if ( m->IsIgnored() ) {
1411 painter->setPen( QColor(255, 255, 0) );
1415 painter->setPen(Qt::magenta);
1418 painter->setPen(Qt::green);
1421 painter->drawLine(x - 5, y, x + 5, y);
1422 painter->drawLine(x, y - 5, x, y + 5);
1426 if ( m_editPoint != NULL ) {
1430 double samp = (*m_editPoint)[serialNumber]->GetSample();
1431 double line = (*m_editPoint)[serialNumber]->GetLine();
1435 QBrush brush(Qt::red);
1439 painter->setPen(pen);
1440 painter->drawLine(x - 5, y, x + 5, y);
1441 painter->drawLine(x, y - 5, x, y + 5);
1461 vp->viewport()->update();
1467 void StereoTool::calculateElevation() {
1468 calculateElevation(m_editPoint);
1479 double elevation=0., elevationError=0.;
1485 if ( m_radiusBox->currentText() ==
"DEM Radius" ) {
1487 leftCamera->
SetImage( (*point)[Left]->GetSample(),
1488 (*point)[Left]->GetLine() );
1491 if ( !m_baseRadius.
isValid() ) {
1492 QString message =
"Invalid Dem radius, defaulting to ellipsoidal.";
1493 QMessageBox::warning(m_stereoTool,
"Invalid Dem radius", message);
1494 m_baseRadius = m_targetRadius;
1499 leftCamera->
SetImage( (*point)[Left]->GetSample(),
1500 (*point)[Left]->GetLine() );
1503 rightCamera->
SetImage( (*point)[Right]->GetSample(),
1504 (*point)[Right]->GetLine() );
1506 double radius, lat, lon, sepang;
1507 if ( Stereo::elevation( *leftCamera, *rightCamera, radius, lat, lon, sepang,
1508 elevationError ) ) {
1509 elevation = radius - m_baseRadius.
meters();
1535 QString filename = QFileDialog::getOpenFileName( m_stereoTool,
1536 "Select a registration template",
".",
1537 "Registration template files (*.def *.pvl);;All files (*)" );
1539 if ( filename.isEmpty() )
1561 Pvl templatePvl( m_pointEditor->templateFileName() );
1565 registrationDialog.setWindowTitle(
"View or Edit Template File: "
1567 registrationDialog.resize(550, 360);
1568 registrationDialog.exec();
1572 QMessageBox::warning(m_stereoTool,
"Error", message);
1584 QString fn = QFileDialog::getSaveFileName( m_stereoTool,
1585 "Choose filename to save under",
1587 "CSV Files (*.csv)" );
1591 if ( !fn.isEmpty() ) {
1592 if ( !fn.endsWith(
".csv") ) {
1593 filename = fn +
".csv";
1604 m_currentFile.setFileName(filename);
1606 m_save->setEnabled(
true);
1612 void StereoTool::saveElevations() {
1614 if ( m_currentFile.fileName().isEmpty() )
return;
1616 bool success = m_currentFile.open(QIODevice::WriteOnly);
1618 QMessageBox::critical(m_stereoTool,
"Error",
1619 "Cannot open file, please check permissions");
1620 m_currentFile.setFileName(
"");
1621 m_save->setDisabled(
true);
1625 QTextStream text(&m_currentFile);
1626 QString header =
"Point ID, Latitude, Longitude, Radius, ";
1627 header +=
"Elevation, Elevation Error, ";
1628 header +=
"Image 1, Sample, Line, Image 2, Sample, Line";
1629 text << header << endl;
1634 for (
int i = 0; i < m_controlNet->GetNumPoints(); i++) {
1637 data = p.
GetId() +
"," +
1642 QString::number( p.
GetMeasure(Left)->GetFocalPlaneMeasuredX(),
'f',
1644 QString::number( p.
GetMeasure(Left)->GetFocalPlaneMeasuredY(),
'f',
1645 6 ) +
"," + leftFile +
"," +
1646 QString::number( p.
GetMeasure(Left)->GetSample() ) +
"," +
1647 QString::number( p.
GetMeasure(Left)->GetLine() ) +
"," +
1649 QString::number( p.
GetMeasure(Right)->GetSample() ) +
"," +
1650 QString::number( p.
GetMeasure(Right)->GetLine() );
1651 text << data << endl;
1653 m_currentFile.close();
1659 void StereoTool::clearNetData() {
1661 delete m_controlNet;
1662 m_controlNet = NULL;
1663 delete m_serialNumberList;
1664 m_serialNumberList = NULL;
1670 void StereoTool::profile() {
1678 if (m_profileDialog) {
1679 delete m_profileDialog;
1680 m_profileDialog = NULL;
1686 QPointF leftStart( (*m_startPoint)[Left]->GetSample(),
1687 (*m_startPoint)[Left]->GetLine() );
1688 QPointF leftEnd( (*m_endPoint)[Left]->GetSample(),
1689 (*m_endPoint)[Left]->GetLine() );
1691 QPointF rightStart( (*m_startPoint)[Right]->GetSample(),
1692 (*m_startPoint)[Right]->GetLine() );
1693 QPointF rightEnd( (*m_endPoint)[Right]->GetSample(),
1694 (*m_endPoint)[Right]->GetLine() );
1700 m_linkedViewports.at(0)->cubeToViewport( (*m_startPoint)[Left]->GetSample(),
1701 (*m_startPoint)[Left]->GetLine(), sx, sy);
1702 m_linkedViewports.at(0)->cubeToViewport( (*m_endPoint)[Left]->GetSample(),
1703 (*m_endPoint)[Left]->GetLine(), ex, ey);
1704 rubberBand1.push_back( QPoint(sx, sy) );
1705 rubberBand1.push_back( QPoint(ex, ey) );
1707 rubberBandVertices.push_back(rubberBand1);
1710 m_linkedViewports.at(1)->cubeToViewport( (*m_startPoint)[Right]->GetSample(),
1711 (*m_startPoint)[Right]->GetLine(), sx, sy);
1712 m_linkedViewports.at(1)->cubeToViewport( (*m_endPoint)[Right]->GetSample(),
1713 (*m_endPoint)[Right]->GetLine(), ex, ey);
1714 rubberBand2.push_back( QPoint(sx, sy) );
1715 rubberBand2.push_back( QPoint(ex, ey) );
1717 rubberBandVertices.push_back(rubberBand2);
1720 QLineF leftProfile(leftStart,leftEnd);
1721 QLineF rightProfile(rightStart,rightEnd);
1725 QLineF longProfile, shortProfile;
1726 Cube *longCube, *shortCube;
1727 if ( leftProfile.length() > rightProfile.length() ) {
1728 longProfile = leftProfile;
1729 longCube = m_leftCube;
1730 shortProfile = rightProfile;
1731 shortCube = m_rightCube;
1734 longProfile = rightProfile;
1735 longCube = m_rightCube;
1736 shortProfile = leftProfile;
1737 shortCube = m_leftCube;
1741 double elevation = 0.;
1742 double elevationError = 0.;
1744 Pvl regDef = m_pointEditor->templateFileName();
1747 int failureCount = 0;
1748 QApplication::setOverrideCursor(Qt::WaitCursor);
1750 for (
int i = 0; i <= (int) shortProfile.length(); i++) {
1751 double shortSamp=0, shortLine=0, longSamp=0, longLine=0;
1753 shortSamp = shortProfile.pointAt( 1/shortProfile.length() * i ).x();
1754 shortLine = shortProfile.pointAt( 1/shortProfile.length() * i ).y();
1756 longSamp = longProfile.pointAt( 1/shortProfile.length() * i ).x();
1757 longLine = longProfile.pointAt( 1/shortProfile.length() * i ).y();
1773 if ( m_radiusBox->currentText() ==
"DEM Radius" ) {
1779 if ( !m_baseRadius.
isValid() ) {
1780 QString message =
"Invalid Dem radius, defaulting to ellipsoidal.";
1781 QMessageBox::warning(m_stereoTool,
"Invalid Dem radius", message);
1782 m_baseRadius = m_targetRadius;
1791 double radius, lat, lon, sepang;
1792 if (Stereo::elevation( *shortCube->
camera(), *longCube->
camera(),
1793 radius, lat, lon, sepang, elevationError) )
1794 elevation = radius - m_baseRadius.
meters();
1795 profileData.append( QPointF(i, elevation) );
1804 QString message =
"Error registering cubes along profile line.\n";
1805 message +=
"Image 1 Sample = " + QString::number(shortSamp);
1806 message +=
" Line = " + QString::number(shortLine);
1807 message +=
"\nImage 2 Sample = " + QString::number(longSamp);
1808 message +=
" Line = " + QString::number(longLine) +
"\n\n";
1810 QMessageBox::critical(m_stereoTool,
"Error", message);
1811 rubberBandTool()->
clear();
1815 QApplication::restoreOverrideCursor();
1818 QString message =
"Registration attempts (pixels on line) = " +
1819 QString::number( (
int)shortProfile.length() ) +
1820 "\n\nRegistration failures = " +
1821 QString::number(failureCount) +
1822 "\n\nYou can adjust registration parameters in the "
1823 "\"Options\" menu in the Elevation Calculator window. "
1824 "Select \"Options\", then \"Registration\", then either "
1825 "\"Select registration template\" or "
1826 "\"View/edit registration template\".";
1827 QMessageBox::information(m_stereoTool,
"Registration Report", message);
1829 if ( ( (
int)shortProfile.length() + 1 - failureCount ) < 2 ) {
1830 QString message =
"Cannot create profile, all auto-registration between ";
1831 message +=
"the left and right cubes along the profile failed. Try ";
1832 message +=
"adjusting the registration parameters.";
1833 QMessageBox::critical(m_stereoTool,
"Error", message);
1841 plotCurve->
setData(
new QwtPointSeriesData(profileData) );
1842 plotCurve->setTitle(
"Elevations (Meters)");
1843 plotCurve->
setPen( QPen(Qt::white) );
1851 plotCurve->
setSource(m_linkedViewports, rubberBandVertices, bands);
1852 plotWindow->
add(plotCurve);
1854 delete m_profileDialog;
1855 m_profileDialog = NULL;
1864 void StereoTool::updateLabels() {
1866 QString elevationLabel, elevationErrorLabel;
1867 QString baseRadiiLabel, leftDemRadiiLabel, rightDemRadiiLabel;
1869 elevationLabel =
"Elevation: " +
1870 QString::number( m_editPoint->
GetMeasure(Left)->
1871 GetFocalPlaneMeasuredX(),
'f', 6 );
1872 elevationErrorLabel =
"Elevation Error: " +
1873 QString::number( m_editPoint->
GetMeasure(Left)->
1874 GetFocalPlaneMeasuredY(),
'f', 6 );
1875 baseRadiiLabel =
"Local Radii: " + QString::number(
1876 m_baseRadius.
meters(),
'f', 6 );
1879 leftCamera->
SetImage( (*m_editPoint)[Left]->GetSample(),
1880 (*m_editPoint)[Left]->GetLine() );
1881 double leftDemRadii =
1883 leftDemRadiiLabel =
"Left DEM Radii: " +
1884 QString::number(leftDemRadii,
'f', 6);
1887 rightCamera->
SetImage( (*m_editPoint)[Right]->GetSample(),
1888 (*m_editPoint)[Right]->GetLine() );
1889 double rightDemRadii =
1891 rightDemRadiiLabel =
"Right DEM Radii: " +
1892 QString::number(rightDemRadii,
'f', 6);
1895 elevationLabel =
"Elevation: ";
1896 elevationErrorLabel =
"Elevation Error: ";
1897 baseRadiiLabel =
"Local Radii: ";
1898 leftDemRadiiLabel =
"Left DEM Radii: ";
1899 rightDemRadiiLabel =
"Right DEM Radii: ";
1901 m_elevationLabel->setText(elevationLabel);
1902 m_elevationErrorLabel->setText(elevationErrorLabel);
1903 m_baseRadiiLabel->setText(baseRadiiLabel);
1904 m_leftDemRadiiLabel->setText(leftDemRadiiLabel);
1905 m_rightDemRadiiLabel->setText(rightDemRadiiLabel);
1910 void StereoTool::readSettings() {
1911 FileName config(
"$HOME/.Isis/qview/Stereo Tool.config");
1912 QSettings settings(config.expanded(),
1913 QSettings::NativeFormat);
1914 m_showWarning = settings.value(
"showWarning",
true).toBool();
1920 void StereoTool::writeSettings() {
1921 FileName config(
"$HOME/.Isis/qview/Stereo Tool.config");
1922 QSettings settings(config.expanded(),
1923 QSettings::NativeFormat);
1924 settings.setValue(
"showWarning", m_showWarning);