Isis 3 Programmer Reference
ControlPointEditWidget.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include "ControlPointEditWidget.h"
10
11#include <iomanip>
12#include <sstream>
13#include <vector>
14
15#include <QAction>
16#include <QCheckBox>
17#include <QComboBox>
18#include <QFileDialog>
19#include <QFileInfo>
20#include <QFormLayout>
21#include <QGroupBox>
22#include <QHBoxLayout>
23#include <QLabel>
24#include <QMainWindow>
25#include <QMessageBox>
26#include <QObject>
27#include <QPushButton>
28#include <QScrollBar>
29#include <QShortcut>
30#include <QSplitter>
31#include <QTableWidget>
32#include <QTextEdit>
33#include <QVBoxLayout>
34
35#include "Application.h"
36#include "Camera.h"
37#include "Control.h"
38#include "ControlMeasureEditWidget.h"
39#include "ControlMeasure.h"
40#include "ControlMeasureLogData.h"
41#include "ControlNet.h"
42#include "ControlPoint.h"
43#include "DeleteControlPointDialog.h"
44#include "Directory.h"
45#include "FileName.h"
46#include "IException.h"
47#include "Latitude.h"
48#include "Longitude.h"
49#include "MainWindow.h"
50#include "MdiCubeViewport.h"
51#include "NewControlPointDialog.h"
52#include "NewGroundSourceLocationDialog.h"
53#include "Project.h"
54#include "Pvl.h"
55#include "PvlEditDialog.h"
56#include "SerialNumber.h"
57#include "SerialNumberList.h"
58#include "Shape.h"
59#include "ShapeList.h"
60#include "SpecialPixel.h"
61#include "Table.h"
62#include "TemplateList.h"
63#include "ToolPad.h"
64#include "UniversalGroundMap.h"
65#include "ViewportMainWindow.h"
66#include "Workspace.h"
67
68using namespace std;
69
70namespace Isis {
79 bool addMeasures) : QWidget(parent) {
80
81 m_directory = directory;
82 m_addMeasuresButton = addMeasures;
83 m_cnetModified = false;
84 m_templateModified = false;
85 m_serialNumberList = NULL;
86 m_editPoint = NULL;
87
90 m_demOpen = false;
91
92 m_parent = parent;
93
95
96 connect(this, SIGNAL(newControlNetwork(ControlNet *)),
97 m_measureEditor, SIGNAL(newControlNetwork(ControlNet *)));
98
99 connect(m_directory->project(), SIGNAL(templatesAdded(TemplateList *)),
100 this, SLOT(addTemplates(TemplateList *)));
101 }
102
103
104 ControlPointEditWidget::~ControlPointEditWidget () {
105
106 }
107
108
109 QString ControlPointEditWidget::editPointId() {
110
111 QString result = "";
112 if (m_editPoint) {
113 result = m_editPoint->GetId();
114 }
115 return result;
116 }
117
118
119 ControlPoint *ControlPointEditWidget::editPoint() {
120
121 ControlPoint *result = NULL;
122 if (m_editPoint) {
123 result = m_editPoint;
124 }
125 return result;
126 }
127
128
154 void ControlPointEditWidget::createPointEditor(QWidget *parent, bool addMeasures) {
155
156 setWindowTitle("Control Point Editor");
157 setObjectName("ControlPointEditWidget");
158 connect(this, SIGNAL(destroyed(QObject *)), this, SLOT(clearEditPoint()));
159
161
162 // create m_measureEditor first since we need to get its templateFileName
163 // later
164 m_measureEditor = new ControlMeasureEditWidget(parent, true, true);
165
166 // TODO Does this need to be moved to ControlNetEditMainWindow???
167 connect(this, SIGNAL(newControlNetwork(ControlNet *)),
168 m_measureEditor, SIGNAL(newControlNetwork(ControlNet *)));
169
170
171 connect(this, SIGNAL(stretchChipViewport(Stretch *, CubeViewport *)),
172 m_measureEditor, SIGNAL(stretchChipViewport(Stretch *, CubeViewport *)));
173 connect(m_measureEditor, SIGNAL(measureSaved()), this, SLOT(measureSaved()));
174 connect(this, SIGNAL(cnetModified()), this, SLOT(colorizeSaveNetButton()));
175
176 QPushButton *addMeasure = NULL;
178 addMeasure = new QPushButton("Add Measure(s) to Point");
179 addMeasure->setToolTip("Add a new measure to the edit control point.");
180 addMeasure->setWhatsThis("This allows a new control measure to be added "
181 "to the currently edited control point. A selection "
182 "box with all cubes from the input list will be "
183 "displayed with those that intersect with the "
184 "control point highlighted.");
185 //TODO addMeasure() slot is not implemented ???
186 connect(addMeasure, SIGNAL(clicked()), this, SLOT(addMeasure()));
187 }
188
189 m_reloadPoint = new QPushButton("Reload Point");
190 m_reloadPoint->setToolTip("Reload the control point.");
191 m_reloadPoint->setWhatsThis("Reload the measures for the control point"
192 " in the Chip Viewports to its saved values. ");
193 connect(m_reloadPoint, SIGNAL(clicked()), this, SLOT(reloadPoint()));
194
195 m_savePoint = new QPushButton ("Save Point");
196 m_savePoint->setShortcut(Qt::Key_P);
197 m_savePoint->setToolTip("Save the edit control point to the control network. "
198 "<strong>Shortcut: P</strong>");
199 m_savePoint->setWhatsThis("Save the edit control point to the control "
200 "network which is loaded into memory in its entirety. "
201 "When a control point is selected for editing, "
202 "a copy of the point is made so that the original control "
203 "point remains in the network.");
205 connect (m_savePoint, SIGNAL(clicked()), this, SLOT(savePoint()));
206
207 m_saveNet = new QPushButton ("Save Control Net");
208 m_saveNet->setShortcut(Qt::Key_S);
209 m_saveNet->setToolTip("Save current control network. "
210 "<strong>Shortcut: S</strong>");
211 m_savePoint->setWhatsThis("Save the control network.");
212// m_saveDefaultPalette = m_savePoint->palette();
213// This slot is needed because we cannot directly emit a signal with a ControlNet
214// argument after the "Save Net" push button is selected since the parameter list must match.
215// The saveNet slot will simply emit a signal with the ControlNet as the argument.
216 connect (m_saveNet, SIGNAL(clicked()), this, SLOT(saveNet()));
217
218 QHBoxLayout * saveMeasureLayout = new QHBoxLayout;
220 saveMeasureLayout->addWidget(addMeasure);
221 }
222
223 saveMeasureLayout->addWidget(m_reloadPoint);
224 saveMeasureLayout->addWidget(m_savePoint);
225 saveMeasureLayout->addWidget(m_saveNet);
226 saveMeasureLayout->insertStretch(-1);
227
228 m_cnetFileNameLabel = new QLabel("Control Network: " + m_cnetFileName);
229
230 // Create a combobox to allow user to select either the default registration file or one of the
231 // imported registration files.
233 m_templateComboBox->setToolTip("Choose a template file");
234 m_templateComboBox->setWhatsThis("FileName of the sub-pixel "
235 "registration template. Refer to $ISISROOT/doc/documents/"
236 "PatternMatch/PatternMatch.html for a description of the "
237 "contents of this file.");
238 m_templateComboBox->addItem(m_measureEditor->templateFileName());
239 QList <TemplateList *> regTemplates = m_directory->project()->regTemplates();
240 foreach(TemplateList *templateList, regTemplates) {
241 foreach(Template *templateFile, *templateList){
242 m_templateComboBox->addItem(templateFile->importName()
243 + "/" + FileName(templateFile->fileName()).name());
244 }
245 }
246 QFormLayout *templateFileLayout = new QFormLayout();
247 templateFileLayout->addRow("Template File:", m_templateComboBox);
248
249 // Set-up connections to give registration combobox functionality
250 connect(m_templateComboBox, SIGNAL(activated(QString)),
251 this, SLOT(setTemplateFile(QString)));
252 connect(m_measureEditor, SIGNAL(setTemplateFailed(QString)),
253 this, SLOT(resetTemplateComboBox(QString)));
254
255 QVBoxLayout * centralLayout = new QVBoxLayout;
256
257 centralLayout->addWidget(m_cnetFileNameLabel);
258 centralLayout->addLayout(templateFileLayout);
259 centralLayout->addWidget(createTopSplitter());
260 centralLayout->addStretch();
261 centralLayout->addWidget(m_measureEditor);
262 centralLayout->addLayout(saveMeasureLayout);
263
264 QWidget *centralWidget = new QWidget;
265 centralWidget->setLayout(centralLayout);
266
267 QScrollArea *scrollArea = new QScrollArea();
268 scrollArea->setObjectName("ControlPointEditWidgetScroll");
269 scrollArea->setWidget(centralWidget);
270 scrollArea->setWidgetResizable(true);
271 centralWidget->adjustSize();
272
273 QHBoxLayout *mainLayout = new QHBoxLayout;
274 mainLayout->addWidget(scrollArea);
275 setLayout(mainLayout);
276
277// connect(this, SIGNAL(controlPointChanged()), this, SLOT(paintAllViewports()));
278
279// readSettings();
280 }
281
282
289
290 QHBoxLayout * measureLayout = new QHBoxLayout;
291 measureLayout->addWidget(createLeftMeasureGroupBox());
292 measureLayout->addWidget(createRightMeasureGroupBox());
293
294 QVBoxLayout * groupBoxesLayout = new QVBoxLayout;
295 groupBoxesLayout->addWidget(createControlPointGroupBox());
296 groupBoxesLayout->addStretch();
297 groupBoxesLayout->addLayout(measureLayout);
298
299 QWidget * groupBoxesWidget = new QWidget;
300 groupBoxesWidget->setLayout(groupBoxesLayout);
301
303
304 QSplitter * topSplitter = new QSplitter;
305 topSplitter->addWidget(groupBoxesWidget);
306 topSplitter->addWidget(m_templateEditorWidget);
307// topSplitter->setStretchFactor(0, 4);
308// topSplitter->setStretchFactor(1, 3);
309
311
312 return topSplitter;
313 }
314
315
322
323 // create left vertical layout
324 m_ptIdValue = new QLabel;
325
326 m_numMeasures = new QLabel;
327
328 m_aprioriLatitude = new QLabel;
329 m_aprioriLongitude = new QLabel;
330 m_aprioriRadius = new QLabel;
331
332 // create right vertical layout's top layout
333 m_lockPoint = new QCheckBox("Edit Lock Point");
334 connect(m_lockPoint, SIGNAL(clicked(bool)), this, SLOT(setLockPoint(bool)));
335 m_ignorePoint = new QCheckBox("Ignore Point");
336 connect(m_ignorePoint, SIGNAL(clicked(bool)),
337 this, SLOT(setIgnorePoint(bool)));
338 connect(this, SIGNAL(ignorePointChanged()), m_ignorePoint, SLOT(toggle()));
339
341 for (int i=0; i<ControlPoint::PointTypeCount; i++) {
344 }
345 QFormLayout *pointTypeLayout = new QFormLayout;
346 pointTypeLayout->addRow("PointType:", m_pointTypeCombo);
347 connect(m_pointTypeCombo, SIGNAL(activated(int)),
348 this, SLOT(setPointType(int)));
349
352 connect(m_groundSourceCombo, SIGNAL(currentIndexChanged(int)),
353 this, SLOT(groundSourceFileSelectionChanged(int)));
354 QFormLayout *groundSourceLayout = new QFormLayout;
355 groundSourceLayout->addRow("Ground Source:", m_groundSourceCombo);
356 QFormLayout *radiusSourceLayout = new QFormLayout;
357 radiusSourceLayout->addRow("Radius Source:", m_radiusSourceCombo);
358
359 QVBoxLayout * mainLayout = new QVBoxLayout;
360 mainLayout->addWidget(m_ptIdValue);
361 mainLayout->addWidget(m_numMeasures);
362 mainLayout->addLayout(groundSourceLayout);
363 mainLayout->addLayout(radiusSourceLayout);
364 mainLayout->addWidget(m_aprioriLatitude);
365 mainLayout->addWidget(m_aprioriLongitude);
366 mainLayout->addWidget(m_aprioriRadius);
367 mainLayout->addWidget(m_lockPoint);
368 mainLayout->addWidget(m_ignorePoint);
369 mainLayout->addLayout(pointTypeLayout);
370
371 // create the groupbox
372 QGroupBox * groupBox = new QGroupBox("Control Point");
373 groupBox->setLayout(mainLayout);
374
375 return groupBox;
376 }
377
378
385
387 m_leftCombo->view()->installEventFilter(this);
388 m_leftCombo->setToolTip("Choose left control measure");
389 m_leftCombo->setWhatsThis("Choose left control measure identified by "
390 "cube filename.");
391 connect(m_leftCombo, SIGNAL(activated(int)),
392 this, SLOT(selectLeftMeasure(int)));
393 m_lockLeftMeasure = new QCheckBox("Edit Lock Measure");
394 connect(m_lockLeftMeasure, SIGNAL(clicked(bool)),
395 this, SLOT(setLockLeftMeasure(bool)));
396 m_ignoreLeftMeasure = new QCheckBox("Ignore Measure");
397 connect(m_ignoreLeftMeasure, SIGNAL(clicked(bool)),
398 this, SLOT(setIgnoreLeftMeasure(bool)));
399 connect(this, SIGNAL(ignoreLeftChanged()),
400 m_ignoreLeftMeasure, SLOT(toggle()));
401 m_leftReference = new QLabel();
402 m_leftMeasureType = new QLabel();
403 QVBoxLayout * leftLayout = new QVBoxLayout;
404 leftLayout->addWidget(m_leftCombo);
405 leftLayout->addWidget(m_lockLeftMeasure);
406 leftLayout->addWidget(m_ignoreLeftMeasure);
407 leftLayout->addWidget(m_leftReference);
408 leftLayout->addWidget(m_leftMeasureType);
409
410 QGroupBox * leftGroupBox = new QGroupBox("Left Measure");
411 leftGroupBox->setLayout(leftLayout);
412
413 return leftGroupBox;
414 }
415
416
427
428 // create widgets for the right groupbox
430 m_model = new QStandardItemModel();
431 m_rightCombo->setModel(m_model);
432 m_rightCombo->view()->installEventFilter(this);
433 m_rightCombo->setToolTip("Choose right control measure. "
434 "<strong>Shortcuts: PageUp/PageDown</strong>");
435 m_rightCombo->setWhatsThis("Choose right control measure identified by "
436 "cube filename. "
437 "Note: PageUp selects previous measure; "
438 "PageDown selects next meausure.");
439
440 m_rightCombo->view()->setSelectionMode(QAbstractItemView::SingleSelection);
441 m_rightCombo->view()->setDragEnabled(true);
442 m_rightCombo->view()->setAcceptDrops(true);
443 m_rightCombo->view()->setDropIndicatorShown(true);
444 m_rightCombo->view()->setDragDropMode(QAbstractItemView::InternalMove);
445
446 // Attach shortcuts to this widget for selecting right measures
447 // Note: Qt handles this memory for us since ControlPointEditWidget is the parent of these shortcuts
448 QShortcut *nextMeasure = new QShortcut(Qt::Key_PageDown, this);
449 connect(nextMeasure, SIGNAL(activated()), this, SLOT(nextRightMeasure()));
450 QShortcut *prevMeasure = new QShortcut(Qt::Key_PageUp, this);
451 connect(prevMeasure, SIGNAL(activated()), this, SLOT(previousRightMeasure()));
452
453 connect(m_rightCombo, SIGNAL(activated(int)),
454 this, SLOT(selectRightMeasure(int)));
455 m_lockRightMeasure = new QCheckBox("Edit Lock Measure");
456 connect(m_lockRightMeasure, SIGNAL(clicked(bool)),
457 this, SLOT(setLockRightMeasure(bool)));
458 m_ignoreRightMeasure = new QCheckBox("Ignore Measure");
459 connect(m_ignoreRightMeasure, SIGNAL(clicked(bool)),
460 this, SLOT(setIgnoreRightMeasure(bool)));
461 connect(this, SIGNAL(ignoreRightChanged()),
462 m_ignoreRightMeasure, SLOT(toggle()));
463 m_rightReference = new QLabel();
464 m_rightMeasureType = new QLabel();
465
466 // create right groupbox
467 QVBoxLayout * rightLayout = new QVBoxLayout;
468 rightLayout->addWidget(m_rightCombo);
469 rightLayout->addWidget(m_lockRightMeasure);
470 rightLayout->addWidget(m_ignoreRightMeasure);
471 rightLayout->addWidget(m_rightReference);
472 rightLayout->addWidget(m_rightMeasureType);
473
474 QGroupBox * rightGroupBox = new QGroupBox("Right Measure");
475 rightGroupBox->setLayout(rightLayout);
476
477 return rightGroupBox;
478 }
479
480
485
486 QToolBar *toolBar = new QToolBar("Template Editor ToolBar");
487
488 toolBar->addAction(m_openTemplateFile);
489 toolBar->addSeparator();
490 toolBar->addAction(m_saveTemplateFile);
491 toolBar->addAction(m_saveTemplateFileAs);
492
493 m_templateEditor = new QTextEdit;
494 connect(m_templateEditor, SIGNAL(textChanged()), this,
495 SLOT(setTemplateModified()));
496
497 QVBoxLayout *mainLayout = new QVBoxLayout;
498 mainLayout->addWidget(toolBar);
499 mainLayout->addWidget(m_templateEditor);
500
502 m_templateEditorWidget->setLayout(mainLayout);
503 }
504
505
510
511 m_closePointEditor = new QAction(QIcon(FileName("base/icons/fileclose.png").expanded()),
512 "&Close", this);
513 m_closePointEditor->setToolTip("Close this window");
514 m_closePointEditor->setStatusTip("Close this window");
515 m_closePointEditor->setShortcut(Qt::ALT + Qt::Key_F4);
516 QString whatsThis = "<b>Function:</b> Closes the Match Tool window for this point "
517 "<p><b>Shortcut:</b> Alt+F4 </p>";
518 m_closePointEditor->setWhatsThis(whatsThis);
519 connect(m_closePointEditor, SIGNAL(triggered()), this, SLOT(close()));
520
521 m_showHideTemplateEditor = new QAction(QIcon(FileName("base/icons/view_text.png").expanded()),
522 "&View/edit registration template", this);
523 m_showHideTemplateEditor->setCheckable(true);
524 m_showHideTemplateEditor->setToolTip("View and/or edit the registration template");
525 m_showHideTemplateEditor->setStatusTip("View and/or edit the registration template");
526 whatsThis = "<b>Function:</b> Displays the curent registration template. "
527 "The user may edit and save changes under a chosen filename.";
528 m_showHideTemplateEditor->setWhatsThis(whatsThis);
529 connect(m_showHideTemplateEditor, SIGNAL(triggered()), this,
530 SLOT(showHideTemplateEditor()));
531
532 m_saveChips = new QAction(QIcon(FileName("base/icons/window_new.png").expanded()),
533 "Save registration chips", this);
534 m_saveChips->setToolTip("Save registration chips");
535 m_saveChips->setStatusTip("Save registration chips");
536 whatsThis = "<b>Function:</b> Save registration chips to file. "
537 "Each chip: pattern, search, fit will be saved to a separate file.";
538 m_saveChips->setWhatsThis(whatsThis);
539 connect(m_saveChips, SIGNAL(triggered()), this, SLOT(saveChips()));
540
541 m_openTemplateFile = new QAction(QIcon(FileName("base/icons/fileopen.png").expanded()),
542 "&Open registration template", this);
543 m_openTemplateFile->setToolTip("Set registration template");
544 m_openTemplateFile->setStatusTip("Set registration template");
545 whatsThis = "<b>Function:</b> Allows user to select a new file to set as "
546 "the registration template";
547 m_openTemplateFile->setWhatsThis(whatsThis);
548 connect(m_openTemplateFile, SIGNAL(triggered()), this, SLOT(openTemplateFile()));
549
550 m_saveTemplateFile = new QAction(QIcon(FileName("base/icons/mActionFileSave.png").expanded()),
551 "&Save template file", this);
552 m_saveTemplateFile->setToolTip("Save the template file");
553 m_saveTemplateFile->setStatusTip("Save the template file");
554 m_saveTemplateFile->setWhatsThis("Save the registration template file");
555 connect(m_saveTemplateFile, SIGNAL(triggered()), this,
556 SLOT(saveTemplateFile()));
557
558 m_saveTemplateFileAs = new QAction(QIcon(FileName("base/icons/mActionFileSaveAs.png").expanded()),
559 "&Save template as...", this);
560 m_saveTemplateFileAs->setToolTip("Save the template file as");
561 m_saveTemplateFileAs->setStatusTip("Save the template file as");
562 m_saveTemplateFileAs->setWhatsThis("Save the registration template file as");
563 connect(m_saveTemplateFileAs, SIGNAL(triggered()), this,
564 SLOT(saveTemplateFileAs()));
565 }
566
567
582 void ControlPointEditWidget::setShapesForPoint(double latitude, double longitude) {
583
584 if (latitude == Null || longitude == Null) {
585 // Use current editPoint to get latitude, longitude.
586 // Use apriori surface point to find location on ground source. If
587 // apriori surface point does not exist use reference measure
588 if (m_editPoint->HasAprioriCoordinates()) {
589 SurfacePoint sPt = m_editPoint->GetAprioriSurfacePoint();
590 latitude = sPt.GetLatitude().degrees();
591 longitude = sPt.GetLongitude().degrees();
592 }
593 else {
594 ControlMeasure m = *(m_editPoint->GetRefMeasure());
595 int camIndex = m_serialNumberList->serialNumberIndex(m.GetCubeSerialNumber());
596 Camera *cam;
597 cam = m_controlNet->Camera(camIndex);
598 cam->SetImage(m.GetSample(),m.GetLine());
599 latitude = cam->UniversalLatitude();
600 longitude = cam->UniversalLongitude();
601 }
602 }
603
605 m_projectShapeNames.clear();
606 m_nameToShapeMap.clear();
607
608 // Get all shapes from project, putting shapes that contain the current m_editPoint at the
609 // top of the list.
610 QStringList shapeNamesNoPoint;
611 // Create map between the Shape file name & Shape
612 QList<ShapeList *> shapeLists = m_directory->project()->shapes();
613 foreach (ShapeList *shapeList, shapeLists) {
614 foreach (Shape *shape, *shapeList) {
615 UniversalGroundMap *gmap = new UniversalGroundMap(*(shape->cube()));
616 if (gmap->SetUniversalGround(latitude, longitude)) {
618 }
619 else {
620 shapeNamesNoPoint<<shape->fileName();
621 }
622 m_nameToShapeMap[shape->fileName()] = shape;
623 delete gmap;
624 }
625 }
627 // Add shapes that do not contain point
628 if (shapeNamesNoPoint.count() > 0) {
629 m_projectShapeNames<<shapeNamesNoPoint;
630 }
631 }
632
633
641 m_measureEditor->setLeftMeasure(m_leftMeasure, m_leftCube.data(), m_editPoint->GetId());
642 m_measureEditor->setRightMeasure(m_rightMeasure, m_rightCube.data(), m_editPoint->GetId());
643 }
644
645
652
653 // TODO If network & snList already exists do some error checking
654 // Make copy; we add ground source files to the list, and we don't want to cause problems for
655 // other ipce entities that are using
656// if (m_serialNumberList) {
657// delete m_serialNumberList;
658// m_serialNumberList = NULL;
659// }
660// m_serialNumberList = new SerialNumberList(snList);
661 m_serialNumberList = snList;
662 }
663
664
673 // TODO more error checking
674 m_control = control;
675 m_controlNet = control->controlNet();
676 m_cnetFileName = control->fileName();
677
678 QStringList cnetDirs = m_cnetFileName.split('/');
679 QString strippedCnetFilename = cnetDirs.value(cnetDirs.length() -1);
680 m_cnetFileNameLabel->setText("Control Network: " + strippedCnetFilename);
682 m_cnetFileNameLabel->setWhatsThis(m_cnetFileName);
683 setWindowTitle("Control Point Editor- Control Network File: " + m_cnetFileName);
684
685 emit newControlNetwork(m_controlNet);
686 }
687
688
696
697 if (m_directory->project()->activeControl()) {
698 m_control = m_directory->project()->activeControl();
699 m_controlNet = m_control->controlNet();
700 m_cnetFileName = m_control->fileName();
701
702 m_cnetFileNameLabel->setText("Control Network: " + m_cnetFileName);
703 setWindowTitle("Control Point Editor- Control Network File: " + m_cnetFileName);
704
705 emit newControlNetwork(m_controlNet);
706 }
707 }
708
709
722
724 if (groundMeasure) {
725 m_editPoint->Add(groundMeasure);
726
727 // Add to measure combo boxes
728 QString groundFile = m_serialNumberList->fileName(groundMeasure->GetCubeSerialNumber());
729 QString tempFileName = FileName(groundFile).name();
730
731 m_pointFiles<<groundFile;
732 m_leftCombo->addItem(tempFileName);
733 m_rightCombo->addItem(tempFileName);
734 int rightIndex = m_rightCombo->findText(tempFileName);
735 m_rightCombo->setCurrentIndex(rightIndex);
736 selectRightMeasure(rightIndex);
738 }
739 }
740
741
755
756 ControlMeasure *groundMeasure = NULL;
757
758 // Try to set ground source file information. If unsuccessful, return null ground measure
759 if (!setGroundSourceInfo()) {
760 return groundMeasure;
761 }
762
763 // Use apriori surface point to find location on ground source. If
764 // apriori surface point does not exist use reference measure
765 double lat = 0.;
766 double lon = 0.;
767 if (m_editPoint->HasAprioriCoordinates()) {
768 SurfacePoint sPt = m_editPoint->GetAprioriSurfacePoint();
769 lat = sPt.GetLatitude().degrees();
770 lon = sPt.GetLongitude().degrees();
771 }
772 else {
773 ControlMeasure m = *(m_editPoint->GetRefMeasure());
774 int camIndex = m_serialNumberList->serialNumberIndex(m.GetCubeSerialNumber());
775 Camera *cam;
776 cam = m_controlNet->Camera(camIndex);
777 cam->SetImage(m.GetSample(),m.GetLine());
778 lat = cam->UniversalLatitude();
779 lon = cam->UniversalLongitude();
780 }
781
782 // Try to locate point position on current ground source,
783 if (!m_groundGmap->SetUniversalGround(lat,lon)) {
784 QString message = "This point does not exist on the ground source.\n";
785 message += "Latitude = " + QString::number(lat);
786 message += " Longitude = " + QString::number(lon);
787 message += "\n A ground measure will not be created.";
788 QMessageBox::warning(this, "Warning", message);
789 }
790 else {
791 groundMeasure = new ControlMeasure;
792 groundMeasure->SetCubeSerialNumber(m_groundSN);
793 groundMeasure->SetType(ControlMeasure::Candidate);
794 groundMeasure->SetCoordinate(m_groundGmap->Sample(), m_groundGmap->Line());
795 groundMeasure->SetChooserName("GroundMeasureTemporary");
796 }
797
798 return groundMeasure;
799 }
800
801
812
813 FileName groundFile;
814 ControlPoint::SurfacePointSource::Source groundSourceType =
815 ControlPoint::SurfacePointSource::None;
816
817 bool success = false;
818
819 // No ground source chosen, clear out any old info
820 if (m_groundSourceCombo->currentText().contains("NONE")) {
821 success = false;
822 }
823 else {
824 // Chosen ground source is an imported shape in project
825 if (m_groundSourceCombo->currentText().contains(".ecub")) {
826 Shape *shape = m_nameToShapeMap[m_groundSourceCombo->currentText()];
827 groundFile = FileName(shape->fileName());
828 //groundSourceType = shape->surfacePointSource();
829 success = true;
830 }
831 // Not imported shape, must be from m_editPoints AprioriXYZSource in the cnet
832 else if (m_editPoint->HasAprioriSurfacePointSourceFile()) {
833 groundFile = FileName(m_groundSourceCombo->currentText());
834 // Apriori ground source does not exist and user chose not to give new location so simply
835 // return unsuccessful
836 if (!groundFile.fileExists()) {
837 success = false;
838 }
839 else {
840 groundSourceType = m_editPoint->GetAprioriSurfacePointSource();
841 success = true;
842 }
843 }
844 }
845
846 // If a new ground file was found set ground source information for later use, first clearing
847 // out the old ground source information. If new ground same as old ground, we will not change
848 // anything, simply return successful.
849 if (success && (groundFile.expanded() != m_groundFilename)) {
851 m_groundFilename = groundFile.expanded();
852
853 // Get cube, then universal groundmap
854 QScopedPointer<Cube> groundCube(new Cube(groundFile, "r"));
855 m_groundGmap.reset(NULL);
856 QScopedPointer<UniversalGroundMap> newGroundGmap(new UniversalGroundMap(*groundCube));
857 m_groundGmap.reset(newGroundGmap.take());
858
859 // Create new serial number for ground source and add to serial number list
860 m_groundSN = SerialNumber::Compose(groundFile.expanded(), true);
862
863 m_groundSourceType = groundSourceType;
864 }
865 // Could not successfully find a ground source file, clear out any old info and return
866 // unsuccessful
867 else if (!success) {
869 }
870
871 return success;
872 }
873
874
886
887 FileName newGroundFile;
888
889 if (!groundFile.fileExists()) {
890
891 // If user previously chose to change all ground source locations, but didn't update the net
892 // fix this ground source to new location
893 // If all groundLocations are to be changed...
895 QFileInfo oldFile(groundFile.expanded());
896 QFileInfo newFile(m_newGroundDir, oldFile.fileName());
897
898 newGroundFile = FileName(newFile.absoluteFilePath());
899 }
900
901 // If can't find ground, re-prompt user for new location. Maybe it's a new ground source.
902 if (!newGroundFile.fileExists()) {
903 // Give options for finding ground source file location. A new location
904 // for new location or new source, either a Shape in the project, or import a new shape,
905 // or simplay choose file?
906 QString message = "Ground Source file " + groundFile.expanded();
907 message += " doesn't exist. Has the file moved? Would you like to enter a new location for"
908 " this ground source?";
909 int ret = QMessageBox::question(this, "Ground Source not found", message);
910 if (ret == QMessageBox::Yes) {
911 QString dir = m_directory->project()->shapeDataRoot();
913 "New Ground Source Location", dir);
914 if (dialog->exec() == QDialog::Accepted) {
915 m_newGroundDir = dialog->selectedFiles().value(0);
916 m_changeAllGroundLocation = dialog->changeAllGroundSourceLocation();
917 m_changeGroundLocationInNet = dialog->changeControlNet();
918 // Change all ground source locations to reflect new directory
921 }
922 // Change location of apriori for current edit point so combo boxes updated properly
923 QFileInfo oldFile(groundFile.expanded());
924 QFileInfo newFile(m_newGroundDir, oldFile.fileName());
925 newGroundFile = newFile.absoluteFilePath();
926 m_editPoint->SetAprioriSurfacePointSourceFile(newGroundFile.toString());
927 }
928 else {
929 // Either user does not want to change location of ground source or the new location
930 // Dialog was cancelled. Load point without the ground source.
931 newGroundFile = NULL;
932 }
933 }
934 else {
935 // Either user does not want to change location of ground source or the new location
936 // Dialog was cancelled. Load point without the ground source.
937 newGroundFile = NULL;
938 }
939 }
940 }
941 return newGroundFile;
942 }
943
944
951
952 for (int i = 0; i < m_controlNet->GetNumPoints(); i++ ) {
953 ControlPoint *cp = m_controlNet->GetPoint(i);
954 if (cp->HasAprioriSurfacePointSourceFile()) {
955 FileName groundFile(cp->GetAprioriSurfacePointSourceFile());
956 QFileInfo oldFile(groundFile.expanded());
957 QFileInfo newFile(m_newGroundDir, oldFile.fileName());
958 groundFile = newFile.absoluteFilePath();
959 cp->SetAprioriSurfacePointSourceFile(groundFile.expanded());
960 }
961 }
962 emit cnetModified();
963 }
964
965
973
974 //Get the reference image's shape model
975 QString referenceSN = m_editPoint->GetReferenceSN();
976 QString referenceFileName = m_serialNumberList->fileName(referenceSN);
977 QScopedPointer<Cube> referenceCube(new Cube(referenceFileName, "r"));
978 PvlGroup kernels = referenceCube->group("Kernels");
979 QString shapeFile = kernels["ShapeModel"];
980
981 // If the reference measure has a shape model cube then set that as the radius
982 // This will NOT WORK for shape model files (not the default of Null or Ellipsoid)
983 // that are not cubes
984 if (shapeFile.contains(".cub")) {
985 if (shapeFile.contains("dem")) {
986 m_radiusSourceType = ControlPoint::RadiusSource::DEM;
987 }
988 else {
989 m_radiusSourceType = ControlPoint::RadiusSource::Ellipsoid;
990 }
991
992 m_radiusFilename = shapeFile;
993 initDem(shapeFile);
994 }
995 // If no shape model then use the ABC of the target body
996 else {
997 m_radiusSourceType = ControlPoint::RadiusSource::Ellipsoid;
998 Spice *refSpice = new Spice(*referenceCube);
999 Distance refRadii[3];
1000 refSpice->radii(refRadii);
1001 m_demFile = QString::number(refRadii[0].meters()) + ", " +
1002 QString::number(refRadii[1].meters()) + ", " +
1003 QString::number(refRadii[2].meters());
1004
1005 m_radiusFilename = "";
1006 }
1007 }
1008
1009
1017 void ControlPointEditWidget::initDem (QString demFile) {
1018
1019 // If a DEM is already opened, check if new is same as old. If new,
1020 // close old, open new.
1021 if (m_demOpen) {
1022 if (m_demFile == demFile) {
1023 return;
1024 }
1025
1026 m_demCube.reset(NULL);
1027 m_demFile.clear();
1028 }
1029
1030 QApplication::setOverrideCursor(Qt::WaitCursor);
1031 try {
1032 QScopedPointer<Cube> newDemCube(new Cube(demFile, "r"));
1033
1034 m_demFile = FileName(newDemCube->fileName()).name();
1035 m_demCube.reset(newDemCube.take());
1036 }
1037 catch (IException &e) {
1038 QMessageBox::critical(this, "Error", e.toString());
1039 QApplication::restoreOverrideCursor();
1040 return;
1041 }
1042 m_demOpen = true;
1043
1044 // Make sure this is a dem
1045 if (!m_demCube->hasTable("ShapeModelStatistics")) {
1046 QString message = m_demFile + " is not a DEM.";
1047 QMessageBox::critical(this, "Error", message);
1048 m_demCube.reset(NULL);
1049 m_demOpen = false;
1050 m_demFile.clear();
1051 QApplication::restoreOverrideCursor();
1052 return;
1053 }
1054 m_radiusSourceType = ControlPoint::RadiusSource::DEM;
1055 m_radiusFilename = demFile;
1056
1057 QApplication::restoreOverrideCursor();
1058 }
1059
1060
1068 double ControlPointEditWidget::demRadius(double latitude, double longitude) {
1069
1070 if (!m_demOpen) return Null;
1071
1072 UniversalGroundMap *demMap = new UniversalGroundMap(*m_demCube);
1073 if (!demMap->SetUniversalGround(latitude, longitude)) {
1074 delete demMap;
1075 demMap = NULL;
1076 return Null;
1077 }
1078
1079 // Use bilinear interpolation to read radius from DEM
1080 // Use bilinear interpolation from dem
1081 Interpolator *interp = new Interpolator(Interpolator::BiLinearType);
1082
1083 // Buffer used to read from the model
1084 Portal *portal = new Portal(interp->Samples(), interp->Lines(),
1085 m_demCube->pixelType(),
1086 interp->HotSample(), interp->HotLine());
1087 portal->SetPosition(demMap->Sample(), demMap->Line(), 1);
1088 m_demCube->read(*portal);
1089 double radius = interp->Interpolate(demMap->Sample(), demMap->Line(),
1090 portal->DoubleBuffer());
1091 delete demMap;
1092 demMap = NULL;
1093 delete interp;
1094 interp = NULL;
1095 delete portal;
1096 portal = NULL;
1097
1098 return radius;
1099 }
1100
1101
1109
1110 QString newChosenGroundFile = m_groundSourceCombo->currentText();
1111 if (newChosenGroundFile == m_groundFilename) {
1112 return;
1113 }
1115 }
1116
1117
1123
1124 if (m_groundSN.isEmpty()) {
1125 return;
1126 }
1127
1128 // If the loaded point is a fixed point, see if there is a temporary measure
1129 // holding the coordinate information for the current ground source. If so,
1130 // delete this measure and remove from the Chip viewport and measure selection combo.
1131 if (m_editPoint && m_editPoint->GetType() != ControlPoint::Free &&
1132 m_editPoint->HasSerialNumber(m_groundSN)) {
1133 m_editPoint->Delete(m_groundSN);
1134
1135 if (m_leftCombo->findText(QFileInfo(m_groundFilename).fileName()) >= 0) {
1136 m_leftCombo->removeItem(m_leftCombo->findText(QFileInfo(m_groundFilename).fileName()));
1137 if (m_leftMeasure->GetCubeSerialNumber() == m_groundSN) {
1139 }
1140 }
1141 if (m_rightCombo->findText(QFileInfo(m_groundFilename).fileName())) {
1142 m_rightCombo->removeItem(m_rightCombo->findText(QFileInfo(m_groundFilename).fileName()));
1143 if (m_rightMeasure->GetCubeSerialNumber() == m_groundSN) {
1145 }
1146 }
1147 m_pointFiles.removeAll(m_groundFilename);
1148 }
1149 // Remove from serial number list
1151
1152 // Reset ground source variables
1153 m_groundFilename.clear();
1154 m_groundSN.clear();
1155 m_groundGmap.reset(NULL);
1156 m_groundSourceType = ControlPoint::SurfacePointSource::None;
1157 }
1158
1159
1167 void ControlPointEditWidget::setEditPoint(ControlPoint *controlPoint, QString serialNumber) {
1168
1169 // If m_editPoint was never saved to control net (parent=NULL), delete
1170 if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1171 delete m_editPoint;
1172 m_editPoint = NULL;
1173 }
1174
1175 // If incoming control point is new point (has not been saved to control net, simply assign
1176 // to m_editPoint, otherwise create copy. It will not be saved to net until "Save Point"
1177 // is selected
1178 if (controlPoint->Parent() == NULL) {
1179 m_editPoint = controlPoint;
1180
1181 // New point in editor, so colorize all save buttons
1182 colorizeAllSaveButtons("red");
1183 }
1184 else {
1186 *m_editPoint = *controlPoint;
1187
1188 // New point loaded, make sure all save button's text is default black color
1189 colorizeAllSaveButtons("black");
1190 }
1191 loadPoint(serialNumber);
1192 loadTemplateFile(m_measureEditor->templateFileName());
1193 }
1194
1195
1196 void ControlPointEditWidget::colorizeAllSaveButtons(QString color) {
1197
1198 if (color == "black") {
1199 // Don't need to colorize save measure button, when loading new measure, the measure editor
1200 // will set back to default palette.
1201 m_savePoint->setPalette(m_saveDefaultPalette);
1202 m_saveNet->setPalette(m_saveDefaultPalette);
1203 }
1204 else if (color == "red") {
1205 m_measureEditor->colorizeSaveButton();
1208 }
1209 }
1210
1211
1232 void ControlPointEditWidget::loadPoint(QString serialNumber) {
1233
1234 // Write pointId
1235 QString CPId = m_editPoint->GetId();
1236
1237 QString ptId("Point ID: ");
1238 ptId += (QString) CPId;
1239 m_ptIdValue->setText(ptId);
1240
1241 // Set shapes for this point. Shapes are what has been imported into project.
1243
1244 // Write number of measures
1245 QString ptsize = "Number of Measures: " +
1246 QString::number(m_editPoint->GetNumMeasures());
1247 m_numMeasures->setText(ptsize);
1248
1249 // Set EditLock box correctly
1250 m_lockPoint->setChecked(m_editPoint->IsEditLocked());
1251
1252 // Set ignore box correctly
1253 m_ignorePoint->setChecked(m_editPoint->IsIgnored());
1254
1255
1256 // Refill combos since they are dependent on the current edit point
1257 // Turn off signals until filled since we don't want slot called.
1258 m_groundSourceCombo->blockSignals(true);
1259 m_radiusSourceCombo->blockSignals(true);
1260 m_groundSourceCombo->clear();
1261 m_radiusSourceCombo->clear();
1262 m_groundSourceCombo->addItem("NONE");
1263 m_groundSourceCombo->setCurrentText("NONE");
1264 m_radiusSourceCombo->addItem("NONE - Use reference measure's radius");
1265 m_radiusSourceCombo->setCurrentText("NONE - Use reference measure's radius");
1266
1267 // Load any imported project shapes that contain m_editPoint into the ground and any Dem's into
1268 // radius source combo boxes. Only add Dems to radius combo.
1269 if (m_projectShapeNames.count() > 0) {
1270 for (int i=0; i<m_numberProjectShapesWithPoint; i++) {
1272 if (shape->radiusSource() == ControlPoint::RadiusSource::DEM) {
1273 m_radiusSourceCombo->addItem(shape->fileName());
1274 }
1275 else {
1276 m_groundSourceCombo->addItem(shape->fileName());
1277 }
1278 }
1279 }
1280
1281 // If available, add the CP AprioriSurfacePointSourceFile and AprioriRadiusSourceFile
1282 if (m_editPoint->HasAprioriSurfacePointSourceFile()) {
1283 FileName aprioriSurfacePointFile = FileName(m_editPoint->GetAprioriSurfacePointSourceFile());
1284 // If file doesn't exist, prompt user for changing location before adding to combo
1285 if (!aprioriSurfacePointFile.fileExists()) {
1286 aprioriSurfacePointFile = checkGroundFileLocation(aprioriSurfacePointFile);
1287 }
1288 if (!aprioriSurfacePointFile.toString().isEmpty()) {
1289 m_groundSourceCombo->addItem(aprioriSurfacePointFile.toString());
1290 m_groundSourceCombo->setCurrentText(aprioriSurfacePointFile.toString());
1291 m_groundSourceCombo->setItemData(m_groundSourceCombo->currentIndex(),
1292 QColor(Qt::darkGreen), Qt::ForegroundRole);
1293 m_groundSourceCombo->setItemData(m_groundSourceCombo->currentIndex(),
1294 QFont("DejaVu Sans", 10, QFont::Bold), Qt::FontRole);
1295 }
1296 }
1297
1298 if (m_editPoint->HasAprioriRadiusSourceFile()) {
1299 //TODO check location of radius file
1300 m_radiusSourceCombo->addItem(m_editPoint->GetAprioriRadiusSourceFile());
1301 m_radiusSourceCombo->setCurrentText(m_editPoint->GetAprioriRadiusSourceFile());
1302 m_radiusSourceCombo->setItemData(m_radiusSourceCombo->currentIndex(),
1303 QColor(Qt::green), Qt::ForegroundRole);
1304 m_radiusSourceCombo->setItemData(m_groundSourceCombo->currentIndex(),
1305 QFont("DejaVu Sans", 10, QFont::Bold), Qt::FontRole);
1306 }
1307 if (m_editPoint->GetType() == ControlPoint::Free) {
1308 m_groundSourceCombo->setEnabled(false);
1309 m_radiusSourceCombo->setEnabled(false);
1310 }
1311 else {
1312 m_groundSourceCombo->setEnabled(true);
1313 m_radiusSourceCombo->setEnabled(true);
1314 }
1315 m_groundSourceCombo->blockSignals(false);
1316 m_radiusSourceCombo->blockSignals(false);
1317
1318
1319 // If constrained or fixed point, create a measure for
1320 // the ground source, load reference on left, ground source on right
1321 if (m_editPoint->GetType() != ControlPoint::Free) {
1322 // If m_editPoint already has a ground measure, delete
1323 for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
1324 ControlMeasure &m = *(*m_editPoint)[i];
1325 if (m.GetChooserName() == "GroundMeasureTemporary") {
1326 m_editPoint->Delete(&m);
1327 }
1328 }
1329 // Create a temporary measure to hold the ground point info for ground source
1330 // This measure will be deleted when the ControlPoint is saved to the
1331 // ControlNet.
1333 if (groundMeasure) {
1334 m_editPoint->Add(groundMeasure);
1335 }
1336 }
1337
1338
1339
1340 // Reset PointType combo box appropriately.
1341 m_pointTypeCombo->clear();
1342 for (int i=0; i<ControlPoint::PointTypeCount; i++) {
1345 }
1347 m_pointTypeCombo->setToolTip("Change ControlPoint type");
1348
1350
1351
1352
1353 // Clear combo boxes
1354 m_leftCombo->clear();
1355 m_rightCombo->clear();
1356 m_pointFiles.clear();
1357
1358
1359 // Need all files for this point
1360 for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
1361 ControlMeasure &m = *(*m_editPoint)[i];
1362 QString file = m_serialNumberList->fileName(m.GetCubeSerialNumber());
1363 m_pointFiles<<file;
1364 QString tempFileName = FileName(file).name();
1365
1366 // This actually fills the right combo box for selecting measures. A model was used to enable
1367 // drag & drop for ordering measures which will also set the blink order.
1368 QStandardItem *item = new QStandardItem(tempFileName);
1369 item->setFlags(item->flags() & ~Qt::ItemIsDropEnabled);
1370 m_model->appendRow(item);
1371
1372 m_leftCombo->addItem(tempFileName);
1373
1374 if (m_editPoint->IsReferenceExplicit() &&
1375 (QString)m.GetCubeSerialNumber() == m_editPoint->GetReferenceSN()) {
1376 m_leftCombo->setItemData(i,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
1377 m_rightCombo->setItemData(i,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
1378 }
1379 }
1380
1382
1383 int leftIndex = -1;
1384 int rightIndex = -1;
1385
1386 QString referenceSerialNumber;
1387 // Check for reference
1388 if (m_editPoint->IsReferenceExplicit()) {
1389 referenceSerialNumber = m_editPoint->GetReferenceSN();
1390 leftIndex = m_editPoint->IndexOfRefMeasure();
1391 }
1392
1393 if (!serialNumber.isEmpty() && serialNumber != referenceSerialNumber) {
1394 QString file = m_serialNumberList->fileName(serialNumber);
1395 rightIndex = m_rightCombo->findText(FileName(file).name());
1396 if (leftIndex == -1) {
1397 if (rightIndex == 0) {
1398 leftIndex = 1;
1399 }
1400 else {
1401 leftIndex = 0;
1402 }
1403 }
1404 }
1405
1406 if (leftIndex == -1) {
1407 if (rightIndex == 0) {
1408 leftIndex = 1;
1409 }
1410 else {
1411 leftIndex = 0;
1412 }
1413 }
1414
1415 // If ground measure exists, load in right viewport
1416 if (m_editPoint->HasSerialNumber(m_groundSN)) {
1417 rightIndex = m_rightCombo->findText(m_groundSN);
1418 }
1419 if (rightIndex <= 0) {
1420 if (leftIndex == 0) {
1421 rightIndex = 1;
1422 }
1423 else {
1424 rightIndex = 0;
1425 }
1426 }
1427 // Handle pts with a single measure, for now simply put measure on left/right
1428 // Evenutally put on left with black on right??
1429 if (rightIndex > m_editPoint->GetNumMeasures()-1) rightIndex = 0;
1430
1431 m_rightCombo->setCurrentIndex(rightIndex);
1432 m_leftCombo->setCurrentIndex(leftIndex);
1433
1434 // Initialize pointEditor with measures
1435 selectLeftMeasure(leftIndex);
1436 selectRightMeasure(rightIndex);
1437
1438 this->setVisible(true);
1439 this->raise();
1440 }
1441
1442
1453 void ControlPointEditWidget::createControlPoint(double latitude, double longitude, Cube *cube,
1454 bool isGroundSource) {
1455
1456 // TODO: CHECK SUBPIXEL REGISTER RADIO BUTTON OPTION (CHECKBOX?)
1457
1458 // Create list box of all files highlighting those that
1459 // contain the point.
1460 QStringList pointFiles;
1461
1462 Camera *cam;
1463 for (int i = 0; i < m_serialNumberList->size(); i++) {
1464 if (m_serialNumberList->serialNumber(i) == m_groundSN) continue;
1465 cam = m_controlNet->Camera(i);
1466 if (cam->SetUniversalGround(latitude, longitude)) {
1467 // Make sure point is within image boundary
1468 double samp = cam->Sample();
1469 double line = cam->Line();
1470 if (samp >= 1 && samp <= cam->Samples() &&
1471 line >= 1 && line <= cam->Lines()) {
1472 pointFiles<<m_serialNumberList->fileName(i);
1473 }
1474 }
1475 }
1476
1477 // Set shapes from project to fill dialog, indicating number of shapes that contain the CP.
1478 // The shapes which contain the CP will be at the front of the QStringList.
1479 setShapesForPoint(latitude, longitude);
1480
1482 m_serialNumberList, m_lastUsedPointId, this, true, true, true);
1483 newPointDialog->setFiles(pointFiles);
1484 newPointDialog->setGroundSource(m_projectShapeNames, m_numberProjectShapesWithPoint);
1485
1486 // Load imported project shapes that are Dems and contain point location into the radius combo.
1487 if (m_projectShapeNames.count() > 0) {
1488 QStringList radiusSourceFiles;
1489 for (int i=0; i<m_numberProjectShapesWithPoint; i++) {
1491 if (shape->radiusSource() == ControlPoint::RadiusSource::DEM) {
1492 radiusSourceFiles<<shape->fileName();
1493 }
1494 }
1495 newPointDialog->setRadiusSource(radiusSourceFiles);
1496 }
1497
1498
1499
1500 if (newPointDialog->exec() == QDialog::Accepted) {
1501 m_lastUsedPointId = newPointDialog->pointId();
1502 ControlPoint *newPoint =
1504
1505 // If this ControlPointId already exists, message box pops up and user is
1506 // asked to enter a new value.
1507 if (m_controlNet->ContainsPoint(newPoint->GetId())) {
1508 QString message = "A ControlPoint with Point Id = [" + newPoint->GetId();
1509 message += "] already exists. Re-enter Point Id for this ControlPoint.";
1510 QMessageBox::warning(this, "New Point Id", message);
1511 pointFiles.clear();
1512 delete newPoint;
1513 newPoint = NULL;
1514 createControlPoint(latitude, longitude);
1515 return;
1516 }
1517
1519
1520 QStringList selectedFiles = newPointDialog->selectedFiles();
1521 foreach (QString selectedFile, selectedFiles) {
1522 // Create measure for any file selected
1524 // Find serial number for this file
1525 QString sn = m_serialNumberList->serialNumber(selectedFile);
1526 m->SetCubeSerialNumber(sn);
1527 int camIndex = m_serialNumberList->fileNameIndex(selectedFile);
1528 cam = m_controlNet->Camera(camIndex);
1529 cam->SetUniversalGround(latitude, longitude);
1530 m->SetCoordinate(cam->Sample(),cam->Line());
1531 m->SetAprioriSample(cam->Sample());
1532 m->SetAprioriLine(cam->Line());
1533 m->SetType(ControlMeasure::Manual);
1534 m->SetChooserName(Application::UserName());
1535 m->SetCamera(cam);
1536 newPoint->Add(m);
1537 }
1538
1539 // Get point type from dialog
1540 bool isGroundPoint = (newPointDialog->pointType() != ControlPoint::Free);
1541 newPoint->SetType((ControlPoint::PointType) newPointDialog->pointType());
1542
1543 if (isGroundPoint) {
1544 Shape *shape = m_nameToShapeMap[newPointDialog->groundSource()];
1545 // Save ground source information in control point
1546 if (shape) {
1547 newPoint->SetAprioriSurfacePointSource(shape->surfacePointSource());
1548 }
1549 else {
1550 newPoint->SetAprioriSurfacePointSource(ControlPoint::SurfacePointSource::None);
1551 }
1553 }
1554
1555 setEditPoint(newPoint);
1556 emit controlPointAdded(newPoint->GetId());
1557 }
1558 }
1559
1560
1567
1568 // Make a copy and make sure editPoint is a copy (which means it does not
1569 // have a parent network.
1570 if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1571 delete m_editPoint;
1572 m_editPoint = NULL;
1573 }
1575 *m_editPoint = *controlPoint;
1576 loadPoint();
1577
1578 DeleteControlPointDialog *deletePointDialog = new DeleteControlPointDialog;
1579 QString CPId = m_editPoint->GetId();
1580 deletePointDialog->pointIdValue->setText(CPId);
1581
1582 // Need all files for this point
1583 for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
1584 ControlMeasure &m = *(*m_editPoint)[i];
1585 QString file = m_serialNumberList->fileName(m.GetCubeSerialNumber());
1586 deletePointDialog->fileList->addItem(file);
1587 }
1588
1589 if (deletePointDialog->exec()) {
1590
1591 int numDeleted = deletePointDialog->fileList->selectedItems().count();
1592
1593 // Delete entire control point, either through deleteAllCheckBox or all measures selected
1594 if (deletePointDialog->deleteAllCheckBox->isChecked() ||
1595 numDeleted == m_editPoint->GetNumMeasures()) {
1596
1597 // If all measures being deleted, let user know and give them the option to quit operation
1598 if (!deletePointDialog->deleteAllCheckBox->isChecked()) {
1599 QString message = "You have selected all measures in this point to be deleted. This "
1600 "control point will be deleted. Do you want to delete this control point?";
1601 int response = QMessageBox::question(this,
1602 "Delete control point", message,
1603 QMessageBox::Yes | QMessageBox::No,
1604 QMessageBox::Yes);
1605 // If No, do nothing
1606 if (response == QMessageBox::No) {
1607 return;
1608 }
1609 }
1610
1611 //this->setVisible(false);
1612 // remove this point from the control network
1613 if (m_controlNet->DeletePoint(m_editPoint->GetId()) ==
1615 QMessageBox::information(this, "EditLocked Point",
1616 "This point is EditLocked and cannot be deleted.");
1617 return;
1618 }
1619 if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1620// delete m_editPoint;
1621// m_editPoint = NULL;
1622 }
1623 }
1624
1625 // Delete specific measures from control point
1626 else {
1627 // Keep track of editLocked measures for reporting
1628 int lockedMeasures = 0;
1629 for (int i=0; i<deletePointDialog->fileList->count(); i++) {
1630 QListWidgetItem *item = deletePointDialog->fileList->item(i);
1631 if (!deletePointDialog->fileList->isItemSelected(item)) continue;
1632
1633 // Do not delete reference without asking user
1634 if (m_editPoint->IsReferenceExplicit() &&
1635 (m_editPoint->GetRefMeasure()->GetCubeSerialNumber() ==
1636 (*m_editPoint)[i]->GetCubeSerialNumber())) {
1637 QString message = "You are trying to delete the Reference measure."
1638 " Do you really want to delete the Reference measure?";
1639 switch (QMessageBox::question(this,
1640 "Delete Reference measure?", message,
1641 "&Yes", "&No", 0, 0)) {
1642 // Yes: skip to end of switch todelete the measure
1643 case 0:
1644 break;
1645 // No: continue to next measure in the loop
1646 case 1:
1647 // if only a single measure and it's reference and user chooses not to delete,
1648 // simply return. The point has not changed.
1649 if (numDeleted == 1) {
1650 return;
1651 }
1652 continue;
1653 }
1654 }
1655
1656 if (m_editPoint->Delete(i) == ControlMeasure::MeasureLocked) {
1657 lockedMeasures++;
1658 }
1659 }
1660
1661 if (lockedMeasures > 0) {
1662 QMessageBox::information(this,"EditLocked Measures",
1663 QString::number(lockedMeasures) + " / "
1664 + QString::number(
1665 deletePointDialog->fileList->selectedItems().size()) +
1666 " measures are EditLocked and were not deleted.");
1667 }
1668
1669 loadPoint();
1670
1671// loadTemplateFile(m_pointEditor->templateFileName());
1672 }
1673
1674 // emit a signal to alert user to save when exiting
1675 m_control->setModified(true);
1676 emit cnetModified();
1677
1678 if (m_editPoint != NULL) {
1679 // Change Save Point button text to red
1681 }
1682 }
1683 }
1684
1685
1749
1750 // Read original measures from the network for comparison with measures
1751 // that have been edited
1752 ControlMeasure *origLeftMeasure =
1753 m_editPoint->GetMeasure(m_leftMeasure->GetCubeSerialNumber());
1754 ControlMeasure *origRightMeasure =
1755 m_editPoint->GetMeasure(m_rightMeasure->GetCubeSerialNumber());
1756 // Neither measure has changed, return
1757 if (*origLeftMeasure == *m_leftMeasure && *origRightMeasure == *m_rightMeasure) {
1758 return;
1759 }
1760
1761 if (m_editPoint->IsIgnored()) {
1762 QString message = "You are saving changes to a measure on an ignored ";
1763 message += "point. Do you want to set Ignore = False on the point and ";
1764 message += "both measures?";
1765 switch (QMessageBox::question(this, "Save Measure", message, "&Yes", "&No", 0, 0)) {
1766 // Yes: set Ignore=false for the point and measures and save point
1767 case 0:
1768 m_editPoint->SetIgnored(false);
1769 emit ignorePointChanged();
1770 if (m_leftMeasure->IsIgnored()) {
1771 m_leftMeasure->SetIgnored(false);
1772 emit ignoreLeftChanged();
1773 }
1774 if (m_rightMeasure->IsIgnored()) {
1775 m_rightMeasure->SetIgnored(false);
1776 emit ignoreRightChanged();
1777 }
1778 // No: keep Ignore=true and save measure
1779 case 1:
1780 break;
1781 }
1782 }
1783
1784 bool savedAMeasure = false;
1785 // Error check both measures for edit lock, ignore status and reference
1786 bool leftChangeOk = validateMeasureChange(m_leftMeasure);
1787 if (leftChangeOk) {
1788 m_leftMeasure->SetChooserName(Application::UserName());
1789 *origLeftMeasure = *m_leftMeasure;
1790 savedAMeasure = true;
1791 }
1792 bool rightChangeOk = validateMeasureChange(m_rightMeasure);
1793 if (rightChangeOk) {
1794 m_rightMeasure->SetChooserName(Application::UserName());
1795 *origRightMeasure = *m_rightMeasure;
1796 savedAMeasure = true;
1797 }
1798
1799 // If this is a fixed or constrained point, and either the left or right measure is the ground
1800 // source, update the lat,lon,radius.
1801 //
1802 if (m_editPoint->GetType() != ControlPoint::Free &&
1803 (m_leftMeasure->GetCubeSerialNumber() == m_groundSN ||
1804 m_rightMeasure->GetCubeSerialNumber() == m_groundSN)) {
1805 // If point is locked and it is not a new point, print error
1806 if (m_editPoint->IsEditLocked() && m_controlNet->ContainsPoint(m_editPoint->GetId())) {
1807 QString message = "This control point is edit locked. The Apriori latitude, longitude and ";
1808 message += "radius cannot be updated. You must first unlock the point by clicking the ";
1809 message += "check box above labeled \"Edit Lock Point\".";
1810 QMessageBox::warning(this, "Point Locked", message);
1811 return;
1812 }
1813 if (m_leftMeasure->IsIgnored()) {
1814 QString message = "This is a Constrained or Fixed point and the reference measure is ";
1815 message += "Ignored. Unset the Ignore flag on the reference measure before saving.";
1816 QMessageBox::warning(this, "Point Locked", message);
1817 return;
1818 }
1819 updateGroundPosition();
1820 }
1821
1822 // If left measure == right measure, update left
1823 if (m_leftMeasure->GetCubeSerialNumber() == m_rightMeasure->GetCubeSerialNumber()) {
1825 // Update left measure of measureEditor
1826 m_measureEditor->setLeftMeasure (m_leftMeasure, m_leftCube.data(),
1827 m_editPoint->GetId());
1828 }
1829
1830 // Change Save Point button text to red
1831 if (savedAMeasure) {
1833 }
1834
1835 // Update measure info
1838 }
1839
1840
1849
1850 // Read original measures from the network for comparison with measures
1851 // that have been edited
1852 ControlMeasure *origMeasure =
1853 m_editPoint->GetMeasure(m->GetCubeSerialNumber());
1854
1855 // If measure hasn't changed, return false, to keep original
1856 if (*m == *origMeasure) return false;
1857
1858 // Is measure on Left or Right? This is needed to print correct information
1859 // to users in identifying the measure and for updating information widgets.
1860 QString side = "right";
1861 if (m->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
1862 side = "left";
1863 }
1864
1865 // Only print error if both original measure in network and the current
1866 // edit measure are both editLocked and measure has changed. If only the edit measure is
1867 // locked, then user just locked and it needs to be saved.
1868 // Do not use this classes IsMeasureLocked since we actually want to
1869 // check the original againsted the edit measure and we don't care
1870 // if this is a reference measure. The check for moving a reference is
1871 // done below.
1872 if (origMeasure->IsEditLocked() && m->IsEditLocked()) {
1873 QString message = "The " + side + " measure is editLocked ";
1874 message += "for editing. Do you want to set EditLock = False for this ";
1875 message += "measure?";
1876 int response = QMessageBox::question(this, "Save Measure",
1877 message, QMessageBox::Yes | QMessageBox::No);
1878 // Yes: set EditLock=false for the right measure
1879 if (response == QMessageBox::Yes) {
1880 m->SetEditLock(false);
1881 if (side == "left") {
1882 m_lockLeftMeasure->setChecked(false);
1883 }
1884 else {
1885 m_lockRightMeasure->setChecked(false);
1886 }
1887 }
1888 // No: keep EditLock=true and do NOT save measure
1889 else {
1890 return false;
1891 }
1892 }
1893
1894 if (origMeasure->IsIgnored() && m->IsIgnored()) {
1895 QString message = "The " + side + "measure is ignored. ";
1896 message += "Do you want to set Ignore = False on the measure?";
1897 switch (QMessageBox::question(this, "Save Measure", message, "&Yes", "&No", 0, 0)) {
1898 // Yes: set Ignore=false for the right measure and save point
1899 case 0:
1900 m->SetIgnored(false);
1901 if (side == "left") {
1902 emit ignoreLeftChanged();
1903 }
1904 else {
1905 emit ignoreRightChanged();
1906 }
1907 // No: keep Ignore=true and save point
1908 case 1:
1909 break;;
1910 }
1911 }
1912
1913 // If measure is explicit reference and it has moved,warn user
1914 ControlMeasure *refMeasure = m_editPoint->GetRefMeasure();
1915 if (m_editPoint->IsReferenceExplicit()) {
1916 if (refMeasure->GetCubeSerialNumber() == m->GetCubeSerialNumber()) {
1917 if (m->GetSample() != origMeasure->GetSample() || m->GetLine() != origMeasure->GetLine()) {
1918 QString message = "You are making a change to the reference measure. You ";
1919 message += "may need to move all of the other measures to match the new ";
1920 message += " coordinate of the reference measure. Do you really want to ";
1921 message += " change the reference measure's location? ";
1922 switch(QMessageBox::question(this, "Save Measure",
1923 message, "&Yes", "&No", 0, 0)){
1924 // Yes: Save measure
1925 case 0:
1926 break;
1927 // No: keep original reference, return without saving
1928 case 1:
1929 ControlMeasure *origLeftMeasure =
1930 m_editPoint->GetMeasure(m_leftMeasure->GetCubeSerialNumber());
1931 m_measureEditor->setLeftPosition(origLeftMeasure->GetSample(),
1932 origLeftMeasure->GetLine());
1933 return false;
1934 }
1935 }
1936 }
1937 // New reference measure
1938 else if (side == "left" && (refMeasure->GetCubeSerialNumber() != m->GetCubeSerialNumber())) {
1939 QString message = "This point already contains a reference measure. ";
1940 message += "Would you like to replace it with the measure on the left?";
1941 int response = QMessageBox::question(this,
1942 "Save Measure", message,
1943 QMessageBox::Yes | QMessageBox::No,
1944 QMessageBox::Yes);
1945 // Replace reference measure
1946 if (response == QMessageBox::Yes) {
1947 // Update measure file combo boxes: old reference normal font,
1948 // new reference bold font
1949 QString file = m_serialNumberList->fileName(m_leftMeasure->GetCubeSerialNumber());
1950 QString fname = FileName(file).name();
1951 int iref = m_leftCombo->findText(fname);
1952
1953 // Save normal font from new reference measure
1954 QVariant font = m_leftCombo->itemData(iref,Qt::FontRole);
1955 m_leftCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
1956 iref = m_rightCombo->findText(fname);
1957 m_rightCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
1958
1959 file = m_serialNumberList->fileName(refMeasure->GetCubeSerialNumber());
1960 fname = FileName(file).name();
1961 iref = m_leftCombo->findText(fname);
1962 m_leftCombo->setItemData(iref,font,Qt::FontRole);
1963 iref = m_rightCombo->findText(fname);
1964 m_rightCombo->setItemData(iref,font,Qt::FontRole);
1965
1966 m_editPoint->SetRefMeasure(m->GetCubeSerialNumber());
1967 }
1968 }
1969 }
1970 else {
1971 // No explicit reference, If left, set explicit reference
1972 if (side == "left") {
1973 m_editPoint->SetRefMeasure(m->GetCubeSerialNumber());
1974 }
1975 }
1976
1977 // All test pass, return true (ok to change measure)
1978 return true;
1979
1980
1981 }
1982
1983
1994
1995 // Check if ControlPoint has reference measure, if reference Measure is
1996 // not the same measure that is on the left chip viewport, set left
1997 // measure as reference.
1998 ControlMeasure *refMeasure = m_editPoint->GetRefMeasure();
1999 if (refMeasure->GetCubeSerialNumber() != m_leftMeasure->GetCubeSerialNumber()) {
2000 QString message = "This point already contains a reference measure. ";
2001 message += "Would you like to replace it with the measure on the left?";
2002 int response = QMessageBox::question(this,
2003 "Match Tool Save Measure", message,
2004 QMessageBox::Yes | QMessageBox::No,
2005 QMessageBox::Yes);
2006 // Replace reference measure
2007 if (response == QMessageBox::Yes) {
2008 // Update measure file combo boxes: old reference normal font,
2009 // new reference bold font
2010 QString file = m_serialNumberList->fileName(m_leftMeasure->GetCubeSerialNumber());
2011 QString fname = FileName(file).name();
2012 int iref = m_leftCombo->findText(fname);
2013
2014 // Save normal font from new reference measure
2015 QVariant font = m_leftCombo->itemData(iref,Qt::FontRole);
2016 m_leftCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
2017 iref = m_rightCombo->findText(fname);
2018 m_rightCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
2019
2020 file = m_serialNumberList->fileName(refMeasure->GetCubeSerialNumber());
2021 fname = FileName(file).name();
2022 iref = m_leftCombo->findText(fname);
2023 m_leftCombo->setItemData(iref,font,Qt::FontRole);
2024 iref = m_rightCombo->findText(fname);
2025 m_rightCombo->setItemData(iref,font,Qt::FontRole);
2026
2027 m_editPoint->SetRefMeasure(m_leftMeasure->GetCubeSerialNumber());
2028 }
2029
2030 // ??? Need to set rest of measures to Candiate and add more warning. ???//
2031 }
2032 }
2033
2034
2035 /*
2036 * Update the position of ground point
2037 *
2038 * @author 2012-04-26 Tracie Sucharski - moved functionality from measureSaved
2039 *
2040 * @internal
2041 *
2042 */
2043 void ControlPointEditWidget::updateGroundPosition() {
2044
2045 // Determine if the left or right measure is the ground. Use ground measure to update
2046 // apriori surface point.
2047 ControlMeasure *groundMeasure;
2048 if (m_leftMeasure->GetCubeSerialNumber() == m_groundSN) {
2049 groundMeasure = m_leftMeasure;
2050 }
2051 else {
2052 groundMeasure = m_rightMeasure;
2053 }
2054 m_groundGmap->SetImage(groundMeasure->GetSample(), groundMeasure->GetLine());
2055
2056 double lat = m_groundGmap->UniversalLatitude();
2057 double lon = m_groundGmap->UniversalLongitude();
2058
2059 // Find radius source file
2060 // If nothing has been selected from the Radius source combo, use the Reference measure
2061 if (m_radiusSourceCombo->currentText().contains("NONE")) {
2062 m_radiusFilename.clear();
2063 m_demOpen = false;
2064 m_demFile.clear();
2065 m_demCube.reset(NULL);
2067 }
2068 else {
2069 Shape *shape = m_nameToShapeMap[m_radiusSourceCombo->currentText()];
2070 if (shape) {
2071 m_radiusFilename = shape->cube()->externalCubeFileName().toString();
2072 //m_radiusSourceType = shape->radiusSource();
2073 }
2074 // Radius source comes from what is already saved in the cnet as AprioriRadiusSourceFile
2075 // This will contain the path
2076 else {
2077 m_radiusFilename = m_radiusSourceCombo->currentText();
2078 m_radiusSourceType = m_editPoint->GetAprioriRadiusSource();
2079 }
2080 initDem(m_radiusFilename);
2081 }
2082
2083
2084 double radius;
2085 // Update radius, order of precedence
2086 // 1. If a dem has been opened, read radius from dem.
2087 // 2. Get radius from reference measure
2088 // If image has shape model, radius will come from shape model
2089 //
2090 if (m_demOpen) {
2091 radius = demRadius(lat,lon);
2092 if (radius == Null) {
2093 QString msg = "Could not read radius from DEM, will default to "
2094 "local radius of reference measure.";
2095 QMessageBox::warning(this, "Warning", msg);
2096 if (m_editPoint->GetRefMeasure()->Camera()->SetGround(Latitude(lat, Angle::Degrees),
2097 Longitude(lon, Angle::Degrees))) {
2098 radius = m_editPoint->GetRefMeasure()->Camera()->LocalRadius().meters();
2099 // TODO Should this be set here, this is probably not working as intended since it is
2100 // overwritten below outside of if (radius == Null)
2101 m_editPoint->SetAprioriRadiusSource(ControlPoint::RadiusSource::None);
2102 }
2103 else {
2104 QString message = "Error trying to get radius at this pt. "
2105 "Lat/Lon does not fall on the reference measure. "
2106 "Cannot save this measure.";
2107 QMessageBox::critical(this,"Error",message);
2108 return;
2109 }
2110 }
2111 m_editPoint->SetAprioriRadiusSource(m_radiusSourceType);
2112 m_editPoint->SetAprioriRadiusSourceFile(m_radiusFilename);
2113 }
2114 else {
2115 // Get radius from reference image
2116 if (m_editPoint->GetRefMeasure()->Camera()->SetGround(Latitude(lat, Angle::Degrees),
2117 Longitude(lon, Angle::Degrees))) {
2118 radius = m_editPoint->GetRefMeasure()->Camera()->LocalRadius().meters();
2119 }
2120 else {
2121 QString message = "Error trying to get radius at this pt. "
2122 "Lat/Lon does not fall on the reference measure. "
2123 "Cannot save this measure.";
2124 QMessageBox::critical(this,"Error",message);
2125 return;
2126 }
2127 }
2128
2129 try {
2130 // Read apriori surface point if it exists so that point is
2131 // replaced, but sigmas are retained. Save sigmas because the
2132 // SurfacePoint class will change them if the coordinates change.
2133 if (m_editPoint->HasAprioriCoordinates()) {
2134 SurfacePoint aprioriPt = m_editPoint->GetAprioriSurfacePoint();
2135 Distance latSigma = aprioriPt.GetLatSigmaDistance();
2136 Distance lonSigma = aprioriPt.GetLonSigmaDistance();
2137 Distance radiusSigma = aprioriPt.GetLocalRadiusSigma();
2138 aprioriPt.SetSphericalCoordinates(Latitude(lat, Angle::Degrees),
2139 Longitude(lon, Angle::Degrees),
2140 Distance(radius, Distance::Meters));
2141 aprioriPt.SetSphericalSigmasDistance(latSigma, lonSigma, radiusSigma);
2142 m_editPoint->SetAprioriSurfacePoint(aprioriPt);
2143 }
2144 else {
2145 m_editPoint->SetAprioriSurfacePoint(SurfacePoint(
2146 Latitude(lat, Angle::Degrees),
2147 Longitude(lon, Angle::Degrees),
2148 Distance(radius, Distance::Meters)));
2149 }
2150 }
2151 catch (IException &e) {
2152 QString message = "Unable to set Apriori Surface Point.\n";
2153 message += "Latitude = " + QString::number(lat);
2154 message += " Longitude = " + QString::number(lon);
2155 message += " Radius = " + QString::number(radius) + "\n";
2156 message += e.toString();
2157 QMessageBox::critical(this,"Error",message);
2158 return;
2159 }
2160
2161 m_editPoint->SetAprioriSurfacePointSource(m_groundSourceType);
2162 QString fullGroundFilename;
2163 if (m_groundFilename.contains(".ecub")) {
2164 // Find shape to get external cube filename
2165 fullGroundFilename = m_nameToShapeMap[m_groundFilename]->cube()->externalCubeFileName().expanded();
2166 }
2167 else {
2168 fullGroundFilename = m_groundFilename;
2169 }
2170 m_editPoint->SetAprioriSurfacePointSourceFile(fullGroundFilename);
2171
2173 }
2174
2175
2191
2192 // Make a copy of edit point for updating the control net since the edit
2193 // point is still loaded in the point editor.
2194 ControlPoint *updatePoint = new ControlPoint;
2195 *updatePoint = *m_editPoint;
2196
2197 // If this is a fixed or constrained point, see if there is a temporary
2198 // measure holding the coordinate information from the ground source.
2199 // If so, delete this measure before saving point. Clear out the
2200 // fixed Measure variable (memory deleted in ControlPoint::Delete).
2201 if (updatePoint->GetType() != ControlPoint::Free && updatePoint->HasSerialNumber(m_groundSN)) {
2202 // Delete measure with m_groundSN
2203 updatePoint->Delete(m_groundSN);
2204 }
2205
2206 // If edit point exists in the network, save the updated point. If it
2207 // does not exist, add it.
2208 if (m_controlNet->ContainsPoint(updatePoint->GetId())) {
2209 ControlPoint *p;
2210 p = m_controlNet->GetPoint(QString(updatePoint->GetId()));
2211 *p = *updatePoint;
2212 delete updatePoint;
2213 updatePoint = NULL;
2214 emit controlPointChanged(m_editPoint->GetId());
2215 }
2216 else {
2217 m_controlNet->AddPoint(updatePoint);
2218 emit controlPointAdded(m_editPoint->GetId());
2219 }
2220
2221 // Change Save Measure button text back to default
2222 m_savePoint->setPalette(m_saveDefaultPalette);
2223
2224 // At exit, or when opening new net, use for prompting user for a save
2225 m_cnetModified = true;
2226 m_control->setModified(true);
2227 emit cnetModified();
2228 // Refresh chipViewports to show new positions of controlPoints
2229 m_measureEditor->refreshChips();
2230 }
2231
2232
2249
2250 if (m_editPoint == NULL) return;
2251
2252 // If pointType is equal to current type, nothing to do
2253 if (m_editPoint->GetType() == pointType) return;
2254 int oldType = m_editPoint->GetType();
2255
2256 // Error check ignored and locked status
2257 if (pointType != ControlPoint::Free && m_leftMeasure->IsIgnored()) {
2258 m_pointTypeCombo->setCurrentIndex((int) m_editPoint->GetType());
2259 QString message = "The reference measure is Ignored. Unset the Ignore flag on the ";
2260 message += "reference measure before setting the point type to Constrained or Fixed.";
2261 QMessageBox::warning(m_parent, "Ignored Reference Measure", message);
2262 return;
2263 }
2264 ControlPoint::Status status = m_editPoint->SetType((ControlPoint::PointType) pointType);
2265 if (status == ControlPoint::PointLocked) {
2266 m_pointTypeCombo->setCurrentIndex((int) m_editPoint->GetType());
2267 QString message = "This control point is edit locked. The point type cannot be changed. You ";
2268 message += "must first unlock the point by clicking the check box above labeled ";
2269 message += "\"Edit Lock Point\".";
2270 QMessageBox::warning(m_parent, "Point Locked", message);
2271 return;
2272 }
2273
2274 // Changing type between Contrained and Fixed, simply colorize Save CP button and return. Do
2275 // not re-load CP or re-create ground CM.
2276 if (oldType != ControlPoint::Free && m_editPoint->GetType() != ControlPoint::Free) {
2278 }
2279 // If changing from Constrained or Fixed to Free, remove ground CM, disable ground/radius source
2280 // combos, re-load CP, colorize Save CP.
2281 else if (oldType != ControlPoint::Free && m_editPoint->GetType() == ControlPoint::Free) {
2282 // Find temporary measure holding the coordinate information from the ground source and
2283 // delete from CP. This CM has a chooser name = GroundMeasureTemporary.
2284 // Clear out the fixed Measure variable (memory deleted in ControlPoint::Delete).
2285 for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
2286 ControlMeasure &m = *(*m_editPoint)[i];
2287 if (m.GetChooserName() == "GroundMeasureTemporary") {
2288 m_editPoint->Delete(&m);
2289 }
2290 }
2291 loadPoint();
2292 m_groundSourceCombo->setEnabled(false);
2293 m_radiusSourceCombo->setEnabled(false);
2295 }
2296 // Changing from Free to Constrained or Fixed, loadGroundMeasure,which will create temporary
2297 // gound measure, load into the measure combo boxes and colorize Save CP button.
2298 else if (oldType == ControlPoint::Free && m_editPoint->GetType() != ControlPoint::Free) {
2300 m_groundSourceCombo->setEnabled(true);
2301 m_radiusSourceCombo->setEnabled(true);
2303 }
2304 }
2305
2306
2317
2318 if (m_editPoint == NULL) return;
2319
2320 m_editPoint->SetEditLock(lock);
2322 }
2323
2324
2336
2337 if (m_editPoint == NULL) return;
2338
2339 ControlPoint::Status status = m_editPoint->SetIgnored(ignore);
2340 if (status == ControlPoint::PointLocked) {
2341 m_ignorePoint->setChecked(m_editPoint->IsIgnored());
2342 QString message = "Unable to change Ignored on point. Set EditLock ";
2343 message += " to False.";
2344 QMessageBox::critical(this, "Error", message);
2345 return;
2346 }
2348 }
2349
2350
2366
2367 if (m_editPoint->IsEditLocked()) {
2368 m_lockLeftMeasure->setChecked(m_leftMeasure->IsEditLocked());
2369 QMessageBox::warning(this, "Point Locked","Point is Edit Locked. You must un-lock point"
2370 " before changing a measure.");
2371 m_lockLeftMeasure->setChecked(m_leftMeasure->IsEditLocked());
2372 return;
2373 }
2374
2375 if (m_leftMeasure != NULL) m_leftMeasure->SetEditLock(lock);
2376
2377 // If the right chip is the same as the left chip , update the right editLock
2378 // box.
2379 if (m_rightMeasure != NULL) {
2380 if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
2381 m_rightMeasure->SetEditLock(lock);
2382 m_lockRightMeasure->setChecked(lock);
2383 }
2384 }
2385 emit measureChanged();
2386 }
2387
2388
2406
2407 if (m_leftMeasure != NULL) m_leftMeasure->SetIgnored(ignore);
2408
2409 // If the right chip is the same as the left chip , update the right
2410 // ignore box.
2411 if (m_rightMeasure != NULL) {
2412 if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
2413 m_rightMeasure->SetIgnored(ignore);
2414 m_ignoreRightMeasure->setChecked(ignore);
2415 }
2416 }
2417 emit measureChanged();
2418 }
2419
2420
2436
2437 if (m_editPoint->IsEditLocked()) {
2438 m_lockRightMeasure->setChecked(m_rightMeasure->IsEditLocked());
2439 QMessageBox::warning(this, "Point Locked","Point is Edit Locked. You must un-lock point"
2440 " before changing a measure.");
2441 m_lockRightMeasure->setChecked(m_rightMeasure->IsEditLocked());
2442 return;
2443 }
2444
2445 if (m_rightMeasure != NULL) m_rightMeasure->SetEditLock(lock);
2446
2447 // If the left chip is the same as the right chip , update the left editLock box.
2448 if (m_leftMeasure != NULL) {
2449 if (m_leftMeasure->GetCubeSerialNumber() == m_rightMeasure->GetCubeSerialNumber()) {
2450 m_leftMeasure->SetEditLock(lock);
2451 m_lockLeftMeasure->setChecked(lock);
2452 }
2453 }
2454 emit measureChanged();
2455 }
2456
2457
2476
2477 if (m_rightMeasure != NULL) m_rightMeasure->SetIgnored(ignore);
2478
2479 // If the right chip is the same as the left chip , update the right
2480 // ignore blox.
2481 if (m_leftMeasure != NULL) {
2482 if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
2483 m_leftMeasure->SetIgnored(ignore);
2484 m_ignoreLeftMeasure->setChecked(ignore);
2485 }
2486 }
2487 emit measureChanged();
2488 }
2489
2490
2501
2502 int curIndex = m_rightCombo->currentIndex();
2503 if (curIndex < m_rightCombo->count() - 1) {
2504 // update the right measure list index and select that measure
2505 m_rightCombo->setCurrentIndex(curIndex + 1);
2506 selectRightMeasure(curIndex+1);
2507 }
2508 }
2509
2510
2521
2522 int curIndex = m_rightCombo->currentIndex();
2523 if (curIndex > 0) {
2524 // update the right measure list index and select that measure
2525 m_rightCombo->setCurrentIndex(curIndex - 1);
2526 selectRightMeasure(curIndex-1);
2527 }
2528 }
2529
2530
2531
2545
2546 QString file = m_pointFiles[index];
2547 QString serial;
2548 try {
2549 serial = m_serialNumberList->serialNumber(file);
2550 }
2551 catch (IException &e) {
2552 QString message = "Make sure the correct cube is opened.\n\n";
2553 message += e.toString();
2554 QMessageBox::critical(this, "Error", message);
2555
2556 // Set index of combo back to what it was before user selected new. Find the index
2557 // of current left measure.
2558 QString file = m_serialNumberList->fileName(m_leftMeasure->GetCubeSerialNumber());
2559 int i = m_leftCombo->findText(FileName(file).name());
2560 if (i < 0) i = 0;
2561 m_leftCombo->setCurrentIndex(i);
2562 return;
2563 }
2564
2565 if (m_leftMeasure != NULL) {
2566 delete m_leftMeasure;
2567 m_leftMeasure = NULL;
2568 }
2569
2571 *m_leftMeasure = *((*m_editPoint)[serial]);
2572
2573 // If m_leftCube is not null, delete before creating new one
2574 m_leftCube.reset(new Cube(file, "r"));
2575
2576 // Update left measure of pointEditor
2577 m_measureEditor->setLeftMeasure (m_leftMeasure, m_leftCube.data(), m_editPoint->GetId());
2579 }
2580
2581
2593
2594 QString file = m_pointFiles[index];
2595
2596 QString serial;
2597 try {
2598 serial = m_serialNumberList->serialNumber(file);
2599 }
2600 catch (IException &e) {
2601 QString message = "Make sure the correct cube is opened.\n\n";
2602 message += e.toString();
2603 QMessageBox::critical(this, "Error", message);
2604
2605 // Set index of combo back to what it was before user selected new. Find the index
2606 // of current left measure.
2607 QString file = m_serialNumberList->fileName(m_rightMeasure->GetCubeSerialNumber());
2608 int i = m_rightCombo->findText(FileName(file).name());
2609 if (i < 0) i = 0;
2610 m_rightCombo->setCurrentIndex(i);
2611 return;
2612 }
2613
2614 if (m_rightMeasure != NULL) {
2615 delete m_rightMeasure;
2616 m_rightMeasure = NULL;
2617 }
2618
2620 *m_rightMeasure = *((*m_editPoint)[serial]);
2621
2622 // If m_rightCube is not null, delete before creating new one
2623 m_rightCube.reset(new Cube(file, "r"));
2624
2625 // Update left measure of pointEditor
2626 m_measureEditor->setRightMeasure (m_rightMeasure, m_rightCube.data(), m_editPoint->GetId());
2628 }
2629
2630
2649
2650 // Set editLock measure box correctly
2652 m_leftMeasure->GetCubeSerialNumber()));
2653 // Set ignore measure box correctly
2654 m_ignoreLeftMeasure->setChecked(m_leftMeasure->IsIgnored());
2655
2656 QString s = "Reference: ";
2657 if (m_editPoint->IsReferenceExplicit() &&
2658 (QString(m_leftMeasure->GetCubeSerialNumber()) == m_editPoint->GetReferenceSN())) {
2659 s += "True";
2660 }
2661 else {
2662 s += "False";
2663 }
2664 m_leftReference->setText(s);
2665
2666 s = "Measure Type: ";
2667 if (m_leftMeasure->GetType() == ControlMeasure::Candidate) s += "Candidate";
2668 if (m_leftMeasure->GetType() == ControlMeasure::Manual) s += "Manual";
2669 if (m_leftMeasure->GetType() == ControlMeasure::RegisteredPixel) s += "RegisteredPixel";
2670 if (m_leftMeasure->GetType() == ControlMeasure::RegisteredSubPixel) s += "RegisteredSubPixel";
2671 m_leftMeasureType->setText(s);
2672 }
2673
2674
2695
2696 // Set editLock measure box correctly
2698 m_rightMeasure->GetCubeSerialNumber()));
2699 // Set ignore measure box correctly
2700 m_ignoreRightMeasure->setChecked(m_rightMeasure->IsIgnored());
2701
2702 QString s = "Reference: ";
2703 if (m_editPoint->IsReferenceExplicit() &&
2704 (QString(m_rightMeasure->GetCubeSerialNumber()) == m_editPoint->GetReferenceSN())) {
2705 s += "True";
2706 }
2707 else {
2708 s += "False";
2709 }
2710
2711 m_rightReference->setText(s);
2712
2713 s = "Measure Type: ";
2714 if (m_rightMeasure->GetType() == ControlMeasure::Candidate) s+= "Candidate";
2715 if (m_rightMeasure->GetType() == ControlMeasure::Manual) s+= "Manual";
2716 if (m_rightMeasure->GetType() == ControlMeasure::RegisteredPixel) s+= "RegisteredPixel";
2717 if (m_rightMeasure->GetType() == ControlMeasure::RegisteredSubPixel) s+= "RegisteredSubPixel";
2718 m_rightMeasureType->setText(s);
2719 }
2720
2721
2722
2734
2735 if(e->type() != QEvent::Leave) return false;
2736 if(o == m_leftCombo->view()) {
2738 m_leftCombo->hidePopup();
2739 }
2740 if (o == m_rightCombo->view()) {
2742 m_rightCombo->hidePopup();
2743 }
2744 return true;
2745 }
2746
2747
2755
2756 if (m_templateModified) {
2757 int r = QMessageBox::warning(this, tr("OK to continue?"),
2758 tr("The currently opened registration template has been modified.\n"
2759 "Save changes?"),
2760 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
2761 QMessageBox::Yes);
2762
2763 if (r == QMessageBox::Yes)
2765 else if (r == QMessageBox::Cancel)
2766 return false;
2767 }
2768
2769 return true;
2770 }
2771
2772
2779
2780 if (!okToContinue())
2781 return;
2782
2783 QString filename = QFileDialog::getOpenFileName(this,
2784 "Select a registration template", ".",
2785 "Registration template files (*.def *.pvl);;All files (*)");
2786
2787 if (filename.isEmpty())
2788 return;
2789
2790 if (m_measureEditor->setTemplateFile(filename)) {
2791 loadTemplateFile(filename);
2792 }
2793 }
2794
2795
2802
2803 QFile file(FileName((QString) fn).expanded());
2804 if (!file.open(QIODevice::ReadOnly)) {
2805 QString msg = "Failed to open template file \"" + fn + "\"";
2806 QMessageBox::warning(this, "IO Error", msg);
2807 return;
2808 }
2809
2810 QTextStream stream(&file);
2811 m_templateEditor->setText(stream.readAll());
2812 file.close();
2813
2814 QScrollBar * sb = m_templateEditor->verticalScrollBar();
2815 sb->setValue(sb->minimum());
2816
2817 m_templateModified = false;
2818 m_saveTemplateFile->setEnabled(false);
2819 }
2820
2821
2826
2827 m_templateModified = true;
2828 m_saveTemplateFile->setEnabled(true);
2829 }
2830
2831
2836
2837 if (!m_templateModified)
2838 return;
2839
2840 QString filename =
2841 m_measureEditor->templateFileName();
2842
2843 writeTemplateFile(filename);
2844 }
2845
2846
2851
2852 QString filename = QFileDialog::getSaveFileName(this,
2853 "Save registration template", ".",
2854 "Registration template files (*.def *.pvl);;All files (*)");
2855
2856 if (filename.isEmpty())
2857 return;
2858
2859 writeTemplateFile(filename);
2860 }
2861
2862
2869
2870 QString contents = m_templateEditor->toPlainText();
2871
2872 // catch errors in Pvl format when populating pvl object
2873 stringstream ss;
2874 ss << contents;
2875 try {
2876 Pvl pvl;
2877 ss >> pvl;
2878 }
2879 catch(IException &e) {
2880 QString message = e.toString();
2881 QMessageBox::warning(this, "Error", message);
2882 return;
2883 }
2884
2885 QString expandedFileName(FileName((QString) fn).expanded());
2886
2887 QFile file(expandedFileName);
2888
2889 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
2890 QString msg = "Failed to save template file to \"" + fn + "\"\nDo you "
2891 "have permission?";
2892 QMessageBox::warning(this, "IO Error", msg);
2893 return;
2894 }
2895
2896 // now save contents
2897 QTextStream stream(&file);
2898 stream << contents;
2899 file.close();
2900
2901 if (m_measureEditor->setTemplateFile(fn)) {
2902 m_templateModified = false;
2903 m_saveTemplateFile->setEnabled(false);
2904 }
2905 }
2906
2907
2921
2922 try{
2923 // Get the template file from the ControlPointEditWidget object
2924 Pvl templatePvl(m_measureEditor->templateFileName());
2925 // Create registration dialog window using PvlEditDialog class
2926 // to view and/or edit the template
2927 PvlEditDialog registrationDialog(templatePvl);
2928 registrationDialog.setWindowTitle("View or Edit Template File: "
2929 + templatePvl.fileName());
2930 registrationDialog.resize(550,360);
2931 registrationDialog.exec();
2932 }
2933 catch (IException &e) {
2934 QString message = e.toString();
2935 QMessageBox::information(this, "Error", message);
2936 }
2937 }
2938
2939
2947
2948 m_measureEditor->saveChips();
2949 }
2950
2951
2956
2958 return;
2959
2960 m_templateEditorWidget->setVisible(!m_templateEditorWidget->isVisible());
2961 }
2962
2963
2970 if(templateList->type() == "registrations") {
2971 for(int i = 0; i < templateList->size(); i++) {
2972 m_templateComboBox->addItem(templateList->at(i)->importName()
2973 + "/" + FileName(templateList->at(i)->fileName()).name());
2974 }
2975 }
2976 }
2977
2978
2987 QString expandedFileName = filename;
2988 if(!filename.startsWith("$base")){
2989 expandedFileName = m_directory->project()->templateRoot()
2990 + "/registrations/" + filename;
2991 }
2992 if (m_measureEditor->setTemplateFile(expandedFileName)) {
2993 loadTemplateFile(expandedFileName);
2994 }
2995 }
2996
2997
3005 if(fileName.startsWith("$base")) {
3006 m_templateComboBox->setCurrentIndex(0);
3007 }
3008 QList<QString> components = fileName.split("/");
3009 int size = components.size();
3010 int index = m_templateComboBox->findText(components[size - 2] + "/" + components[size - 1]);
3011 if (index != -1) {
3012 m_templateComboBox->setCurrentIndex(index);
3013 }
3014 }
3015
3016
3029
3030 QString s;
3031
3032 SurfacePoint aprioriPoint = m_editPoint->GetAprioriSurfacePoint();
3033 if (aprioriPoint.GetLatitude().degrees() == Null) {
3034 s = "Apriori Latitude: Null";
3035 }
3036 else {
3037 s = "Apriori Latitude: " +
3038 QString::number(aprioriPoint.GetLatitude().degrees());
3039 }
3040 m_aprioriLatitude->setText(s);
3041 if (aprioriPoint.GetLongitude().degrees() == Null) {
3042 s = "Apriori Longitude: Null";
3043 }
3044 else {
3045 s = "Apriori Longitude: " +
3046 QString::number(aprioriPoint.GetLongitude().degrees());
3047 }
3048 m_aprioriLongitude->setText(s);
3049 if (aprioriPoint.GetLocalRadius().meters() == Null) {
3050 s = "Apriori Radius: Null";
3051 }
3052 else {
3053 s = "Apriori Radius: " +
3054 QString::number(aprioriPoint.GetLocalRadius().meters(),'f',2) +
3055 " <meters>";
3056 }
3057 m_aprioriRadius->setText(s);
3058 }
3059
3060
3076// TODO Is this needed?
3077//
3078// void ControlPointEditWidget::refresh() {
3079//
3080// // Check point being edited, make sure it still exists, if not ???
3081// // Update ignored checkbox??
3082// if (m_editPoint != NULL) {
3083// try {
3084// QString id = m_ptIdValue->text().remove("Point ID: ");
3085// m_controlNet->GetPoint(id);
3086// }
3087// catch (IException &) {
3088// delete m_editPoint;
3089// m_editPoint = NULL;
3090// emit controlPointChanged();
3093// }
3094// }
3095// }
3096
3097
3104
3105 QColor qc = Qt::red;
3106 QPalette p = m_savePoint->palette();
3107 p.setColor(QPalette::ButtonText,qc);
3108 m_savePoint->setPalette(p);
3109 }
3110
3111
3121
3122 if (reset) {
3123 // Change Save Net button text back to default black
3124 m_saveNet->setPalette(m_saveDefaultPalette);
3125 }
3126 else {
3127 QColor qc = Qt::red;
3128 QPalette p = m_savePoint->palette();
3129 p.setColor(QPalette::ButtonText,qc);
3130 m_saveNet->setPalette(p);
3131 }
3132
3133 }
3134
3135
3147 bool ControlPointEditWidget::IsMeasureLocked (QString serialNumber) {
3148
3149 if (m_editPoint == NULL) return false;
3150
3151 // Reference implicitly editLocked
3152 if (m_editPoint->IsEditLocked() && m_editPoint->IsReferenceExplicit() &&
3153 (m_editPoint->GetReferenceSN() == serialNumber)) {
3154 return true;
3155 }
3156 // Return measures explicit editLocked value
3157 else {
3158 return m_editPoint->GetMeasure(serialNumber)->IsEditLocked();
3159 }
3160
3161 }
3162
3163
3172
3173 m_control->write();
3174
3175 // Change Save Measure button text back to default
3176 m_saveNet->setPalette(m_saveDefaultPalette);
3177 }
3178
3179
3184 delete m_editPoint;
3185 m_editPoint = NULL;
3186 }
3187
3188
3189 // 2014-07-21 TLS Ipce This needs to be changed to return the help information or
3190 // widget?? to the calling program, so that it can be added to a menu or toolbar.
3191#if 0
3192 void ControlPointEditWidget::showHelp() {
3193
3194 QDialog *helpDialog = new QDialog(this);
3195 helpDialog->setWindowTitle("Match Tool Help");
3196
3197 QVBoxLayout *mainLayout = new QVBoxLayout;
3198 helpDialog->setLayout(mainLayout);
3199
3200 QLabel *matchTitle = new QLabel("<h2>Match Tool</h2>");
3201 mainLayout->addWidget(matchTitle);
3202
3203 QLabel *matchSubtitle = new QLabel("A tool for interactively measuring and editing sample/line "
3204 "registration points between cubes. These "
3205 "points contain sample, line postions only, no latitude or "
3206 "longitude values are used or recorded.");
3207 matchSubtitle->setWordWrap(true);
3208 mainLayout->addWidget(matchSubtitle);
3209
3210 QTabWidget *tabArea = new QTabWidget;
3211 tabArea->setDocumentMode(true);
3212 mainLayout->addWidget(tabArea);
3213
3214 // TAB 1 - Overview
3215 QScrollArea *overviewTab = new QScrollArea;
3216 overviewTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
3217 overviewTab->setWidgetResizable(true);
3218 QWidget *overviewContainer = new QWidget;
3219 QVBoxLayout *overviewLayout = new QVBoxLayout;
3220 overviewContainer->setLayout(overviewLayout);
3221
3222 QLabel *purposeTitle = new QLabel("<h2>Purpose</h2>");
3223 overviewLayout->addWidget(purposeTitle);
3224
3225 QLabel *purposeText = new QLabel("<p>This tool is for recording and editing registration "
3226 "points measured between cubes displayed in the <i>qview</i> main window.</p> <p>The "
3227 "recorded registration points are sample and line pixel coordinates only. Therefore, this "
3228 "tool can be used on any images including ones that do not contain a camera model "
3229 "(i.e, The existence of the Isis Instrument Group on the image labels is not required). "
3230 "This also means that the tool differs from the <i>qnet</i> control point network "
3231 "application in that no latitude or longitude values are ever used or recorded "
3232 "(regardless if the image has a camera model in Isis).</p>"
3233 "<p>The output control point network that this tool generates is primarily used 1) as "
3234 "input for an image-wide sample/line translation to register one image to another by "
3235 "'moving' pixel locations - refer to the documentation for applications such as "
3236 "<i>translate</i> and <i>warp</i>, or 2) to export the file and use the recorded "
3237 "measurements in other spreadsheet or plotting packages to visualize magnitude "
3238 "and direction of varying translations of the images relative to one another.</p> "
3239 "<p>An automated version of this match tool is the <i>coreg</i> application. This tool "
3240 "can be used to visually evaluate and edit the control point network created by "
3241 "<i>coreg</i>.</p> "
3242 "<p>The format of the output point network file is binary. This tool uses the Isis control "
3243 " network framework to create, co-register and save all control points and pixel "
3244 "measurements. The application <i>cnetbin2pvl</i> can be used to convert from binary to "
3245 "a readable PVL format."
3246 "<p>The Mouse Button functions are: (same as <i>qnet</i>)<ul><li>Modify Point=Left</li> "
3247 "<li>Delete Point=Middle</li><li>Create New Point=Right</li></ul></p>"
3248 "<p>Control Points are drawn on the associated displayed cubes with the following colors: "
3249 "Green=Valid registration point; Yellow=Ignored point; Red=Active point being edited");
3250 purposeText->setWordWrap(true);
3251 overviewLayout->addWidget(purposeText);
3252
3253 overviewTab->setWidget(overviewContainer);
3254
3255 // TAB 2 - Quick Start
3256 QScrollArea *quickTab = new QScrollArea;
3257 quickTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
3258 quickTab->setWidgetResizable(true);
3259 QWidget *quickContainer = new QWidget;
3260 QVBoxLayout *quickLayout = new QVBoxLayout;
3261 quickContainer->setLayout(quickLayout);
3262
3263 QLabel *quickTitle = new QLabel("<h2>Quick Start</h2>");
3264 quickLayout->addWidget(quickTitle);
3265
3266 QLabel *quickSubTitle = new QLabel("<h3>Preparation:</h3>");
3267 quickLayout->addWidget(quickSubTitle);
3268
3269 QString toolIconDir = FileName("$base/icons").expanded();
3270
3271 QLabel *quickPrep = new QLabel("<p><ul>"
3272 "<li>Open the cubes with overlapping areas for choosing control points</li>"
3273 "<li>Choose the match tool <img src=\"" + toolIconDir +
3274 "/stock_draw-connector-with-arrows.png\" width=22 height=22> "
3275 "from the toolpad on the right side of the <i>qview</i> main window</li>");
3276 quickPrep->setWordWrap(true);
3277 quickLayout->addWidget(quickPrep);
3278
3279 QLabel *morePrep = new QLabel("<p>Once the Match tool is activated the tool bar at the top "
3280 "of the main window contains file action buttons and a help button:");
3281 morePrep->setWordWrap(true);
3282 quickLayout->addWidget(morePrep);
3283
3284 QLabel *fileButtons = new QLabel("<p><ul>"
3285 "<li><img src=\"" + toolIconDir + "/fileopen.png\" width=22 height=22> Open an existing "
3286 "control network <b>Note:</b> If you do not open an existing network, a new one will "
3287 "be created</li>"
3288 "<li><img src=\"" + toolIconDir + "/mActionFileSaveAs.png\" width=22 height=22> Save "
3289 "control network as ...</li>"
3290 "<li><img src=\"" + toolIconDir + "/mActionFileSave.png\" width=22 height=22> Save "
3291 "control network to current file</li>"
3292 "<li><img src=\"" + toolIconDir + "/help-contents.png\" width=22 height=22> Show Help "
3293 "</li></ul></p>");
3294 fileButtons->setWordWrap(true);
3295 quickLayout->addWidget(fileButtons);
3296
3297 QLabel *quickFunctionTitle = new QLabel("<h3>Cube Viewport Functions:</h3>");
3298 quickLayout->addWidget(quickFunctionTitle);
3299
3300 QLabel *quickFunction = new QLabel(
3301 "The match tool window will be shown once "
3302 "you click in a cube viewport window using one of the following "
3303 "mouse functions. <b>Note:</b> Existing control points are drawn on the cube viewports");
3304 quickFunction->setWordWrap(true);
3305 quickLayout->addWidget(quickFunction);
3306
3307 QLabel *quickDesc = new QLabel("<p><ul>"
3308 "<li>Left Click - Modify the control point closest to the click <b>Note:</b> "
3309 "All cubes in the control point must be displayed before loading the point</li>"
3310 "<li>Middle Click - Delete the control point closest to the click</li>"
3311 "<li>Right Click - Create a new control point at the click location</li></ul></p>");
3312 quickDesc->setWordWrap(true);
3313 quickDesc->setOpenExternalLinks(true);
3314 quickLayout->addWidget(quickDesc);
3315
3316 quickTab->setWidget(quickContainer);
3317
3318 // TAB 3 - Control Point Editing
3319 QScrollArea *controlPointTab = new QScrollArea;
3320 controlPointTab->setWidgetResizable(true);
3321 controlPointTab->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
3322 QWidget *controlPointContainer = new QWidget;
3323 QVBoxLayout *controlPointLayout = new QVBoxLayout;
3324 controlPointContainer->setLayout(controlPointLayout);
3325
3326 QLabel *controlPointTitle = new QLabel("<h2>Control Point Editing</h2>");
3327 controlPointLayout->addWidget(controlPointTitle);
3328
3329 QLabel *mouseLabel = new QLabel("<p><h3>When the \"Match\" tool "
3330 "is activated, the mouse buttons have the following function in the "
3331 "cube viewports of the main qview window:</h3>");
3332 mouseLabel->setWordWrap(true);
3333 mouseLabel->setScaledContents(true);
3334 controlPointLayout->addWidget(mouseLabel);
3335
3336 QLabel *controlPointDesc = new QLabel("<ul>"
3337 "<li>Left click - Edit the closest control point <b>Note:</b> "
3338 "All cubes in the control point must be displayed before loading the point</li>"
3339 "<li>Middle click - Delete the closest control point</li>"
3340 "<li>Right click - Create new control point at cursor location. This will bring up a new "
3341 "point dialog which allows you to enter a point id and will list all cube viewports, "
3342 "highlighting cubes where the point has been chosen by clicking on the cube's viewport. "
3343 "When the desired cubes have been chosen, select the \"Done\" button which will load the "
3344 "control point into the control point editor window which will allow the control measure "
3345 "positions to be refined.</li>");
3346 controlPointDesc->setWordWrap(true);
3347 controlPointLayout->addWidget(controlPointDesc);
3348
3349 QLabel *controlPointEditing = new QLabel(
3350 "<h4>Changing Control Measure Locations</h4>"
3351 "<p>Both the left and right control measure positions can be adjusted by:"
3352 "<ul>"
3353 "<li>Move the cursor location under the crosshair by clicking the left mouse "
3354 "button</li>"
3355 "<li>Move 1 pixel at a time by using arrow keys on the keyboard</li>"
3356 "<li>Move 1 pixel at a time by using arrow buttons above the right and left views</li>"
3357 "</ul></p>"
3358 "<h4>Other Point Editor Functions</h4>"
3359 "<p>Along the right border of the window:</p>"
3360 "<ul>"
3361 "<li><strong>Link Zoom</strong> This will link the two small viewports together when "
3362 "zooming (ie. If this is checked, if the left view is zoomed, the right view will "
3363 "match the left view's zoom factor. "
3364 "<b>Note:</b> Zooming is controlled from the left view.</li>"
3365 "<li><strong>No Rotate:</strong> Turn off the rotation and bring right view back to "
3366 "its original orientation</li>"
3367 "<li><strong>Rotate:</strong> Rotate the right view using either the dial "
3368 "or entering degrees </li>"
3369 "<li><strong>Show control points:</strong> Draw crosshairs at all control "
3370 "point locations visible within the view</li>"
3371 "<li><strong>Show crosshair:</strong> Show a red crosshair across the entire "
3372 "view</li>"
3373 "<li><strong>Circle:</strong> Draw circle which may help center measure "
3374 "on a crater</li></ul"
3375 "<p>Below the left view:</p>"
3376 "<ul><li><strong>Blink controls:</strong> Blink the left and right view in the "
3377 "left view window using the \"Blink Start\" button <img src=\"" + toolIconDir +
3378 "/blinkStart.png\" width=22 height=22> and \"Blink Stop\" button <img src=\"" +
3379 toolIconDir + "/blinkStop.png\" width=22 height=22>. The arrow keys above the left "
3380 "and right views and the keyboard arrow keys may be used to move the both views while "
3381 "blinking.</li>"
3382 "<li><strong>Register:</strong> Sub-pixel register the right view to "
3383 "the left view. A default registration template is used for setting parameters "
3384 "passed to the sub-pixel registration tool. The user may load in a predefined "
3385 "template or edit the current loaded template to influence successful "
3386 "co-registration results. For more information regarding the pattern matching "
3387 "functionlity or how to create a parameter template, refer to the Isis PatternMatch "
3388 "document and the <i>autoregtemplate</i> application.</li>"
3389 "<li><strong>Save Measures:</strong> Save the two control measures using the sample, "
3390 "line positions under the crosshairs.</li>"
3391 "<li><strong>Save Point:</strong> Save the control point to the control network.</li>"
3392 "</ul>");
3393 controlPointEditing->setWordWrap(true);
3394 controlPointLayout->addWidget(controlPointEditing);
3395
3396 controlPointTab->setWidget(controlPointContainer);
3397
3398 tabArea->addTab(overviewTab, "&Overview");
3399 tabArea->addTab(quickTab, "&Quick Start");
3400 tabArea->addTab(controlPointTab, "&Control Point Editing");
3401
3402 QHBoxLayout *buttonsLayout = new QHBoxLayout;
3403 // Flush the buttons to the right
3404 buttonsLayout->addStretch();
3405
3406 QPushButton *closeButton = new QPushButton("&Close");
3407 closeButton->setIcon(QIcon(FileName("$base/icons/guiStop.png").expanded()));
3408 closeButton->setDefault(true);
3409 connect(closeButton, SIGNAL(clicked()),
3410 helpDialog, SLOT(close()));
3411 buttonsLayout->addWidget(closeButton);
3412
3413 mainLayout->addLayout(buttonsLayout);
3414
3415 helpDialog->show();
3416 }
3417#endif
3418}
This is free and unencumbered software released into the public domain.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
static QString UserName()
Returns the user name.
This represents an ISIS control net in a project-based GUI interface.
Definition Control.h:66
ControlNet * controlNet()
Open and return a pointer to the ControlNet for this Control.
Definition Control.cpp:150
QString fileName() const
Access the name of the control network file associated with this Control.
Definition Control.cpp:272
a control measurement
Status SetCubeSerialNumber(QString newSerialNumber)
Set cube serial number.
@ Manual
Hand Measured (e.g., qnet)
@ Candidate
(e.g., autoseed, interest) AKA predicted, unmeasured, unverified
@ RegisteredSubPixel
Registered to sub-pixel (e.g., pointreg)
@ RegisteredPixel
Registered to whole pixel (e.g.,pointreg)
a control network
Definition ControlNet.h:258
QPointer< QComboBox > m_templateComboBox
ComboBox of imported registration templates.
void setLockLeftMeasure(bool ignore)
Set the "EditLock" keyword of the measure shown in the left viewport to the value of the input parame...
void saveTemplateFileAs()
Save the contents of template editor to a file chosen by the user.
bool m_addMeasuresButton
Indicates whether or not to add "Add Measures(s) to Point".
void deletePoint(ControlPoint *controlPoint)
Gives user options for deleting a control point from the control network.
void setLockRightMeasure(bool ignore)
Set the "EditLock" keyword of the measure shown in the right viewport to the value of the input param...
QPointer< Control > m_control
Current Control.
QPointer< QLabel > m_rightMeasureType
Label for the right measure's adjustment type.
QPointer< QCheckBox > m_ignorePoint
Checkbox to ignore the current point.
void setIgnoreRightMeasure(bool ignore)
Set the "Ignore" keyword of the measure shown in the right viewport to the value of the input paramet...
void previousRightMeasure()
Selects the previous right measure when activated by key shortcut.
QPointer< ControlPoint > m_editPoint
The control point being edited.
void checkReference()
Change which measure is the reference.
void updateRightMeasureInfo()
Update the right measure information.
void colorizeSaveNetButton(bool reset=false)
Turn "Save Net" button text to red.
QPointer< QPushButton > m_reloadPoint
Button to reload current point to saved measures.
QPointer< QComboBox > m_rightCombo
Combobox to load right measure into right chip viewport.
bool m_changeAllGroundLocation
Change the ground source location of all fixed, constrained points in the network.
bool IsMeasureLocked(QString serialNumber)
Check for implicitly locked measure in m_editPoint.
void setEditPoint(ControlPoint *controlPoint, QString serialNumber="")
Slot called by Directory to set the control point for editing.
QPointer< QWidget > m_parent
Parent widget.
QPointer< QCheckBox > m_lockLeftMeasure
Checkbox to edit lock/unlock the left measure.
QPointer< QPushButton > m_saveNet
Button to save the current control network.
bool okToContinue()
Checks the state of the template registration file and determines if it is safe to continue opening a...
void resetTemplateComboBox(QString fileName)
Reset the selected template in the template combobox if the template selected by the user does not sa...
bool validateMeasureChange(ControlMeasure *m)
Validates a change to a control measure.
void setShapesForPoint(double latitude=Null, double longitude=Null)
Fill m_projectShapeNames with ALL shapes currently in project.
QPointer< ControlMeasureEditWidget > m_measureEditor
Pointer to control measure editor widget.
bool m_templateModified
Indicates if the registration template was edited.
QPointer< QAction > m_saveTemplateFile
Action to save a registration template file to disk.
QPointer< QComboBox > m_pointTypeCombo
Combobox to change the type of the current point.
QPointer< ControlMeasure > m_leftMeasure
Left control measure.
QString m_cnetFileName
Filename of the control network that is being modified.
bool setGroundSourceInfo()
Find the ground source location: First look at current edit point for parameter, AprioriXYZSourceFile...
void changeGroundLocationsInNet()
Change the location of all ground source locations in the ControlNet.
QPointer< QLabel > m_cnetFileNameLabel
Label with name of the control network file.
void setControl(Control *control)
New control network being edited.
QPointer< QComboBox > m_leftCombo
Combobox to load left measure into left chip viewport.
void initDem(QString demFile)
Initialize the given Dem and appropriate member variables for later use editing Fixed or Constrained ...
void saveChips()
Slot which calls ControlPointEditWidget slot to save chips.
QPointer< QCheckBox > m_ignoreLeftMeasure
Checkbox to ignore the left measure.
QString m_groundSN
Serial number of ground source file.
ControlMeasure * createTemporaryGroundMeasure()
Create a temporary measure to hold the ground point info for ground source.
void setSerialNumberList(SerialNumberList *snList)
Set the serial number list.
SerialNumberList * m_serialNumberList
Serial number list for the loaded cubes.
QPointer< QComboBox > m_radiusSourceCombo
ComboBox for selecting ground source.
void loadGroundMeasure()
Load ground measure into right side and add to file combo boxes.
void createControlPoint(double latitude, double longitude, Cube *cube=0, bool isGroundSource=false)
Create a new control point at the given latitude, longitude.
QPointer< QTextEdit > m_templateEditor
Text editor for editing the registration template.
void saveTemplateFile()
Save the file opened in the template editor.
QPointer< QCheckBox > m_lockRightMeasure
Checkbox to edit lock/unlock the right measure.
void createActions()
Creates the actions for the widget.
void addTemplates(TemplateList *templateList)
Add registration TemplateList to combobox when imported to project.
void viewTemplateFile()
Allows the user to view the template file that is currently set.
QStringList m_pointFiles
Associated files for current control point.
void measureSaved()
This method is connected with the measureSaved() signal from ControlMeasureEditWidget.
void openReferenceRadius()
Open a radius source using the shape model of the reference measure of m_editPoint.
FileName checkGroundFileLocation(FileName groundFile)
Ground source file from control net cannot be found, give user option to give new location.
bool m_cnetModified
Indicates if the control network has been modified.
void savePoint()
Save edit point to the Control Network.
void clearGroundSource()
Clear out the ground source used for Constrained or Fixed control points.
void setControlFromActive()
New active control was set from ipce.
void setPointType(int pointType)
Set the point type.
int m_numberProjectShapesWithPoint
Number of shapes containing control point.
void setTemplateFile(QString)
Appends the filename to the registrations path (unless this is the default template) and calls setTem...
QPointer< QAction > m_saveTemplateFileAs
Action to save a new registration template.
bool m_changeGroundLocationInNet
Change the ground source location.
QPointer< QAction > m_openTemplateFile
Action to open a registration template file to disk.
void setIgnorePoint(bool ignore)
Set point's "Ignore" keyword to the value of the input parameter.
void clearEditPoint()
Cleans up the edit point memory.
void reloadPoint()
Set both chip viewports to their original measures for the control point.
void loadPoint(QString serialNumber="")
Load point into ControlPointEditWidget.
void colorizeSavePointButton()
Refresh all necessary widgets in ControlPointEditWidget including the PointEditor and CubeViewports.
void updateSurfacePointInfo()
Update the Surface Point Information in the ControlPointEditWidget.
void openTemplateFile()
Prompt user for a registration template file to open.
QMap< QString, Shape * > m_nameToShapeMap
Map between Shape display name and object.
void nextRightMeasure()
Selects the next right measure when activated by key shortcut.
void createTemplateEditorWidget()
Creates the Widget which contains the template editor and its toolbar.
void setLockPoint(bool ignore)
Set point's "EditLock" keyword to the value of the input parameter.
QPalette m_saveDefaultPalette
Default color pallet of the "Save Point" button.
void selectLeftMeasure(int index)
Select left measure.
QStringList m_projectShapeNames
List of Shapes imported into project, at time of loaded CP.
QString m_lastUsedPointId
Point id of the last used control point.
QPointer< ControlNet > m_controlNet
Current control net.
void groundSourceFileSelectionChanged(int index)
Slot called when user changes selection in m_groundSourceCombo.
void writeTemplateFile(QString)
Write the contents of the template editor to the file provided.
void selectRightMeasure(int index)
Select right measure.
QPointer< QComboBox > m_groundSourceCombo
ComboBox for selecting ground source.
QGroupBox * createLeftMeasureGroupBox()
Creates the "Left Measure" groupbox.
void setTemplateModified()
Called when the template file is modified by the template editor.
QPointer< QWidget > m_templateEditorWidget
Template editor widget.
void showHideTemplateEditor()
Toggles the visibility of the template editor widget.
void setIgnoreLeftMeasure(bool ignore)
Set the "Ignore" keyword of the measure shown in the left viewport to the value of the input paramete...
QScopedPointer< Cube > m_rightCube
Right cube.
void saveNet()
This slot is needed because we cannot directly emit a signal with a ControlNet argument after the "Sa...
QPointer< QCheckBox > m_ignoreRightMeasure
Checkbox to ignore the right measure.
QPointer< QLabel > m_rightReference
Label indicating if right measure is the reference.
bool eventFilter(QObject *o, QEvent *e)
Event filter for ControlPointEditWidget.
QString m_groundFilename
File name of ground source.
QScopedPointer< Cube > m_leftCube
Left cube.
QPointer< QAction > m_closePointEditor
Action to close the point editor.
ControlPoint::SurfacePointSource::Source m_groundSourceType
SurfacePoint type of ground source.
void updateLeftMeasureInfo()
Update the left measure information.
QPointer< ControlMeasure > m_rightMeasure
Right control measure.
QGroupBox * createControlPointGroupBox()
Creates the "Control Point" groupbox.
void loadTemplateFile(QString)
Updates the current template file being used.
QSplitter * createTopSplitter()
Creates everything above the ControlPointEdit.
QPointer< QAction > m_saveChips
Action to save the registration chips Action to toggle visibility of the registration template editor...
QGroupBox * createRightMeasureGroupBox()
Create the "Right Measure" groupbox.
QString m_newGroundDir
Contains the ground source location.
QPointer< QLabel > m_ptIdValue
Label for the point id of the current point.
QPointer< QPushButton > m_savePoint
Button to save current point being edited.
QPointer< QLabel > m_leftReference
Label indicating if left measure is the reference.
bool m_demOpen
Has a radius source been opened?
ControlPointEditWidget(Directory *directory, QWidget *parent, bool addMeasures=false)
Consructs the ControlPointEditWidget widget.
double demRadius(double latitude, double longitude)
Return a radius values from the dem using bilinear interpolation.
void createPointEditor(QWidget *parent, bool addMeasures)
Create the widget for editing control points.
QPointer< QLabel > m_leftMeasureType
Label for the left measure's adjustment type.
QPointer< QCheckBox > m_lockPoint
Checkbox that locks/unlocks the current point.
A single control point.
Status
This is a return status for many of the mutating (setter) method calls.
@ PointLocked
This is returned when the operation requires Edit Lock to be false but it is currently true.
Status SetChooserName(QString name)
Set the point's chooser name.
int Delete(ControlMeasure *measure)
Remove a measurement from the control point, deleting reference measure is allowed.
void Add(ControlMeasure *measure)
Add a measurement to the control point, taking ownership of the measure in the process.
PointType GetType() const
PointType
These are the valid 'types' of point.
@ Free
A Free point is a Control Point that identifies common measurements between two or more cubes.
Status SetType(PointType newType)
Updates the control point's type.
Status SetAprioriSurfacePointSourceFile(QString sourceFile)
This updates the filename of where the apriori surface point came from.
Status SetAprioriSurfacePointSource(SurfacePointSource::Source source)
This updates the source of the surface point.
static QString PointTypeToString(PointType type)
Obtain a string representation of a given PointType.
QString GetId() const
Return the Id of the control point.
bool HasSerialNumber(QString serialNumber) const
Return true if given serial number exists in point.
IO Handler for Isis Cubes.
Definition Cube.h:168
FileName externalCubeFileName() const
If this is an external cube label file, this will give you the cube dn file that this label reference...
Definition Cube.cpp:1541
Widget to display Isis cubes for qt apps.
Project * project() const
Gets the Project for this directory.
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
File name manipulation and expansion.
Definition FileName.h:100
bool fileExists() const
Returns true if the file exists; false otherwise.
Definition FileName.cpp:449
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
Definition FileName.cpp:162
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition FileName.cpp:196
QString toString() const
Returns a QString of the full file name including the file path, excluding the attributes with any Is...
Definition FileName.cpp:515
Isis exception class.
Definition IException.h:91
Pixel interpolator.
Dialog used by ControlPointEditWidget to select a new location for ground source files.
Buffer for containing a two dimensional section of an image.
Definition Portal.h:36
static QString templateRoot(QString projectRoot)
Appends the root directory name 'templates' to the project .
Definition Project.cpp:2124
QList< TemplateList * > regTemplates()
Return registration template FileNames.
Definition Project.cpp:2165
static QString shapeDataRoot(QString projectRoot)
Appends the root directory name 'shapes' to the project .
Definition Project.cpp:2086
Control * activeControl()
Return the Active Control (control network)
Definition Project.cpp:1902
PvlEditDialog creates a QDialog window in which a QTextEdit box displays the contents of a pvl file.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
static QString Compose(Pvl &label, bool def2filename=false)
Compose a SerialNumber from a PVL.
Serial Number list generator.
void remove(const QString &sn)
Remove the specified serial number from the list.
QString serialNumber(const QString &filename)
Return a serial number given a filename.
void add(const QString &filename, bool def2filename=false)
Adds a new filename / serial number pair to the SerialNumberList.
int size() const
How many serial number / filename combos are in the list.
int serialNumberIndex(const QString &sn)
Return a list index given a serial number.
int fileNameIndex(const QString &filename)
Return a list index given a filename.
QString fileName(const QString &sn)
Return a filename given a serial number.
This represents a shape in a project-based GUI interface.
Definition Shape.h:68
QString fileName() const
Get the file name of the cube that this shape represents.
Definition Shape.cpp:376
Cube * cube()
Get the Cube * associated with this display property.
Definition Shape.cpp:324
Internalizes a list of shapes and allows for operations on the entire list.
Definition ShapeList.h:33
Obtain SPICE information for a spacecraft.
Definition Spice.h:283
Pixel value mapper.
Definition Stretch.h:58
This class defines a body-fixed surface point.
QString type() const
Get the type of template in this TemplateList.
Universal Ground Map.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double Null
Value for an Isis Null pixel.
Namespace for the standard library.