1 #include "StereoTool.h"
8 #include "AbstractPlotTool.h"
16 #include "ControlPointEdit.h"
26 #include "MainWindow.h"
30 #include "ProfileDialog.h"
31 #include "PvlEditDialog.h"
35 #include "RubberBandTool.h"
58 QString StereoTool::lastPtIdValue =
"";
72 m_serialNumberList = NULL;
79 m_profileDialog = NULL;
87 connect(
this, SIGNAL( toolActivated() ),
this, SLOT( activateTool() ) );
98 m_stereoTool->setWindowTitle(
"Elevation Calculator (via stereo pairs)");
103 QGridLayout *gridLayout =
new QGridLayout();
107 gridLayout->setColumnMinimumWidth(0, 310);
108 gridLayout->setColumnMinimumWidth(1, 310);
112 m_ptIdValue =
new QLabel();
113 gridLayout->addWidget(m_ptIdValue, row++, 0);
115 m_leftCubeLabel =
new QLabel();
116 m_rightCubeLabel =
new QLabel();
117 gridLayout->addWidget(m_leftCubeLabel, row, 0);
118 gridLayout->addWidget(m_rightCubeLabel, row++, 1);
121 gridLayout->addWidget(m_pointEditor, row++, 0, 1, 3);
123 m_pointEditor->show();
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);
139 m_baseRadiiLabel =
new QLabel;
140 m_baseRadiiLabel->setToolTip(
"Subtracted from the calculated radius to "
141 "determine elevation.");
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);
157 cw->setLayout(gridLayout);
158 m_stereoTool->setCentralWidget(cw);
160 connect(
this, SIGNAL( editPointChanged() ),
this, SLOT(
paintAllViewports() ) );
172 m_save =
new QAction(m_stereoTool);
173 m_save->setText(
"Save Elevation Data...");
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);
181 saveAs->setText(
"Save Elevation Data As...");
183 "<b>Function:</b> Saves the elevation calulations to a file.";
184 saveAs->setWhatsThis(whatsThis);
188 closeStereoTool->setText(
"&Close");
189 closeStereoTool->setShortcut(Qt::ALT + Qt::Key_F4);
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() ) );
196 QMenu *fileMenu = m_stereoTool->menuBar()->addMenu(
"&File");
197 fileMenu->addAction(m_save);
198 fileMenu->addAction(saveAs);
199 fileMenu->addAction(closeStereoTool);
202 templateFile->setText(
"&Set registration template");
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() ) );
209 viewTemplate->setText(
"&View/edit registration template");
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() ) );
217 QMenu *optionMenu = m_stereoTool->menuBar()->addMenu(
"&Options");
218 QMenu *regMenu = optionMenu->addMenu(
"&Registration");
220 regMenu->addAction(templateFile);
221 regMenu->addAction(viewTemplate);
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() ));
228 QMenu *helpMenu = m_stereoTool->menuBar()->addMenu(
"&Help");
229 helpMenu->addAction(showHelpAct);
244 action->setIcon( QPixmap(
toolIconDir() +
"/3d-glasses-icon.png") );
245 action->setToolTip(
"Stereo");
246 action->setWhatsThis(
"<strong>Functionality:</strong> "
248 "<li>Calculate elevation at a single point by creating a "
249 "control point between the image pair. "
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>");
275 QLabel *boxLabel =
new QLabel(
"Local Radius:");
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");
282 "<b>Function: </b>Source for the local radius used for elevation "
284 m_radiusBox->setWhatsThis(text);
285 connect( m_radiusBox, SIGNAL( activated(
int) ),
286 this, SLOT( updateRadiusLineEdit() ));
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\"");
296 "<b>Function: </b>Custom local radius used to calculate elevations. "
297 "This can be changed by selecting \"Custom Radius\" in the box to "
299 m_radiusLineEdit->setWhatsThis(text);
302 connect( m_radiusLineEdit, SIGNAL( editingFinished() ),
303 this, SLOT( userBaseRadius() ));
305 m_radiusLineEdit->setEnabled(
false);
307 QLabel *radiusUnit =
new QLabel(
"Meters");
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() ));
315 QHBoxLayout *layout =
new QHBoxLayout;
316 layout->setMargin(0);
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);
333 void StereoTool::activateTool() {
343 qobject_cast<QWidget *>( parent() ) );
354 void StereoTool::warningDialog() {
359 QVBoxLayout *mainLayout =
new QVBoxLayout;
360 warningDialog->setLayout(mainLayout);
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);
373 QPushButton *okButton =
new QPushButton(
"OK");
374 mainLayout->addStretch();
375 mainLayout->addWidget(okButton);
376 connect( okButton, SIGNAL( clicked() ), warningDialog, SLOT( accept() ));
378 if ( warningDialog->exec() ) {
379 if ( showWarning->isChecked() ) m_showWarning =
false;
388 void StereoTool::showHelp() {
391 helpDialog->setWindowTitle(
"Stereo Tool Help");
393 QVBoxLayout *mainLayout =
new QVBoxLayout;
394 helpDialog->setLayout(mainLayout);
396 QLabel *stereoTitle =
new QLabel(
"<h2>Stereo Tool</h2>");
397 mainLayout->addWidget(stereoTitle);
399 QLabel *stereoSubtitle =
new QLabel(
"A tool for calculating point elevations "
400 "and elevation profiles using stereo pairs "
402 stereoSubtitle->setWordWrap(
true);
403 mainLayout->addWidget(stereoSubtitle);
405 QTabWidget *tabArea =
new QTabWidget;
406 tabArea->setDocumentMode(
true);
407 mainLayout->addWidget(tabArea);
410 QScrollArea *overviewTab =
new QScrollArea;
411 overviewTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
412 overviewTab->setWidgetResizable(
true);
414 QVBoxLayout *overviewLayout =
new QVBoxLayout;
415 overviewContainer->setLayout(overviewLayout);
417 QLabel *purposeTitle =
new QLabel(
"<h2>Purpose</h2>");
418 overviewLayout->addWidget(purposeTitle);
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);
430 QLabel *warningsTitle =
new QLabel(
"<h2>Warnings</h2>");
431 overviewLayout->addWidget(warningsTitle);
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);
440 overviewTab->setWidget(overviewContainer);
443 QScrollArea *quickTab =
new QScrollArea;
444 quickTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
445 quickTab->setWidgetResizable(
true);
447 QVBoxLayout *quickLayout =
new QVBoxLayout;
448 quickContainer->setLayout(quickLayout);
450 QLabel *quickTitle =
new QLabel(
"<h2>Quick Start</h2>");
451 quickLayout->addWidget(quickTitle);
453 QLabel *quickSubTitle =
new QLabel(
"<h3>Preparation:</h3>");
454 quickLayout->addWidget(quickSubTitle);
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);
462 QLabel *quickFunctionTitle =
new QLabel(
"<h3>Cube Viewport Functions:</h3>");
463 quickLayout->addWidget(quickFunctionTitle);
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);
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);
494 quickTab->setWidget(quickContainer);
497 QScrollArea *controlPointTab =
new QScrollArea;
498 controlPointTab->setWidgetResizable(
true);
499 controlPointTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
501 QVBoxLayout *controlPointLayout =
new QVBoxLayout;
502 controlPointContainer->setLayout(controlPointLayout);
504 QLabel *controlPointTitle =
new QLabel(
"<h2>Control Point Editing</h2>");
505 controlPointLayout->addWidget(controlPointTitle);
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);
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);
526 QLabel *controlPointEditing =
new QLabel(
527 "<h4>Changing Measure Locations</h4>"
528 "<p>The measure location can be adjusted by:"
530 "<li>Move the cursor location under the crosshair by clicking the left mouse "
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>"
535 "<h4>Other Point Editor Functions</h4>"
536 "<p>Along the right border of the window:</p>"
538 "<li><strong>Geom:</strong> Geometrically match the right view to the left"
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"
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"
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);
564 controlPointTab->setWidget(controlPointContainer);
568 tabArea->addTab(overviewTab,
"&Overview");
569 tabArea->addTab(quickTab,
"&Quick Start");
570 tabArea->addTab(controlPointTab,
"&Control Point Editing");
572 QHBoxLayout *buttonsLayout =
new QHBoxLayout;
574 buttonsLayout->addStretch();
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);
583 mainLayout->addLayout(buttonsLayout);
592 void StereoTool::userBaseRadius() {
595 m_baseRadius = Distance(m_radiusLineEdit->text().toDouble(),
600 if (m_stereoTool->isVisible() && m_editPoint != NULL) {
601 calculateElevation();
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);
617 void StereoTool::updateRadiusLineEdit() {
620 if ( m_radiusBox->currentText() ==
"Ellipsoid Equitorial Radius" ) {
621 if ( m_targetRadius.
isValid() ) {
622 m_radiusLineEdit->setText( QString::number( m_targetRadius.
meters(),
'f',
624 m_baseRadius = m_targetRadius;
627 m_radiusLineEdit->setText(
"");
629 m_radiusLineEdit->setReadOnly(
true);
630 m_radiusLineEdit->setEnabled(
false);
632 else if ( m_radiusBox->currentText() ==
"DEM Radius" ) {
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);
642 m_radiusLineEdit->setReadOnly(
true);
643 m_radiusLineEdit->setEnabled(
false);
647 m_radiusLineEdit->setText(
"");
648 m_radiusLineEdit->setReadOnly(
true);
649 m_radiusLineEdit->setEnabled(
false);
653 m_radiusLineEdit->setReadOnly(
false);
654 m_radiusLineEdit->setEnabled(
true);
658 if ( m_stereoTool->isVisible() && m_editPoint != NULL ) {
659 calculateElevation();
665 void StereoTool::setupFiles() {
675 m_linkedViewports.clear();
681 if ( m_linkedViewports.size() < 2 ) {
682 IString message =
"Two cube viewports containing a stereo pair "
683 "need to be linked.";
686 if ( m_linkedViewports.size() > 2 ) {
687 IString message =
"Only two cube viewports containing a stereo pair "
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 ) {
705 if ( m_controlNet->GetTarget() !=
706 m_linkedViewports.at(0)->cube()->camera()->target()->name() ) {
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,
716 if (response == QMessageBox::Yes) {
719 m_stereoTool->setShown(
false);
721 m_controlNet =
new ControlNet();
722 m_controlNet->SetTarget(
723 m_linkedViewports.at(0)->cube()->camera()->target()->name() );
724 m_serialNumberList =
new SerialNumberList(
false);
728 m_controlNet =
new ControlNet();
729 m_controlNet->SetTarget(
730 m_linkedViewports.at(0)->cube()->camera()->target()->name() );
731 m_serialNumberList =
new SerialNumberList(
false);
738 setFiles( m_linkedViewports.at(0)->cube(), m_linkedViewports.at(1)->cube() );
754 m_stereoTool->setShown(
false);
779 m_leftCube = leftCube;
780 m_rightCube = rightCube;
785 m_leftCubeLabel->setText(leftName);
786 m_rightCubeLabel->setText(rightName);
796 m_serialNumberList->
add( m_rightCube->
fileName() );
799 vector<Distance> targetRadius = m_controlNet->GetTargetRadii();
800 m_targetRadius =
Distance(targetRadius[0]);
802 if ( !m_targetRadius.
isValid() ) {
803 QString message =
"Could not determine target radius.";
804 QMessageBox::critical(m_stereoTool,
"Error",message);
806 updateRadiusLineEdit();
809 updateRadiusLineEdit();
816 QString message =
"Cannot initialize universal ground map for " +
819 QMessageBox::critical(m_stereoTool,
"Error", message);
826 QString message =
"Cannot initialize universal ground map for" +
829 QMessageBox::critical(m_stereoTool,
"Error", message);
844 double samp = m_editPoint->
GetMeasure(Left)->GetSample();
845 double line = m_editPoint->
GetMeasure(Left)->GetLine();
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',
864 QMessageBox::critical(m_stereoTool,
"Error", message);
867 calculateElevation();
868 emit editPointChanged();
879 rubberBandTool()->
enable(RubberBandTool::LineMode);
880 rubberBandTool()->enablePoints();
881 rubberBandTool()->enableAllClicks();
887 void StereoTool::rubberBandComplete() {
894 catch (IException &e) {
895 QString message = e.toString();
896 QMessageBox::critical(m_stereoTool,
"Error setting stereo pair", message);
897 rubberBandTool()->
clear();
905 QString file = cvp->cube()->fileName();
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);
917 if ( rubberBandTool()->figureIsPoint() ) {
919 cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
920 rubberBandTool()->vertices()[0].ry(),
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);
932 point = m_controlNet->FindClosest(sn, samp, line);
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);
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);
952 ControlPoint *point =
953 m_controlNet->FindClosest(sn, samp, line);
956 QString message =
"No points exist for deleting. Create points ";
957 message +=
"using the right mouse button.";
958 QMessageBox::information(m_stereoTool,
"Warning", message);
963 else if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
965 if (cvp->cube() == m_leftCube) {
978 catch (IException &e) {
979 QString message =
"Cannot create control point.\n\n";
980 message += e.toString();
981 QMessageBox::critical(m_stereoTool,
"Error", message);
983 rubberBandTool()->
clear();
993 if ( rubberBandTool()->mouseButton() & Qt::RightButton ) {
995 cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
996 rubberBandTool()->vertices()[0].ry(),
999 m_startPoint = m_controlNet->FindClosest(sn, samp, line);
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();
1012 cvp->viewportToCube( rubberBandTool()->vertices()[1].rx(),
1013 rubberBandTool()->vertices()[1].ry(),
1016 m_endPoint = m_controlNet->FindClosest(sn, samp, line);
1017 if ( m_startPoint->
GetId() == m_endPoint->
GetId() ) {
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;
1031 rubberBandTool()->
clear();
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();
1057 void StereoTool::clearProfile() {
1058 m_startPoint = NULL;
1060 rubberBandTool()->
clear();
1061 delete m_profileDialog;
1062 m_profileDialog = NULL;
1067 void StereoTool::createStartPoint() {
1074 cvp->viewportToCube( rubberBandTool()->vertices()[0].rx(),
1075 rubberBandTool()->vertices()[0].ry(),
1077 if ( cvp->cube() == m_leftCube ) {
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();
1099 m_startPoint = m_editPoint;
1104 void StereoTool::createEndPoint() {
1111 cvp->viewportToCube( rubberBandTool()->vertices()[1].rx(),
1112 rubberBandTool()->vertices()[1].ry(),
1114 if ( cvp->cube() == m_leftCube ) {
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();
1137 m_endPoint = m_editPoint;
1159 double leftSamp = 0, leftLine = 0;
1160 double rightSamp = 0, rightLine = 0;
1164 leftSamp = m_leftGM->
Sample();
1165 leftLine = m_leftGM->
Line();
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, " +
1184 IString message =
"Point does not exist on cube, " +
1194 IString message =
"Point does not exist on cube, " +
1206 bool goodId =
false;
1209 QString
id = QInputDialog::getText(m_stereoTool,
1210 "Point ID",
"Enter Point ID:",
1211 QLineEdit::Normal, lastPtIdValue,
1218 if ( ok &&
id.isEmpty() ) {
1220 QString message =
"You must enter a point Id.";
1221 QMessageBox::warning(m_stereoTool,
"Warning", message);
1226 if ( m_controlNet->GetNumPoints() > 0 &&
1227 m_controlNet->ContainsPoint(newPoint->
GetId() ) ) {
1228 QString message =
"A ControlPoint with Point Id = [" +
1230 "] already exists. Re-enter unique Point Id.";
1231 QMessageBox::warning(m_stereoTool,
"Unique Point Id", message);
1252 newPoint->
Add(mLeft);
1260 newPoint->
Add(mRight);
1263 m_controlNet->AddPoint(newPoint);
1265 m_editPoint = m_controlNet->GetPoint( (QString) newPoint->
GetId() );
1268 m_stereoTool->setShown(
true);
1269 m_stereoTool->raise();
1271 emit editPointChanged();
1288 m_editPoint = point;
1291 emit editPointChanged();
1295 m_controlNet->DeletePoint( m_editPoint->
GetId() );
1296 m_stereoTool->setShown(
false);
1299 emit editPointChanged();
1311 m_editPoint = point;
1313 m_stereoTool->setShown(
true);
1314 m_stereoTool->raise();
1315 emit editPointChanged();
1328 m_editPoint->
GetId() );
1330 m_rightCube, m_editPoint->
GetId() );
1333 QString ptId =
"Point ID: " + m_editPoint->
GetId();
1334 m_ptIdValue->setText(ptId);
1342 QString serialNumber) {
1348 m_startPoint->
GetMeasure(serialNumber)->GetLine(),
1351 m_endPoint->
GetMeasure(serialNumber)->GetLine(),
1353 painter->setPen(Qt::green);
1354 painter->drawLine(x1, y1, x2, y2);
1372 if ( m_controlNet == NULL || m_controlNet->GetNumPoints() == 0 )
1378 if ( !m_controlNet->GetCubeSerials().contains(
1379 serialNumber) )
return;
1388 m_controlNet->GetMeasuresInCube(serialNumber);
1390 for (
int i = 0; i < measures.count(); i++) {
1393 double samp = m->GetSample();
1394 double line = m->GetLine();
1398 if ( m->Parent()->IsIgnored() ) {
1399 painter->setPen( QColor(255, 255, 0) );
1402 else if ( m->IsIgnored() ) {
1403 painter->setPen( QColor(255, 255, 0) );
1407 painter->setPen(Qt::magenta);
1410 painter->setPen(Qt::green);
1413 painter->drawLine(x - 5, y, x + 5, y);
1414 painter->drawLine(x, y - 5, x, y + 5);
1418 if ( m_editPoint != NULL ) {
1422 double samp = (*m_editPoint)[serialNumber]->GetSample();
1423 double line = (*m_editPoint)[serialNumber]->GetLine();
1427 QBrush brush(Qt::red);
1431 painter->setPen(pen);
1432 painter->drawLine(x - 5, y, x + 5, y);
1433 painter->drawLine(x, y - 5, x, y + 5);
1453 vp->viewport()->update();
1459 void StereoTool::calculateElevation() {
1460 calculateElevation(m_editPoint);
1471 double elevation=0., elevationError=0.;
1477 if ( m_radiusBox->currentText() ==
"DEM Radius" ) {
1479 leftCamera->
SetImage( (*point)[Left]->GetSample(),
1480 (*point)[Left]->GetLine() );
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;
1491 leftCamera->
SetImage( (*point)[Left]->GetSample(),
1492 (*point)[Left]->GetLine() );
1495 rightCamera->
SetImage( (*point)[Right]->GetSample(),
1496 (*point)[Right]->GetLine() );
1498 double radius, lat, lon, sepang;
1499 if ( Stereo::elevation( *leftCamera, *rightCamera, radius, lat, lon, sepang,
1500 elevationError ) ) {
1501 elevation = radius - m_baseRadius.
meters();
1527 QString filename = QFileDialog::getOpenFileName( m_stereoTool,
1528 "Select a registration template",
".",
1529 "Registration template files (*.def *.pvl);;All files (*)" );
1531 if ( filename.isEmpty() )
1553 Pvl templatePvl( m_pointEditor->templateFileName() );
1557 registrationDialog.setWindowTitle(
"View or Edit Template File: "
1558 + templatePvl.fileName() );
1559 registrationDialog.resize(550, 360);
1560 registrationDialog.exec();
1564 QMessageBox::warning(m_stereoTool,
"Error", message);
1576 QString fn = QFileDialog::getSaveFileName( m_stereoTool,
1577 "Choose filename to save under",
1579 "CSV Files (*.csv)" );
1583 if( !fn.isEmpty() ) {
1584 if( !fn.endsWith(
".csv") ) {
1585 filename = fn +
".csv";
1596 m_currentFile.setFileName(filename);
1598 m_save->setEnabled(
true);
1604 void StereoTool::saveElevations() {
1606 if ( m_currentFile.fileName().isEmpty() )
return;
1608 bool success = m_currentFile.open(QIODevice::WriteOnly);
1610 QMessageBox::critical(m_stereoTool,
"Error",
1611 "Cannot open file, please check permissions");
1612 m_currentFile.setFileName(
"");
1613 m_save->setDisabled(
true);
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;
1623 QString leftFile = FileName( m_leftCube->
fileName() ).name();
1624 QString rightFile = FileName( m_rightCube->
fileName() ).name();
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 ) +
1634 QString::number( p.GetMeasure(Left)->GetFocalPlaneMeasuredX(),
'f',
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() ) +
"," +
1641 QString::number( p.GetMeasure(Right)->GetSample() ) +
"," +
1642 QString::number( p.GetMeasure(Right)->GetLine() );
1643 text << data << endl;
1645 m_currentFile.close();
1651 void StereoTool::clearNetData() {
1653 delete m_controlNet;
1654 m_controlNet = NULL;
1655 delete m_serialNumberList;
1656 m_serialNumberList = NULL;
1662 void StereoTool::profile() {
1670 if (m_profileDialog) {
1671 delete m_profileDialog;
1672 m_profileDialog = NULL;
1678 QPointF leftStart( (*m_startPoint)[Left]->GetSample(),
1679 (*m_startPoint)[Left]->GetLine() );
1680 QPointF leftEnd( (*m_endPoint)[Left]->GetSample(),
1681 (*m_endPoint)[Left]->GetLine() );
1683 QPointF rightStart( (*m_startPoint)[Right]->GetSample(),
1684 (*m_startPoint)[Right]->GetLine() );
1685 QPointF rightEnd( (*m_endPoint)[Right]->GetSample(),
1686 (*m_endPoint)[Right]->GetLine() );
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) );
1699 rubberBandVertices.push_back(rubberBand1);
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) );
1709 rubberBandVertices.push_back(rubberBand2);
1712 QLineF leftProfile(leftStart,leftEnd);
1713 QLineF rightProfile(rightStart,rightEnd);
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;
1726 longProfile = rightProfile;
1727 longCube = m_rightCube;
1728 shortProfile = leftProfile;
1729 shortCube = m_leftCube;
1732 QVector<QPointF> profileData;
1733 double elevation = 0.;
1734 double elevationError = 0.;
1736 Pvl regDef = m_pointEditor->templateFileName();
1739 int failureCount = 0;
1740 QApplication::setOverrideCursor(Qt::WaitCursor);
1742 for (
int i = 0; i <= (int) shortProfile.length(); i++) {
1743 double shortSamp=0, shortLine=0, longSamp=0, longLine=0;
1745 shortSamp = shortProfile.pointAt( 1/shortProfile.length() * i ).x();
1746 shortLine = shortProfile.pointAt( 1/shortProfile.length() * i ).y();
1748 longSamp = longProfile.pointAt( 1/shortProfile.length() * i ).x();
1749 longLine = longProfile.pointAt( 1/shortProfile.length() * i ).y();
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 );
1758 if ( ar->Success() ) {
1759 longSamp = ar->CubeSample();
1760 longLine = ar->CubeLine();
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;
1778 shortCube->camera()->IgnoreElevationModel(
true);
1779 longCube->camera()->IgnoreElevationModel(
true);
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) );
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();
1807 QApplication::restoreOverrideCursor();
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);
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);
1829 plotWindow->setAxisLabel(0,
"Elevation (meters)");
1833 plotCurve->setData(
new QwtPointSeriesData(profileData) );
1834 plotCurve->setTitle(
"Elevations (Meters)");
1835 plotCurve->setPen( QPen(Qt::white) );
1836 plotCurve->setColor(Qt::white);
1843 plotCurve->setSource(m_linkedViewports, rubberBandVertices, bands);
1844 plotWindow->add(plotCurve);
1846 delete m_profileDialog;
1847 m_profileDialog = NULL;
1856 void StereoTool::updateLabels() {
1858 QString elevationLabel, elevationErrorLabel;
1859 QString baseRadiiLabel, leftDemRadiiLabel, rightDemRadiiLabel;
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 );
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);
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);
1887 elevationLabel =
"Elevation: ";
1888 elevationErrorLabel =
"Elevation Error: ";
1889 baseRadiiLabel =
"Local Radii: ";
1890 leftDemRadiiLabel =
"Left DEM Radii: ";
1891 rightDemRadiiLabel =
"Right DEM Radii: ";
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);
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();
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);