Isis 3.0 Programmer Reference
Back | Home
QnetTool.cpp
1 #include "QnetTool.h"
2 
3 #include <sstream>
4 #include <vector>
5 #include <iomanip>
6 
7 #include <QComboBox>
8 #include <QFileDialog>
9 #include <QMenuBar>
10 #include <QMessageBox>
11 #include <QScrollBar>
12 #include <QShortcut>
13 #include <QSplitter>
14 #include <QStackedWidget>
15 #include <QtWidgets>
16 #include <QTableWidget>
17 #include <QWhatsThis>
18 
19 #include "QnetDeletePointDialog.h"
20 #include "QnetNewMeasureDialog.h"
21 #include "QnetNewPointDialog.h"
22 #include "QnetFixedPointDialog.h"
23 #include "Workspace.h"
24 
25 #include "Application.h"
26 #include "Brick.h"
27 #include "Camera.h"
28 #include "CameraFactory.h"
29 #include "ControlMeasure.h"
30 #include "ControlMeasureLogData.h"
31 #include "ControlNet.h"
32 #include "ControlPoint.h"
33 #include "ControlPointEdit.h"
34 #include "Distance.h"
35 #include "FileName.h"
36 #include "IException.h"
37 #include "Latitude.h"
38 #include "Longitude.h"
39 #include "MainWindow.h"
40 #include "MdiCubeViewport.h"
41 #include "Projection.h"
42 #include "ProjectionFactory.h"
43 #include "Pvl.h"
44 #include "PvlEditDialog.h"
45 #include "SerialNumber.h"
46 #include "SpecialPixel.h"
47 #include "Spice.h"
48 #include "SurfacePoint.h"
49 #include "Target.h"
50 #include "ToolPad.h"
51 #include "UniversalGroundMap.h"
52 #include "ViewportMainWindow.h"
53 
54 using namespace std;
55 
56 namespace Isis {
57 
67  QnetTool::QnetTool (QWidget *parent) : Tool(parent) {
68  m_controlNet = NULL;
69  m_demOpen = false;
70  m_groundOpen = false;
71  m_serialNumberList = NULL;
72  m_templateModified = false;
73 
74  m_controlNet = new ControlNet;
75  m_serialNumberList = new SerialNumberList;
76 
77  if (qobject_cast<Workspace *>(parent)) {
78  m_workspace = qobject_cast<Workspace *>(parent);
79  }
80  else if (qobject_cast<ViewportMainWindow *>(parent)) {
81  m_workspace = qobject_cast<ViewportMainWindow *>(parent)->workspace();
82  }
83  else {
85  tr("Could not find the workspace with the given parent, expected a Workspace or "
86  "ViewportMainWindow."),
87  _FILEINFO_);
88  }
89 
90  createQnetTool(parent);
91  }
92 
93 
94  QnetTool::~QnetTool () {
95  writeSettings();
96 
97  delete m_editPoint;
98  delete m_leftMeasure;
99  delete m_rightMeasure;
100  delete m_measureTable;
101  delete m_measureWindow;
102  }
103 
104 
105 
132 
133  m_qnetTool = new MainWindow("Qnet Tool", parent);
134  m_qnetTool->setObjectName("QnetTool");
135 
136  createActions();
137  createMenus();
138  createToolBars();
139 
140  // create m_pointEditor first since we need to get its templateFileName
141  // later
142  m_pointEditor = new ControlPointEdit(m_controlNet, parent);
143  connect(this, SIGNAL(newControlNetwork(ControlNet *)),
144  m_pointEditor, SIGNAL(newControlNetwork(ControlNet *)));
145  connect(this,
146  SIGNAL(stretchChipViewport(Stretch *, CubeViewport *)),
147  m_pointEditor,
148  SIGNAL(stretchChipViewport(Stretch *, CubeViewport *)));
149  connect(m_pointEditor, SIGNAL(measureSaved()), this, SLOT(measureSaved()));
150  connect(this, SIGNAL(measureChanged()),
151  m_pointEditor, SLOT(colorizeSaveButton()));
152 
153  QPushButton *addMeasure = new QPushButton("Add Measure(s) to Point");
154  addMeasure->setShortcut(Qt::Key_A);
155  addMeasure->setToolTip("Add a new measure to the edit control point. "
156  "<strong>Shortcut: A</strong>");
157  addMeasure->setWhatsThis("This allows a new control measure to be added "
158  "to the currently edited control point. A selection "
159  "box with all cubes from the input list will be "
160  "displayed with those that intersect with the "
161  "control point highlighted.");
162  connect(addMeasure, SIGNAL(clicked()), this, SLOT(addMeasure()));
163 
164  m_savePoint = new QPushButton ("Save Point");
165  m_savePoint->setShortcut(Qt::Key_P);
166  m_savePoint->setToolTip("Save the edit control point to the control network. "
167  "<strong>Shortcut: P</strong>");
168  m_savePoint->setWhatsThis("Save the edit control point to the control "
169  "network which is loaded into memory in its entirety. "
170  "When a control point is selected for editing, "
171  "a copy of the point is made so that the original control "
172  "point remains in the network.");
173  m_saveDefaultPalette = m_savePoint->palette();
174  connect (m_savePoint,SIGNAL(clicked()),this,SLOT(savePoint()));
175 
176  QHBoxLayout * addMeasureLayout = new QHBoxLayout;
177  addMeasureLayout->addWidget(addMeasure);
178  addMeasureLayout->addWidget(m_savePoint);
179 // addMeasureLayout->addStretch();
180 
181  m_templateFileNameLabel = new QLabel("Template File: " +
182  m_pointEditor->templateFileName());
183  m_templateFileNameLabel->setToolTip("Sub-pixel registration template File.");
184 // QString patternMatchDoc =
185 // FileName("$ISISROOT/doc/documents/PatternMatch/PatternMatch.html").fileName();
186 // m_templateFileNameLabel->setOpenExternalLinks(true);
187  m_templateFileNameLabel->setWhatsThis("FileName of the sub-pixel "
188  "registration template. Refer to $ISISROOT/doc/documents/"
189  "PatternMatch/PatternMatch.html for a description of the "
190  "contents of this file.");
191 
192  m_groundFileNameLabel = new QLabel("Ground Source File: ");
193  m_groundFileNameLabel->setToolTip("Cube used to create ground control "
194  "points, either Fixed or Constrained.");
195  m_groundFileNameLabel->setWhatsThis("This cube is used to create ground "
196  "control points, Fixed or Constrained. This may "
197  "be a Dem, a shaded relief version of a Dem, "
198  "a projected basemap or an unprojected cube with "
199  "corrected camera pointing. This will be used "
200  "to set the apriori latitude, longitude.");
201  m_radiusFileNameLabel = new QLabel("Radius Source: ");
202  m_radiusFileNameLabel->setToolTip("Dem used to set the radius of ground "
203  "control points, Fixed or Constrained. This must "
204  "be a Dem and is strictly used to set the apriori "
205  "radius for ground control points.");
206 
207  QVBoxLayout * centralLayout = new QVBoxLayout;
208 
209  centralLayout->addWidget(m_templateFileNameLabel);
210  centralLayout->addWidget(m_groundFileNameLabel);
211  centralLayout->addWidget(m_radiusFileNameLabel);
212  centralLayout->addWidget(createTopSplitter());
213  centralLayout->addStretch();
214  centralLayout->addWidget(m_pointEditor);
215  centralLayout->addLayout(addMeasureLayout);
216  QWidget * centralWidget = new QWidget;
217  centralWidget->setLayout(centralLayout);
218 
219  QScrollArea *scrollArea = new QScrollArea();
220  scrollArea->setObjectName("QnetToolScroll");
221  scrollArea->setWidget(centralWidget);
222  scrollArea->setWidgetResizable(true);
223  centralWidget->adjustSize();
224  m_qnetTool->setCentralWidget(scrollArea);
225 // m_qnetTool->setCentralWidget(centralWidget);
226 
227 
228  connect(this, SIGNAL(editPointChanged(QString)),
229  this, SLOT(paintAllViewports(QString)));
230 
231  readSettings();
232  }
233 
234 
237 
238  QHBoxLayout * measureLayout = new QHBoxLayout;
239  measureLayout->addWidget(createLeftMeasureGroupBox());
240  measureLayout->addWidget(createRightMeasureGroupBox());
241 
242  QVBoxLayout * groupBoxesLayout = new QVBoxLayout;
243  groupBoxesLayout->addWidget(createControlPointGroupBox());
244  groupBoxesLayout->addStretch();
245  groupBoxesLayout->addLayout(measureLayout);
246 
247  QWidget * groupBoxesWidget = new QWidget;
248  groupBoxesWidget->setLayout(groupBoxesLayout);
249 
251 
252  QSplitter * topSplitter = new QSplitter;
253  topSplitter->addWidget(groupBoxesWidget);
254  topSplitter->addWidget(m_templateEditorWidget);
255  topSplitter->setStretchFactor(0, 4);
256  topSplitter->setStretchFactor(1, 3);
257 
258  m_templateEditorWidget->hide();
259 
260  return topSplitter;
261  }
262 
263 
266 
267  // create left vertical layout
268  m_ptIdValue = new QLabel;
269  m_pointType = new QComboBox;
270  for (int i=0; i<ControlPoint::PointTypeCount; i++) {
271  m_pointType->insertItem(i, ControlPoint::PointTypeToString(
273  }
274  QHBoxLayout *pointTypeLayout = new QHBoxLayout;
275  QLabel *pointTypeLabel = new QLabel("PointType:");
276  pointTypeLayout->addWidget(pointTypeLabel);
277  pointTypeLayout->addWidget(m_pointType);
278  connect(m_pointType, SIGNAL(activated(int)),
279  this, SLOT(setPointType(int)));
280  m_numMeasures = new QLabel;
281  m_pointAprioriLatitude = new QLabel;
282  m_pointAprioriLongitude = new QLabel;
283  m_pointAprioriRadius = new QLabel;
284  m_pointAprioriLatitudeSigma = new QLabel;
285  m_pointAprioriLongitudeSigma = new QLabel;
286  m_pointAprioriRadiusSigma = new QLabel;
287  QVBoxLayout * leftLayout = new QVBoxLayout;
288  leftLayout->addWidget(m_ptIdValue);
289  leftLayout->addLayout(pointTypeLayout);
290  leftLayout->addWidget(m_pointAprioriLatitude);
291  leftLayout->addWidget(m_pointAprioriLongitude);
292  leftLayout->addWidget(m_pointAprioriRadius);
293  leftLayout->addWidget(m_pointAprioriLatitudeSigma);
294  leftLayout->addWidget(m_pointAprioriLongitudeSigma);
295  leftLayout->addWidget(m_pointAprioriRadiusSigma);
296 
297  // create right vertical layout's top layout
298  m_lockPoint = new QCheckBox("Edit Lock Point");
299  connect(m_lockPoint, SIGNAL(clicked(bool)), this, SLOT(setLockPoint(bool)));
300  m_ignorePoint = new QCheckBox("Ignore Point");
301  connect(m_ignorePoint, SIGNAL(clicked(bool)),
302  this, SLOT(setIgnorePoint(bool)));
303  connect(this, SIGNAL(ignorePointChanged()), m_ignorePoint, SLOT(toggle()));
304  m_pointLatitude = new QLabel;
305  m_pointLongitude = new QLabel;
306  m_pointRadius = new QLabel;
307 
308  QVBoxLayout * rightLayout = new QVBoxLayout;
309  rightLayout->addWidget(m_numMeasures);
310  rightLayout->addWidget(m_lockPoint);
311  rightLayout->addWidget(m_ignorePoint);
312  rightLayout->addWidget(m_pointLatitude);
313  rightLayout->addWidget(m_pointLongitude);
314  rightLayout->addWidget(m_pointRadius);
315 
316 
317  QHBoxLayout * mainLayout = new QHBoxLayout;
318  mainLayout->addLayout(leftLayout);
319  mainLayout->addStretch();
320  mainLayout->addLayout(rightLayout);
321 
322  // create the groupbox
323  QGroupBox * groupBox = new QGroupBox("Control Point");
324  groupBox->setLayout(mainLayout);
325 
326  return groupBox;
327  }
328 
329 
332 
333  m_leftCombo = new QComboBox;
334  m_leftCombo->view()->installEventFilter(this);
335  m_leftCombo->setToolTip("Choose left control measure");
336  m_leftCombo->setWhatsThis("Choose left control measure identified by "
337  "cube filename.");
338  connect(m_leftCombo, SIGNAL(activated(int)),
339  this, SLOT(selectLeftMeasure(int)));
340  m_lockLeftMeasure = new QCheckBox("Edit Lock Measure");
341  connect(m_lockLeftMeasure, SIGNAL(clicked(bool)),
342  this, SLOT(setLockLeftMeasure(bool)));
343  m_ignoreLeftMeasure = new QCheckBox("Ignore Measure");
344  connect(m_ignoreLeftMeasure, SIGNAL(clicked(bool)),
345  this, SLOT(setIgnoreLeftMeasure(bool)));
346  connect(this, SIGNAL(ignoreLeftChanged()),
347  m_ignoreLeftMeasure, SLOT(toggle()));
348  m_leftReference = new QLabel();
349  m_leftMeasureType = new QLabel();
350  m_leftSampError = new QLabel();
351  m_leftSampError->setToolTip("<strong>Jigsaw</strong> sample residual.");
352  m_leftSampError->setWhatsThis("This is the sample residual for the left "
353  "measure calculated by the application, "
354  "<strong>jigsaw</strong>.");
355  m_leftLineError = new QLabel();
356  m_leftLineError->setToolTip("<strong>Jigsaw</strong> line residual.");
357  m_leftLineError->setWhatsThis("This is the line residual for the left "
358  "measure calculated by the application, "
359  "<strong>jigsaw</strong>.");
360  m_leftSampShift = new QLabel();
361  m_leftSampShift->setToolTip("Sample shift between apriori and current");
362  m_leftSampShift->setWhatsThis("The shift between the apriori sample and "
363  "the current sample. The apriori sample is set "
364  "when creating a new measure.");
365  m_leftLineShift = new QLabel();
366  m_leftLineShift->setToolTip("Line shift between apriori and current");
367  m_leftLineShift->setWhatsThis("The shift between the apriori line and "
368  "the current line. The apriori line is set "
369  "when creating a new measure.");
370  m_leftGoodness = new QLabel();
371  m_leftGoodness->setToolTip("Goodness of Fit result from sub-pixel "
372  "registration.");
373  m_leftGoodness->setWhatsThis("Resulting Goodness of Fit from sub-pixel "
374  "registration.");
375  QVBoxLayout * leftLayout = new QVBoxLayout;
376  leftLayout->addWidget(m_leftCombo);
377  leftLayout->addWidget(m_lockLeftMeasure);
378  leftLayout->addWidget(m_ignoreLeftMeasure);
379  leftLayout->addWidget(m_leftReference);
380  leftLayout->addWidget(m_leftMeasureType);
381  leftLayout->addWidget(m_leftSampError);
382  leftLayout->addWidget(m_leftLineError);
383  leftLayout->addWidget(m_leftSampShift);
384  leftLayout->addWidget(m_leftLineShift);
385  leftLayout->addWidget(m_leftGoodness);
386 
387  QGroupBox * leftGroupBox = new QGroupBox("Left Measure");
388  leftGroupBox->setLayout(leftLayout);
389 
390  return leftGroupBox;
391  }
392 
393 
404 
405  // create widgets for the right groupbox
406  m_rightCombo = new QComboBox;
407  m_rightCombo->view()->installEventFilter(this);
408 
409  // Attach shortcuts to Qnet Tool's window for selecting right measures
410  // Note: Qt handles this memory for us since m_qnetTool is the parent of these shortcuts
411  QShortcut *nextMeasure = new QShortcut(Qt::Key_PageDown, m_qnetTool);
412  connect(nextMeasure, SIGNAL(activated()), this, SLOT(nextRightMeasure()));
413  QShortcut *prevMeasure = new QShortcut(Qt::Key_PageUp, m_qnetTool);
414  connect(prevMeasure, SIGNAL(activated()), this, SLOT(previousRightMeasure()));
415 
416  m_rightCombo->setToolTip("Choose right control measure. "
417  "<strong>Shortcuts: PageUp/PageDown</strong>");
418  m_rightCombo->setWhatsThis("Choose right control measure identified by "
419  "cube filename. "
420  "Note: PageUp selects previous measure; "
421  "PageDown selects next meausure.");
422  connect(m_rightCombo, SIGNAL(activated(int)),
423  this, SLOT(selectRightMeasure(int)));
424  m_lockRightMeasure = new QCheckBox("Edit Lock Measure");
425  connect(m_lockRightMeasure, SIGNAL(clicked(bool)),
426  this, SLOT(setLockRightMeasure(bool)));
427  m_ignoreRightMeasure = new QCheckBox("Ignore Measure");
428  connect(m_ignoreRightMeasure, SIGNAL(clicked(bool)),
429  this, SLOT(setIgnoreRightMeasure(bool)));
430  connect(this, SIGNAL(ignoreRightChanged()),
431  m_ignoreRightMeasure, SLOT(toggle()));
432  m_rightReference = new QLabel();
433  m_rightMeasureType = new QLabel();
434  m_rightSampError = new QLabel();
435  m_rightSampError->setToolTip("<strong>Jigsaw</strong> sample residual.");
436  m_rightSampError->setWhatsThis("This is the sample residual for the right "
437  "measure which was calculated by the application, "
438  "<strong>jigsaw</strong>.");
439  m_rightLineError = new QLabel();
440  m_rightLineError->setToolTip("<strong>Jigsaw</strong> line residual.");
441  m_rightLineError->setWhatsThis("This is the line residual for the right "
442  "measure which was calculated by the application, "
443  "<strong>jigsaw</strong>.");
444  m_rightSampShift = new QLabel();
445  m_rightSampShift->setToolTip(m_leftSampShift->toolTip());
446  m_rightSampShift->setWhatsThis(m_leftSampShift->whatsThis());
447  m_rightLineShift = new QLabel();
448  m_rightLineShift->setToolTip(m_leftLineShift->toolTip());
449  m_rightLineShift->setWhatsThis(m_leftLineShift->whatsThis());
450  m_rightGoodness = new QLabel();
451  m_rightGoodness->setToolTip(m_leftGoodness->toolTip());
452  m_rightGoodness->setWhatsThis(m_leftGoodness->whatsThis());
453 
454  // create right groupbox
455  QVBoxLayout * rightLayout = new QVBoxLayout;
456  rightLayout->addWidget(m_rightCombo);
457  rightLayout->addWidget(m_lockRightMeasure);
458  rightLayout->addWidget(m_ignoreRightMeasure);
459  rightLayout->addWidget(m_rightReference);
460  rightLayout->addWidget(m_rightMeasureType);
461  rightLayout->addWidget(m_rightSampError);
462  rightLayout->addWidget(m_rightLineError);
463  rightLayout->addWidget(m_rightSampShift);
464  rightLayout->addWidget(m_rightLineShift);
465  rightLayout->addWidget(m_rightGoodness);
466 
467  QGroupBox * rightGroupBox = new QGroupBox("Right Measure");
468  rightGroupBox->setLayout(rightLayout);
469 
470  return rightGroupBox;
471  }
472 
473 
476 
477  QToolBar *toolBar = new QToolBar("Template Editor ToolBar");
478 
479  toolBar->addAction(m_openTemplateFile);
480  toolBar->addSeparator();
481  toolBar->addAction(m_saveTemplateFile);
482  toolBar->addAction(m_saveTemplateFileAs);
483 
484  m_templateEditor = new QTextEdit;
485  connect(m_templateEditor, SIGNAL(textChanged()), this,
486  SLOT(setTemplateModified()));
487 
488  QVBoxLayout *mainLayout = new QVBoxLayout;
489  mainLayout->addWidget(toolBar);
490  mainLayout->addWidget(m_templateEditor);
491 
492  m_templateEditorWidget = new QWidget;
493  m_templateEditorWidget->setLayout(mainLayout);
494  }
495 
496 
497 
506  m_openGround = new QAction(m_qnetTool);
507  m_openGround->setText("Open &Ground Source");
508  m_openGround->setToolTip("Open a ground source for choosing ground control "
509  "points");
510  m_openGround->setStatusTip("Open a ground source for choosing ground "
511  "control points");
512  QString whatsThis =
513  "<b>Function:</b> Open and display a ground source for choosing "
514  "ground control points, both Fixed and Constrained."
515  "This cube can be a level1, level2 or dem cube.";
516  m_openGround->setWhatsThis(whatsThis);
517  connect (m_openGround,SIGNAL(triggered()),this,SLOT(openGround()));
518 
519  m_openDem = new QAction(m_qnetTool);
520  m_openDem->setText("Open &Radius Source");
521  m_openDem->setToolTip("Open radius source file for ground control points");
522  m_openDem->setStatusTip("Open radius source file for ground control points");
523  whatsThis =
524  "<b>Function:</b> Open a DEM for determining the radius when "
525  "choosing ground control points. This is not the file that will be "
526  "displayed for visually picking points. This is strictly used to "
527  "determine the radius value for ground control points.";
528  m_openDem->setWhatsThis(whatsThis);
529  connect (m_openDem,SIGNAL(triggered()),this,SLOT(openDem()));
530 
531  m_saveNet = new QAction(QIcon(toolIconDir() + "/filesave.png"), "Save Control Network ...",
532  m_qnetTool);
533  m_saveNet->setShortcut(Qt::CTRL + Qt::Key_S);
534  m_saveNet->setToolTip("Save current control network");
535  m_saveNet->setStatusTip("Save current control network");
536  whatsThis = "<b>Function:</b> Saves the current <i>"
537  "control network</i>";
538  m_saveNet->setWhatsThis(whatsThis);
539  connect(m_saveNet, SIGNAL(triggered()), this, SLOT(saveNet()));
540 
541  m_saveAsNet = new QAction(QIcon(toolIconDir() + "/filesaveas.png"), "Save Control Network &As...",
542  m_qnetTool);
543  m_saveAsNet->setToolTip("Save current control network to chosen file");
544  m_saveAsNet->setStatusTip("Save current control network to chosen file");
545  whatsThis = "<b>Function:</b> Saves the current <i>"
546  "control network</i> under chosen filename";
547  m_saveAsNet->setWhatsThis(whatsThis);
548  connect(m_saveAsNet, SIGNAL(triggered()), this, SLOT(saveAsNet()));
549 
550  m_closeQnetTool = new QAction(QIcon(toolIconDir() + "/fileclose.png"), "&Close", m_qnetTool);
551  m_closeQnetTool->setToolTip("Close this window");
552  m_closeQnetTool->setStatusTip("Close this window");
553  m_closeQnetTool->setShortcut(Qt::ALT + Qt::Key_F4);
554  whatsThis = "<b>Function:</b> Closes the Qnet Tool window for this point "
555  "<p><b>Shortcut:</b> Alt+F4 </p>";
556  m_closeQnetTool->setWhatsThis(whatsThis);
557  connect(m_closeQnetTool, SIGNAL(triggered()), m_qnetTool, SLOT(close()));
558 
559  m_showHideTemplateEditor = new QAction(QIcon(toolIconDir() + "/view_text.png"),
560  "&View/edit registration template", m_qnetTool);
561  m_showHideTemplateEditor->setCheckable(true);
562  m_showHideTemplateEditor->setToolTip("View and/or edit the registration "
563  "template");
564  m_showHideTemplateEditor->setStatusTip("View and/or edit the registration "
565  "template");
566  whatsThis = "<b>Function:</b> Displays the curent registration template. "
567  "The user may edit and save changes under a chosen filename.";
568  m_showHideTemplateEditor->setWhatsThis(whatsThis);
569  connect(m_showHideTemplateEditor, SIGNAL(triggered()), this,
570  SLOT(showHideTemplateEditor()));
571 
572  m_saveChips = new QAction(QIcon(toolIconDir() + "/savechips.png"), "Save registration chips",
573  m_qnetTool);
574  m_saveChips->setToolTip("Save registration chips");
575  m_saveChips->setStatusTip("Save registration chips");
576  whatsThis = "<b>Function:</b> Save registration chips to file. "
577  "Each chip: pattern, search, fit will be saved to a separate file.";
578  m_saveChips->setWhatsThis(whatsThis);
579  connect(m_saveChips, SIGNAL(triggered()), this, SLOT(saveChips()));
580 
581  m_openTemplateFile = new QAction(QIcon(toolIconDir() + "/fileopen.png"), "&Open registration "
582  "template", m_qnetTool);
583  m_openTemplateFile->setToolTip("Set registration template");
584  m_openTemplateFile->setStatusTip("Set registration template");
585  whatsThis = "<b>Function:</b> Allows user to select a new file to set as "
586  "the registration template";
587  m_openTemplateFile->setWhatsThis(whatsThis);
588  connect(m_openTemplateFile, SIGNAL(triggered()), this, SLOT(openTemplateFile()));
589 
590  m_saveTemplateFile = new QAction(QIcon(toolIconDir() + "/filesave.png"), "&Save template file",
591  m_qnetTool);
592  m_saveTemplateFile->setToolTip("Save the template file");
593  m_saveTemplateFile->setStatusTip("Save the template file");
594  m_saveTemplateFile->setWhatsThis("Save the registration template file");
595  connect(m_saveTemplateFile, SIGNAL(triggered()), this,
596  SLOT(saveTemplateFile()));
597 
598  m_saveTemplateFileAs = new QAction(QIcon(toolIconDir() + "/filesaveas.png"), "&Save template as...",
599  m_qnetTool);
600  m_saveTemplateFileAs->setToolTip("Save the template file as");
601  m_saveTemplateFileAs->setStatusTip("Save the template file as");
602  m_saveTemplateFileAs->setWhatsThis("Save the registration template file as");
603  connect(m_saveTemplateFileAs, SIGNAL(triggered()), this,
604  SLOT(saveTemplateFileAs()));
605 
606  m_whatsThis = new QAction(QIcon(FileName(
607  "$base/icons/contexthelp.png").expanded()),"&Whats's This", m_qnetTool);
608  m_whatsThis->setShortcut(Qt::SHIFT | Qt::Key_F1);
609  m_whatsThis->setToolTip("Activate What's This and click on items on "
610  "user interface to see more information.");
611  connect(m_whatsThis, SIGNAL(triggered()), this, SLOT(enterWhatsThisMode()));
612 
613  }
614 
615 
616 
627 
628  QMenu *fileMenu = m_qnetTool->menuBar()->addMenu("&File");
629  fileMenu->addAction(m_openGround);
630  fileMenu->addAction(m_openDem);
631  fileMenu->addAction(m_saveNet);
632  fileMenu->addAction(m_saveAsNet);
633  fileMenu->addAction(m_closeQnetTool);
634 
635  QMenu * regMenu = m_qnetTool->menuBar()->addMenu("&Registration");
636  regMenu->addAction(m_openTemplateFile);
637  regMenu->addAction(m_showHideTemplateEditor);
638  regMenu->addAction(m_saveChips);
639 
640  QMenu *helpMenu = m_qnetTool->menuBar()->addMenu("&Help");
641  helpMenu->addAction(m_whatsThis);
642  }
643 
644 
645  void QnetTool::createToolBars() {
646 
647  toolBar = new QToolBar;
648  toolBar->setObjectName("TemplateEditorToolBar");
649  toolBar->setFloatable(false);
650  toolBar->addAction(m_saveNet);
651  toolBar->addSeparator();
652  toolBar->addAction(m_showHideTemplateEditor);
653  toolBar->addAction(m_saveChips);
654  toolBar->addAction(m_whatsThis);
655 
656  m_qnetTool->addToolBar(Qt::TopToolBarArea, toolBar);
657  }
658 
659 
660 
725  // Read original measures from the network for comparison with measures
726  // that have been edited
727  ControlMeasure *origLeftMeasure =
728  m_editPoint->GetMeasure(m_leftMeasure->GetCubeSerialNumber());
729  ControlMeasure *origRightMeasure =
730  m_editPoint->GetMeasure(m_rightMeasure->GetCubeSerialNumber());
731 
732  if (m_editPoint->IsIgnored()) {
733  QString message = "You are saving changes to a measure on an ignored ";
734  message += "point. Do you want to set Ignore = False on the point and ";
735  message += "both measures?";
736  switch (QMessageBox::question(m_qnetTool, "Qnet Tool Save Measure",
737  message, "&Yes", "&No", 0, 0)) {
738  // Yes: set Ignore=false for the point and measures and save point
739  case 0:
740  m_editPoint->SetIgnored(false);
741  emit ignorePointChanged();
742  if (m_leftMeasure->IsIgnored()) {
743  m_leftMeasure->SetIgnored(false);
744  emit ignoreLeftChanged();
745  }
746  if (m_rightMeasure->IsIgnored()) {
747  m_rightMeasure->SetIgnored(false);
748  emit ignoreRightChanged();
749  }
750  // No: keep Ignore=true and save measure
751  case 1:
752  break;
753 
754  }
755  }
756  if (origRightMeasure->IsIgnored() && m_rightMeasure->IsIgnored()) {
757  QString message = "You are saving changes to an ignored measure. ";
758  message += "Do you want to set Ignore = False on the right measure?";
759  switch(QMessageBox::question(m_qnetTool, "Qnet Tool Save Measure",
760  message, "&Yes", "&No", 0, 0)){
761  // Yes: set Ignore=false for the right measure and save point
762  case 0:
763  m_rightMeasure->SetIgnored(false);
764  emit ignoreRightChanged();
765  // No: keep Ignore=true and save point
766  case 1:
767  break;
768  }
769  }
770 
771  // Only check reference if point contains explicit reference. Otherwise,
772  // there has not been a reference set, set the measure on the left as the reference.
773  if (m_editPoint->IsReferenceExplicit()) {
774  if (m_editPoint->IsEditLocked()) {
775  QString message = "This control point is edit locked. The Apriori latitude, longitude and ";
776  message += "radius cannot be updated. You must first unlock the point by clicking the ";
777  message += "check box above labeled \"Edit Lock Point\".";
778  QMessageBox::warning(m_qnetTool, "Point Locked", message);
779  return;
780  }
781  // If user does not want to change the reference then don't update the measure
782  if (!checkReference()) {
783  return;
784  }
785  }
786  else if (m_leftMeasure->GetCubeSerialNumber() != m_groundSN) {
787  m_editPoint->SetRefMeasure(m_leftMeasure->GetCubeSerialNumber());
788  }
789 
790  // If this is a fixed or constrained point, and the right measure is the ground source,
791  // update the lat,lon,radius. Only the right measure can be moved, so only need to update
792  // position if the ground measure is loaded on the right.
793  //
794  // If point is locked and it is not a new point, print error
795  // TODO:: Only update if the measure moved
796  if (m_editPoint->GetType() != ControlPoint::Free && (m_groundOpen &&
797  m_rightMeasure->GetCubeSerialNumber() == m_groundSN)) {
798  if (m_editPoint->IsEditLocked() && m_controlNet->ContainsPoint(m_editPoint->GetId())) {
799  QString message = "This control point is edit locked. The Apriori latitude, longitude and ";
800  message += "radius cannot be updated. You must first unlock the point by clicking the ";
801  message += "check box above labeled \"Edit Lock Point\".";
802  QMessageBox::warning(m_qnetTool, "Point Locked", message);
803  return;
804  }
805  if (m_leftMeasure->IsIgnored()) {
806  QString message = "This is a Constrained or Fixed point and the reference measure is ";
807  message += "Ignored. Unset the Ignore flag on the reference measure before saving.";
808  QMessageBox::warning(m_qnetTool, "Point Locked", message);
809  return;
810  }
811  updateGroundPosition();
812  }
813 
814  // Save the right measure and left (if ignore or edit lock flag changed) to
815  // the editPoint The Ignore flag is the only thing that can change on the left
816  // measure.
817  m_rightMeasure->SetChooserName(Application::UserName());
818  *origRightMeasure = *m_rightMeasure;
819 
820  // Only save the left measure if the ignore flag or editLock has changed
821  if (m_leftMeasure->IsIgnored() != origLeftMeasure->IsIgnored() ||
822  m_leftMeasure->IsEditLocked() != origLeftMeasure->IsEditLocked()) {
823  m_leftMeasure->SetChooserName(Application::UserName());
824  *origLeftMeasure = *m_leftMeasure;
825  }
826 
827  // If left measure == right measure, update left
828  if (m_leftMeasure->GetCubeSerialNumber() ==
829  m_rightMeasure->GetCubeSerialNumber()) {
830  *m_leftMeasure = *m_rightMeasure;
831  // Update left measure of pointEditor
832  m_pointEditor->setLeftMeasure (m_leftMeasure, m_leftCube.data(),
833  m_editPoint->GetId());
834  }
835 
836  // Change Save Point button text to red
838 
839  editPointChanged(m_editPoint->GetId());
840 
841  // Update measure info
845  }
846 
847 
848 
865 
866  // Check if ControlPoint has reference measure, if reference Measure is
867  // not the same measure that is on the left chip viewport, set left
868  // measure as reference.
869  ControlMeasure *refMeasure = m_editPoint->GetRefMeasure();
870  if ( (m_leftMeasure->GetCubeSerialNumber() != m_groundSN) &&
871  (refMeasure->GetCubeSerialNumber() != m_leftMeasure->GetCubeSerialNumber()) ) {
872  QString message = "This point already contains a reference measure. ";
873  message += "Would you like to replace it with the measure on the left?";
874  int response = QMessageBox::question(m_qnetTool,
875  "Qnet Tool Save Measure", message,
876  QMessageBox::Yes | QMessageBox::No,
877  QMessageBox::Yes);
878  // Replace reference measure
879  if (response == QMessageBox::Yes) {
880  // Update measure file combo boxes: old reference normal font,
881  // new reference bold font
882  QString file = m_serialNumberList->fileName(m_leftMeasure->GetCubeSerialNumber());
883  QString fname = FileName(file).name();
884  int iref = m_leftCombo->findText(fname);
885 
886  // Save normal font from new reference measure
887  QVariant font = m_leftCombo->itemData(iref,Qt::FontRole);
888  m_leftCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
889  iref = m_rightCombo->findText(fname);
890  m_rightCombo->setItemData(iref,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
891 
892  file = m_serialNumberList->fileName(refMeasure->GetCubeSerialNumber());
893  fname = FileName(file).name();
894  iref = m_leftCombo->findText(fname);
895  m_leftCombo->setItemData(iref,font,Qt::FontRole);
896  iref = m_rightCombo->findText(fname);
897  m_rightCombo->setItemData(iref,font,Qt::FontRole);
898 
899  m_editPoint->SetRefMeasure(m_leftMeasure->GetCubeSerialNumber());
900  // Update reference measure to new reference measure
901  refMeasure = m_editPoint->GetRefMeasure();
902  }
903  // ??? Need to set rest of measures to Candidate and add more warning. ???//
904  }
905 
906  // If the right measure is the reference, make sure they really want
907  // to move the reference.
908  if (refMeasure->GetCubeSerialNumber() == m_rightMeasure->GetCubeSerialNumber()) {
909  QString message = "You are making a change to the reference measure. You ";
910  message += "may need to move all of the other measures to match the new ";
911  message += " coordinate of the reference measure. Do you really want to ";
912  message += " change the reference measure? ";
913  switch(QMessageBox::question(m_qnetTool, "Qnet Tool Save Measure",
914  message, "&Yes", "&No", 0, 0)){
915  // Yes: Save measure
916  case 0:
917  return true;
918  // No: keep original reference, return ChipViewports to previous states
919  case 1:
920  selectRightMeasure(m_rightCombo->currentIndex());
921  selectLeftMeasure(m_leftCombo->currentIndex());
922  return false;
923  }
924  }
925  return true;
926  }
927 
928 
929 
930  /*
931  * Update the position of ground point
932  *
933  * @author 2012-04-26 Tracie Sucharski - moved functionality from measureSaved
934  *
935  * @internal
936  *
937  */
938  void QnetTool::updateGroundPosition() {
939 
940  // TODO: If groundSource file opened does not match the SurfacePoint Source
941  // file, print warning.
942 
943  // This method only called if ground measure is on the right. Use ground measure to update
944  // apriori surface point.
945  ControlMeasure *groundMeasure = m_rightMeasure;
946  if (!m_groundGmap->SetImage(groundMeasure->GetSample(),
947  groundMeasure->GetLine())) {
948  // TODO : should never happen, either add error check or
949  // get rid of
950  }
951 
952  double lat = m_groundGmap->UniversalLatitude();
953  double lon = m_groundGmap->UniversalLongitude();
954 // cout<<"lat = "<<setprecision(15)<<lat<<endl;
955 // cout<<"lon = "<<lon<<endl;
956  double radius;
957  // Update radius, order of precedence
958  // 1. If a dem has been opened, read radius from dem.
959  // 2. Get radius from reference measure
960  // If image has shape model, radius will come from shape model
961  //
962  if (m_demOpen) {
963  radius = demRadius(lat,lon);
964  if (radius == Null) {
965  QString msg = "Could not read radius from DEM, will default to "
966  "local radius of reference measure.";
967  QMessageBox::warning(m_qnetTool, "Warning", msg);
968  if (m_editPoint->GetRefMeasure()->Camera()->SetGround(
969  Latitude(lat, Angle::Degrees), Longitude(lon, Angle::Degrees))) {
970  radius =
971  m_editPoint->GetRefMeasure()->Camera()->LocalRadius().meters();
972  m_editPoint->SetAprioriRadiusSource(
973  ControlPoint::RadiusSource::None);
974  //m_editPoint->SetAprioriRadiusSourceFile(m_radiusSourceFile);
975  }
976  else {
977  QString message = "Error trying to get radius at this pt. "
978  "Lat/Lon does not fall on the reference measure. "
979  "Cannot save this measure.";
980  QMessageBox::critical(m_qnetTool,"Error",message);
981  return;
982  }
983  }
984  m_editPoint->SetAprioriRadiusSource(m_groundRadiusSource);
985  m_editPoint->SetAprioriRadiusSourceFile(m_radiusSourceFile);
986  }
987  else {
988  // Get radius from reference image
989  if (m_editPoint->GetRefMeasure()->Camera()->SetGround(
990  Latitude(lat, Angle::Degrees), Longitude(lon, Angle::Degrees))) {
991  radius =
992  m_editPoint->GetRefMeasure()->Camera()->LocalRadius().meters();
993 // cout.width(15);
994 // cout.precision(4);
995 // cout<<"Camera Radius = "<<fixed<<radius<<endl;
996  //radius = m_groundGmap->Projection()->LocalRadius();
997  }
998  else {
999  QString message = "Error trying to get radius at this pt. "
1000  "Lat/Lon does not fall on the reference measure. "
1001  "Cannot save this measure.";
1002  QMessageBox::critical(m_qnetTool,"Error",message);
1003  return;
1004  }
1005  }
1006 
1007  try {
1008  // Read apriori surface point if it exists so that point is
1009  // replaced, but sigmas are retained. Save sigmas because the
1010  // SurfacePoint class will change them if the coordinates change.
1011  vector<Distance> targetRadii = m_controlNet->GetTargetRadii();
1012  if (m_editPoint->HasAprioriCoordinates()) {
1013  SurfacePoint aprioriPt = m_editPoint->GetAprioriSurfacePoint();
1014  aprioriPt.SetRadii(Distance(targetRadii[0]),
1015  Distance(targetRadii[1]),
1016  Distance(targetRadii[2]));
1017  Distance latSigma = aprioriPt.GetLatSigmaDistance();
1018  Distance lonSigma = aprioriPt.GetLonSigmaDistance();
1019  Distance radiusSigma = aprioriPt.GetLocalRadiusSigma();
1020  aprioriPt.SetSphericalCoordinates(Latitude(lat, Angle::Degrees),
1021  Longitude(lon, Angle::Degrees),
1022  Distance(radius, Distance::Meters));
1023  aprioriPt.SetSphericalSigmasDistance(latSigma, lonSigma, radiusSigma);
1024  m_editPoint->SetAprioriSurfacePoint(aprioriPt);
1025  }
1026  else {
1027  m_editPoint->SetAprioriSurfacePoint(SurfacePoint(
1028  Latitude(lat, Angle::Degrees),
1029  Longitude(lon, Angle::Degrees),
1030  Distance(radius, Distance::Meters)));
1031  }
1032  }
1033  catch (IException &e) {
1034  QString message = "Unable to set Apriori Surface Point.\n";
1035  message += "Latitude = " + QString::number(lat);
1036  message += " Longitude = " + QString::number(lon);
1037  message += " Radius = " + QString::number(radius) + "\n";
1038  message += e.toString();
1039  QMessageBox::critical(m_qnetTool,"Error",message);
1040  }
1041  m_editPoint->SetAprioriSurfacePointSource(m_groundSurfacePointSource);
1042  m_editPoint->SetAprioriSurfacePointSourceFile(m_groundSourceFile);
1043 
1045 
1046  }
1047 
1048 
1049 
1065 
1066  // Make a copy of edit point for updating the control net since the edit
1067  // point is still loaded in the point editor.
1068  ControlPoint *updatePoint = new ControlPoint;
1069  *updatePoint = *m_editPoint;
1070 
1071  // If this is a fixed or constrained point, see if there is a temporary
1072  // measure holding the coordinate information from the ground source.
1073  // If so, delete this measure before saving point. Clear out the
1074  // fixed Measure variable (memory deleted in ControlPoint::Delete).
1075  if (updatePoint->GetType() != ControlPoint::Free &&
1076  updatePoint->HasSerialNumber(m_groundSN)) {
1077  updatePoint->Delete(m_groundSN);
1078  }
1079 
1080  // If edit point exists in the network, save the updated point. If it
1081  // does not exist, add it.
1082  if (m_controlNet->ContainsPoint(updatePoint->GetId())) {
1083  ControlPoint *p;
1084  p = m_controlNet->GetPoint(QString(updatePoint->GetId()));
1085  *p = *updatePoint;
1086  delete updatePoint;
1087  updatePoint = NULL;
1088  }
1089  else {
1090  m_controlNet->AddPoint(updatePoint);
1091  }
1092 
1093  // Change Save Measure button text back to default
1094  m_savePoint->setPalette(m_saveDefaultPalette);
1095 
1096  // ???? Why was this here??? loadPoint();
1097  // emit signal so the nav tool refreshes the list
1098  emit refreshNavList();
1099  // emit signal so the nav tool can update edit point
1100  emit editPointChanged(m_editPoint->GetId());
1101  // emit a signal to alert user to save when exiting
1102  emit netChanged();
1103  // Refresh chipViewports to show new positions of controlPoints
1104  m_pointEditor->refreshChips();
1105  }
1106 
1107 
1108 
1123  void QnetTool::setPointType (int pointType) {
1124  if (m_editPoint == NULL) return;
1125 
1126  // If pointType is equal to current type, nothing to do
1127  if (m_editPoint->GetType() == pointType) return;
1128 
1129  if (pointType != ControlPoint::Free && m_leftMeasure->IsIgnored()) {
1130  m_pointType->setCurrentIndex((int) m_editPoint->GetType());
1131  QString message = "The reference measure is Ignored. Unset the Ignore flag on the ";
1132  message += "reference measure before setting the point type to Constrained or Fixed.";
1133  QMessageBox::warning(m_qnetTool, "Ignored Reference Measure", message);
1134  return;
1135  }
1136 
1137  bool unloadGround = false;
1138  if (m_editPoint->GetType() != ControlPoint::Free && pointType == ControlPoint::Free)
1139  unloadGround = true;
1140 
1141  // save the old point's type
1142  int temp = m_editPoint->GetType();
1143 
1144  ControlPoint::Status status = m_editPoint->SetType((ControlPoint::PointType) pointType);
1145  if (status == ControlPoint::PointLocked) {
1146  m_pointType->setCurrentIndex((int) m_editPoint->GetType());
1147  QString message = "This control point is edit locked. The point type cannot be changed. You ";
1148  message += "must first unlock the point by clicking the check box above labeled ";
1149  message += "\"Edit Lock Point\".";
1150  QMessageBox::warning(m_qnetTool, "Point Locked", message);
1151  return;
1152  }
1153 
1154  // If ground loaded and changing from Free to ground point,
1155  // read temporary ground measure to the point
1156  // Note: changing between Fixed and Constrained will not reload the ground measure
1157  if (pointType != ControlPoint::Free && temp == ControlPoint::Free && m_groundOpen) {
1159  m_pointEditor->colorizeSaveButton();
1160  }
1161  // If going from constrained or fixed to free, unload the ground measure.
1162  else if (unloadGround) {
1163  // Find in point and delete, it will be re-created with current
1164  // ground source if this is a fixed point
1165  if (m_editPoint->HasSerialNumber(m_groundSN)) {
1166  m_editPoint->Delete(m_groundSN);
1167  }
1168 
1169  loadPoint();
1170  m_pointEditor->colorizeSaveButton();
1171  }
1172 
1174  }
1175 
1176 
1177 
1190 
1191  if (!m_groundOpen) return;
1192 
1193  if (findPointLocation()) {
1194  ControlMeasure *groundMeasure = createTemporaryGroundMeasure();
1195 
1196  // Add to measure combo boxes
1197  QString file = m_serialNumberList->fileName(groundMeasure->GetCubeSerialNumber());
1198  m_pointFiles<<file;
1199  QString tempFileName = FileName(file).name();
1200 
1201  m_leftCombo->addItem(tempFileName);
1202  m_rightCombo->addItem(tempFileName);
1203  int rightIndex = m_rightCombo->findText((QString)m_groundFile);
1204  m_rightCombo->setCurrentIndex(rightIndex);
1205  selectRightMeasure(rightIndex);
1206 
1208 
1209  loadMeasureTable();
1210  }
1211  }
1212 
1213 
1214 
1224  void QnetTool::setLockPoint (bool lock) {
1225  if (m_editPoint == NULL) return;
1226 
1227  m_editPoint->SetEditLock(lock);
1229  }
1230 
1231 
1232 
1243  void QnetTool::setIgnorePoint (bool ignore) {
1244  if (m_editPoint == NULL) return;
1245 
1246  ControlPoint::Status status = m_editPoint->SetIgnored(ignore);
1247  if (status == ControlPoint::PointLocked) {
1248  m_ignorePoint->setChecked(m_editPoint->IsIgnored());
1249  QString message = "This control point is edit locked. The Ignored status cannot be ";
1250  message += "changed. You must first unlock the point by clicking the check box above ";
1251  message += "labeled \"Edit Lock Point\".";
1252  QMessageBox::warning(m_qnetTool, "Point Locked", message);
1253  return;
1254  }
1256  }
1257 
1258 
1259 
1260 
1276  void QnetTool::setLockLeftMeasure (bool lock) {
1277 
1278  if (m_editPoint->IsEditLocked()) {
1279  m_lockLeftMeasure->setChecked(m_leftMeasure->IsEditLocked());
1280  QMessageBox::warning(m_qnetTool, "Point Locked","Point is Edit Locked. You must un-lock point"
1281  " before changing a measure.");
1282  m_lockLeftMeasure->setChecked(m_leftMeasure->IsEditLocked());
1283  return;
1284  }
1285 
1286  if (m_leftMeasure != NULL) m_leftMeasure->SetEditLock(lock);
1287 
1288  // If the right chip is the same as the left chip , update the right editLock
1289  // box.
1290  if (m_rightMeasure != NULL) {
1291  if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
1292  m_rightMeasure->SetEditLock(lock);
1293  m_lockRightMeasure->setChecked(lock);
1294  }
1295  }
1296  emit measureChanged();
1297  }
1298 
1299 
1317  void QnetTool::setIgnoreLeftMeasure (bool ignore) {
1318  if (m_leftMeasure != NULL) m_leftMeasure->SetIgnored(ignore);
1319 
1320  // If the right chip is the same as the left chip , update the right
1321  // ignore box.
1322  if (m_rightMeasure != NULL) {
1323  if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
1324  m_rightMeasure->SetIgnored(ignore);
1325  m_ignoreRightMeasure->setChecked(ignore);
1326  }
1327  }
1328  emit measureChanged();
1329  }
1330 
1331 
1348 
1349  if (m_editPoint->IsEditLocked()) {
1350  m_lockRightMeasure->setChecked(m_rightMeasure->IsEditLocked());
1351  QMessageBox::warning(m_qnetTool, "Point Locked","Point is Edit Locked. You must un-lock point"
1352  " before changing a measure.");
1353  m_lockRightMeasure->setChecked(m_rightMeasure->IsEditLocked());
1354  return;
1355  }
1356 
1357  if (m_rightMeasure != NULL) m_rightMeasure->SetEditLock(lock);
1358 
1359  // If the left chip is the same as the right chip , update the left editLock box.
1360  if (m_leftMeasure != NULL) {
1361  if (m_leftMeasure->GetCubeSerialNumber() == m_rightMeasure->GetCubeSerialNumber()) {
1362  m_leftMeasure->SetEditLock(lock);
1363  m_lockLeftMeasure->setChecked(lock);
1364  }
1365  }
1366  emit measureChanged();
1367  }
1368 
1369 
1387  void QnetTool::setIgnoreRightMeasure (bool ignore) {
1388  if (m_rightMeasure != NULL) m_rightMeasure->SetIgnored(ignore);
1389 
1390  // If the right chip is the same as the left chip , update the right
1391  // ignore blox.
1392  if (m_leftMeasure != NULL) {
1393  if (m_rightMeasure->GetCubeSerialNumber() == m_leftMeasure->GetCubeSerialNumber()) {
1394  m_leftMeasure->SetIgnored(ignore);
1395  m_ignoreLeftMeasure->setChecked(ignore);
1396  }
1397  }
1398  emit measureChanged();
1399  }
1400 
1401 
1402 
1409  if (m_cnetFileName.isEmpty()) {
1410  QString message = "This is a new network, you must select "
1411  "\"Save As\" under the File Menu.";
1412  QMessageBox::critical(m_qnetTool, "Error", message);
1413  return;
1414  }
1415  emit qnetToolSave();
1416  //m_controlNet->Write(m_cnetFileName);
1417  }
1418 
1419 
1420 
1425  emit qnetToolSaveAs();
1426  }
1427 
1428 
1429 
1430 
1434  void QnetTool::updateList() {
1435 
1436  //m_pointEditor->setSerialList (*m_serialNumberList);
1437 
1438  }
1439 
1440 
1457  void QnetTool::updateNet(QString cNetFileName) {
1458  m_cnetFileName = cNetFileName;
1459  m_qnetTool->setWindowTitle("Qnet Tool - Control Network File: " +
1460  cNetFileName);
1461  //m_pointEditor->setControlNet(*m_controlNet);
1462 
1463  }
1464 
1465 
1466 
1479  QAction *action = new QAction(pad);
1480  action->setIcon(QPixmap(toolIconDir()+"/stock_draw-connector-with-arrows.png"));
1481  action->setToolTip("Control Point Editor (T)");
1482  action->setShortcut(Qt::Key_T);
1483  QObject::connect(action,SIGNAL(triggered(bool)),this,SLOT(showNavWindow(bool)));
1484  return action;
1485  }
1486 
1487 
1488 
1523  void QnetTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) {
1524  MdiCubeViewport *cvp = cubeViewport();
1525  if (cvp == NULL) return;
1526 
1527  QString file = cvp->cube()->fileName();
1528  QString sn;
1529  try {
1530  sn = m_serialNumberList->serialNumber(file);
1531  }
1532  catch (IException &e) {
1533  QString message = "Cannot get serial number for " + file + ". Is file contained in the ";
1534  message += "cube list?\n";
1535  message += e.toString();
1536  QMessageBox::critical(m_qnetTool, "Error", message);
1537  return;
1538  }
1539 
1540  double samp,line;
1541  cvp->viewportToCube(p.x(),p.y(),samp,line);
1542 
1543  m_leftFile.clear();
1544 
1545  if (s == Qt::LeftButton) {
1546  if (!m_controlNet || m_controlNet->GetNumPoints() == 0) {
1547  QString message = "No points exist for editing. Create points ";
1548  message += "using the right mouse button.";
1549  QMessageBox::warning(m_qnetTool, "Warning", message);
1550  return;
1551  }
1552 
1553  if (sn == m_groundSN) {
1554  QString message = "Cannot select point for editing on ground source. Select ";
1555  message += "point using un-projected images or the Navigator Window.";
1556  QMessageBox::critical(m_qnetTool, "Error", message);
1557  return;
1558  }
1559 
1560  // Find closest control point in network
1561  QString sn = m_serialNumberList->serialNumber(file);
1562 
1563  // since we are in a connected slot, we need to handle exceptions thrown by FindClosest
1564  try {
1565  ControlPoint *point = m_controlNet->FindClosest(sn, samp, line);
1566  modifyPoint(point);
1567  }
1568  catch (IException &ie) {
1569  QString message = "No points exist for editing. Create points using the right mouse";
1570  message += " button.";
1571  QMessageBox::warning(m_qnetTool, "Warning", message);
1572  return;
1573  }
1574  }
1575 
1576  else if (s == Qt::MidButton) {
1577  if (!m_controlNet || m_controlNet->GetNumPoints() == 0) {
1578  QString message = "No points exist for deleting. Create points ";
1579  message += "using the right mouse button.";
1580  QMessageBox::warning(m_qnetTool, "Warning", message);
1581  return;
1582  }
1583 
1584  if (m_groundOpen && file == m_groundCube->fileName()) {
1585  QString message = "Cannot select point for deleting on ground source. Select ";
1586  message += "point using un-projected images or the Navigator Window.";
1587  QMessageBox::critical(m_qnetTool, "Error", message);
1588  return;
1589  }
1590  // Find closest control point in network
1591  ControlPoint *point = NULL;
1592  try {
1593  point = m_controlNet->FindClosest(sn, samp, line);
1594 
1595  if (point == NULL) {
1596  QString message = "No points exist for deleting. Create points ";
1597  message += "using the right mouse button.";
1598  QMessageBox::warning(m_qnetTool, "Warning", message);
1599  return;
1600  }
1601  }
1602  catch (IException &e) {
1603  QString message = "Cannot find point on this image for deleting.";
1604  QMessageBox::critical(m_qnetTool, "Error", message);
1605  return;
1606  }
1607 
1608  deletePoint(point);
1609  }
1610  else if (s == Qt::RightButton) {
1611  m_leftFile = file;
1612  UniversalGroundMap *gmap = cvp->universalGroundMap();
1613  if (!gmap->SetImage(samp,line)) {
1614  QString message = "Invalid latitude or longitude at this point. ";
1615  QMessageBox::critical(m_qnetTool,"Error", message);
1616  return;
1617  }
1618  double lat = gmap->UniversalLatitude();
1619  double lon = gmap->UniversalLongitude();
1620  if (m_groundOpen && file == m_groundCube->fileName()) {
1621  createFixedPoint (lat,lon);
1622  }
1623  else {
1624  createPoint(lat,lon);
1625  }
1626  }
1627  }
1628 
1629 
1630 
1675  void QnetTool::createPoint(double lat,double lon) {
1676 
1677  // TODO: ADD AUTOSEED OPTION (CHECKBOX?)
1678 
1679  // Create list box of all files highlighting those that
1680  // contain the point.
1681  QStringList pointFiles;
1682 
1683  Camera *cam;
1684  for(int i = 0; i < m_serialNumberList->size(); i++) {
1685  if (m_serialNumberList->serialNumber(i) == m_groundSN) continue;
1686  cam = m_controlNet->Camera(i);
1687  if(cam->SetUniversalGround(lat, lon)) {
1688  // Make sure point is within image boundary
1689  double samp = cam->Sample();
1690  double line = cam->Line();
1691  if (samp >= 1 && samp <= cam->Samples() &&
1692  line >= 1 && line <= cam->Lines()) {
1693  pointFiles<<m_serialNumberList->fileName(i);
1694  }
1695  }
1696  }
1697 
1698  QnetNewPointDialog *newPointDialog = new QnetNewPointDialog(this, m_lastUsedPointId);
1699  newPointDialog->setFiles(pointFiles);
1700  if (newPointDialog->exec()) {
1701  m_lastUsedPointId = newPointDialog->pointId();
1702  ControlPoint *newPoint =
1703  new ControlPoint(m_lastUsedPointId);
1704 
1705  // If this ControlPointId already exists, message box pops up and user is
1706  // asked to enter a new value.
1707  if (m_controlNet->ContainsPoint(newPoint->GetId())) {
1708  QString message = "A ControlPoint with Point Id = [" + newPoint->GetId();
1709  message += "] already exists. Re-enter Point Id for this ControlPoint.";
1710  QMessageBox::warning(m_qnetTool, "New Point Id", message);
1711  pointFiles.clear();
1712  delete newPoint;
1713  newPoint = NULL;
1714  createPoint(lat, lon);
1715  return;
1716  }
1717 
1719 
1720  QStringList selectedFiles = newPointDialog->selectedFiles();
1721  foreach (QString selectedFile, selectedFiles) {
1722  // Create measure for any file selected
1723  ControlMeasure *m = new ControlMeasure;
1724  // Find serial number for this file
1725  QString sn =
1726  m_serialNumberList->serialNumber(selectedFile);
1727  m->SetCubeSerialNumber(sn);
1728  int camIndex =
1729  m_serialNumberList->fileNameIndex(selectedFile);
1730  cam = m_controlNet->Camera(camIndex);
1731  cam->SetUniversalGround(lat,lon);
1732  m->SetCoordinate(cam->Sample(),cam->Line());
1733  m->SetAprioriSample(cam->Sample());
1734  m->SetAprioriLine(cam->Line());
1737  m->SetCamera(cam);
1738  newPoint->Add(m);
1739  }
1740  if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1741  delete m_editPoint;
1742  m_editPoint = NULL;
1743  }
1744  m_editPoint = newPoint;
1745 
1746  // If the image that the user clicked on to select the point is not
1747  // included, clear out the leftFile value.
1748  if (!m_leftFile.isEmpty()) {
1749  if (selectedFiles.indexOf(m_leftFile) == -1) {
1750  m_leftFile.clear();
1751  }
1752  }
1753 
1754  // Load new point in QnetTool
1755  loadPoint();
1756  m_qnetTool->setVisible(true);
1757  m_qnetTool->raise();
1758 
1760  m_pointEditor->templateFileName());
1761 
1762 
1763  // emit signal so the nave tool refreshes the list
1764  emit refreshNavList();
1765  // emit signal so the nav tool can update edit point
1766  emit editPointChanged(m_editPoint->GetId());
1768 
1769  }
1770  }
1771 
1772 
1773 
1774 
1775 
1776 
1788  void QnetTool::createFixedPoint(double lat,double lon) {
1789 
1790  // TODO: ADD AUTOSEED OPTION (CHECKBOX?)
1791 
1792  // Create list of list box of all files highlighting those that
1793  // contain the point.
1794  QStringList pointFiles;
1795 
1796  Camera *cam;
1797  for (int i=0; i<m_serialNumberList->size(); i++) {
1798  if (m_serialNumberList->serialNumber(i) == m_groundSN) continue;
1799  cam = m_controlNet->Camera(i);
1800  if (cam->SetUniversalGround(lat,lon)) {
1801  // Make sure point is within image boundary
1802  double samp = cam->Sample();
1803  double line = cam->Line();
1804  if (samp >= 1 && samp <= cam->Samples() &&
1805  line >= 1 && line <= cam->Lines()) {
1806  pointFiles<<m_serialNumberList->fileName(i);
1807  }
1808  }
1809  }
1810 
1811  if (pointFiles.count() == 0) {
1812  QString message = "Point does not intersect any images.";
1813  QMessageBox::critical(m_qnetTool, "No intersection", message);
1814  return;
1815  }
1816 
1817  QnetFixedPointDialog *fixedPointDialog = new QnetFixedPointDialog(this, m_lastUsedPointId);
1818  fixedPointDialog->setFiles(pointFiles);
1819  if (fixedPointDialog->exec()) {
1820  ControlPoint *fixedPoint =
1821  new ControlPoint(fixedPointDialog->pointId());
1822 
1823  if (fixedPointDialog->isFixed()) {
1824  fixedPoint->SetType(ControlPoint::Fixed);
1825  }
1826  else {
1827  fixedPoint->SetType(ControlPoint::Constrained);
1828  }
1829 
1830  // If this ControlPointId already exists, message box pops up and user is
1831  // asked to enter a new value.
1832  if (m_controlNet->ContainsPoint(fixedPoint->GetId())) {
1833  QString message = "A ControlPoint with Point Id = [" + fixedPoint->GetId();
1834  message += "] already exists. Re-enter Point Id for this ControlPoint.";
1835  QMessageBox::warning(m_qnetTool, "New Point Id", message);
1836  pointFiles.clear();
1837  delete fixedPoint;
1838  fixedPoint = NULL;
1839  createFixedPoint(lat,lon);
1840  return;
1841  }
1842 
1843  fixedPoint->SetChooserName(Application::UserName());
1844 
1845  QStringList selectedFiles = fixedPointDialog->selectedFiles();
1846  foreach (QString selectedFile, selectedFiles) {
1847  // Create measure for any file selected
1848  ControlMeasure *m = new ControlMeasure;
1849  // Find serial number for this file
1850  QString sn =
1851  m_serialNumberList->serialNumber(selectedFile);
1852 
1853  // If ground, do not add measure, it will be added in loadPoint
1854  if (sn == m_groundSN) continue;
1855 
1856  m->SetCubeSerialNumber(sn);
1857  int camIndex =
1858  m_serialNumberList->fileNameIndex(selectedFile);
1859  cam = m_controlNet->Camera(camIndex);
1860  cam->SetUniversalGround(lat,lon);
1861  m->SetCoordinate(cam->Sample(),cam->Line());
1864  m->SetCamera(cam);
1865  fixedPoint->Add(m);
1866  }
1867 
1868  // ?????? What radius , check for dem or shape model
1869  double radius = 0;
1870  if (m_demOpen) {
1871  radius = demRadius(lat,lon);
1872  if (radius == Null) {
1873  QString msg = "Could not read radius from DEM, will default to the "
1874  "local radius of the first measure in the control point. This "
1875  "will be updated to the local radius of the chosen reference "
1876  "measure.";
1877  QMessageBox::warning(m_qnetTool, "Warning", msg);
1878  if ((*fixedPoint)[0]->Camera()->SetGround(
1880  radius = (*fixedPoint)[0]->Camera()->LocalRadius().meters();
1881  }
1882  else {
1883  QString msg = "Error trying to get radius at this pt. "
1884  "Lat/Lon does not fall on the reference measure. "
1885  "Cannot create this point.";
1886  QMessageBox::critical(m_qnetTool, "Error", msg);
1887  delete fixedPoint;
1888  fixedPoint = NULL;
1889  delete fixedPointDialog;
1890  fixedPointDialog = NULL;
1891  return;
1892  }
1893  }
1894  }
1895  else {
1896  if ((*fixedPoint)[0]->Camera()->SetGround(
1898  radius = (*fixedPoint)[0]->Camera()->LocalRadius().meters();
1899  }
1900  else {
1901  QString msg = "Error trying to get radius at this pt. "
1902  "Lat/Lon does not fall on the reference measure. "
1903  "Cannot create this point.";
1904  QMessageBox::critical(m_qnetTool, "Error", msg);
1905  delete fixedPoint;
1906  fixedPoint = NULL;
1907  delete fixedPointDialog;
1908  fixedPointDialog = NULL;
1909  return;
1910  }
1911  }
1912 
1914  Latitude(lat, Angle::Degrees),
1915  Longitude(lon, Angle::Degrees),
1916  Distance(radius, Distance::Meters)));
1917 
1918  if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1919  delete m_editPoint;
1920  m_editPoint = NULL;
1921  }
1922  m_editPoint = fixedPoint;
1923 
1924  // Load new point in QnetTool
1925  loadPoint();
1926  m_qnetTool->setVisible(true);
1927  m_qnetTool->raise();
1928 
1929  delete fixedPointDialog;
1930  fixedPointDialog = NULL;
1931 
1932  // emit signal so the nave tool refreshes the list
1933  emit refreshNavList();
1934  // emit signal so the nav tool can update edit point
1935  emit editPointChanged(m_editPoint->GetId());
1937  }
1938  }
1939 
1940 
1941 
1963 
1964  // Make a copy and make sure editPoint is a copy (which means it does not
1965  // have a parent network.
1966  if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
1967  delete m_editPoint;
1968  m_editPoint = NULL;
1969  }
1970  m_editPoint = new ControlPoint;
1971  *m_editPoint = *point;
1972  loadPoint();
1973 
1974  // Change point in viewport to red so user can see what point they are
1975  // about to delete.
1976  // the nav tool will update edit point
1977  emit editPointChanged(m_editPoint->GetId());
1978 
1979  QnetDeletePointDialog *deletePointDialog = new QnetDeletePointDialog;
1980  QString CPId = m_editPoint->GetId();
1981  deletePointDialog->pointIdValue->setText(CPId);
1982 
1983  // Need all files for this point
1984  for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
1985  ControlMeasure &m = *(*m_editPoint)[i];
1986  QString file = m_serialNumberList->fileName(m.GetCubeSerialNumber());
1987  deletePointDialog->fileList->addItem(file);
1988  }
1989 
1990  if (deletePointDialog->exec()) {
1991 
1992  int numDeleted = deletePointDialog->fileList->selectedItems().count();
1993 
1994  // Delete entire control point, either through deleteAllCheckBox or all measures selected
1995  if (deletePointDialog->deleteAllCheckBox->isChecked() ||
1996  numDeleted == m_editPoint->GetNumMeasures()) {
1997 
1998  // If all measures being deleted, let user know and give them the option to quit operation
1999  if (!deletePointDialog->deleteAllCheckBox->isChecked()) {
2000  QString message = "You have selected all measures in this point to be deleted. This "
2001  "control point will be deleted. Do you want to delete this control point?";
2002  int response = QMessageBox::question(m_qnetTool,
2003  "Delete control point", message,
2004  QMessageBox::Yes | QMessageBox::No,
2005  QMessageBox::Yes);
2006  // If No, do nothing
2007  if (response == QMessageBox::No) {
2008  return;
2009  }
2010  }
2011 
2012  // First get rid of deleted point from m_filteredPoints list
2013  // need index in control net for pt
2014  //int i = m_controlNet->
2015  //m_filteredPoints.
2016  m_qnetTool->setVisible(false);
2017  // remove this point from the control network
2018  if (m_controlNet->DeletePoint(m_editPoint->GetId()) ==
2020  QMessageBox::information(m_qnetTool, "EditLocked Point",
2021  "This point is EditLocked and cannot be deleted.");
2022  return;
2023  }
2024  if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
2025  delete m_editPoint;
2026  m_editPoint = NULL;
2027  }
2028  // emit signal so the nav tool refreshes the list
2029  emit refreshNavList();
2030  }
2031 
2032  // Delete specific measures from control point
2033  else {
2034  // Keep track of editLocked measures for reporting
2035  int lockedMeasures = 0;
2036  for (int i=0; i<deletePointDialog->fileList->count(); i++) {
2037  QListWidgetItem *item = deletePointDialog->fileList->item(i);
2038  if (!deletePointDialog->fileList->isItemSelected(item)) continue;
2039 
2040  // Do not delete reference without asking user
2041  if (m_editPoint->IsReferenceExplicit() &&
2042  (m_editPoint->GetRefMeasure()->GetCubeSerialNumber() ==
2043  (*m_editPoint)[i]->GetCubeSerialNumber())) {
2044  QString message = "You are trying to delete the Reference measure."
2045  " Do you really want to delete the Reference measure?";
2046  switch (QMessageBox::question(m_qnetTool,
2047  "Delete Reference measure?", message,
2048  "&Yes", "&No", 0, 0)) {
2049  // Yes: skip to end of switch todelete the measure
2050  case 0:
2051  break;
2052  // No: continue to next measure in the loop
2053  case 1:
2054  // if only a single measure and it's reference and user chooses not to delete,
2055  // simply return. The point has not changed.
2056  if (numDeleted == 1) {
2057  return;
2058  }
2059  continue;
2060  }
2061  }
2062 
2063  if (m_editPoint->Delete(i) == ControlMeasure::MeasureLocked) {
2064  lockedMeasures++;
2065  }
2066  }
2067 
2068  if (lockedMeasures > 0) {
2069  QMessageBox::information(m_qnetTool,"EditLocked Measures",
2070  QString::number(lockedMeasures) + " / "
2071  + QString::number(
2072  deletePointDialog->fileList->selectedItems().size()) +
2073  " measures are EditLocked and were not deleted.");
2074  }
2075 
2076  loadPoint();
2077  m_qnetTool->setVisible(true);
2078  m_qnetTool->raise();
2079 
2080  loadTemplateFile(m_pointEditor->templateFileName());
2081  }
2082 
2083  // emit a signal to alert user to save when exiting
2084  emit netChanged();
2085 
2086  // emit signal so the nav tool can update edit point
2087  if (m_editPoint != NULL) {
2088  emit editPointChanged(m_editPoint->GetId());
2089  // Change Save Point button text to red
2091  }
2092  else {
2093  // if the entire point is deleted, update with point Id = ""
2094  // this signal is connected to QnetTool::paintAllViewports
2095  // and QnetNavTool::updateEditPoint
2096  emit editPointChanged("");
2097  }
2098  }
2099  }
2100 
2101 
2102 
2112 
2113  // If no measures, print info and return
2114  if (point->GetNumMeasures() == 0) {
2115  QString message = "This point has no measures.";
2116  QMessageBox::warning(m_qnetTool, "Warning", message);
2117  // update nav list to re-highlight old point
2118  if (m_editPoint != NULL) {
2119  // emit signal so the nav tool can update edit point
2120  emit editPointChanged(m_editPoint->GetId());
2121  }
2122  else {
2123  // this signal is connected to QnetTool::paintAllViewports
2124  // and QnetNavTool::updateEditPoint
2125  emit editPointChanged("");
2126  }
2127  return;
2128  }
2129  // Make a copy of point for editing, first make sure memory not already
2130  // allocated
2131  if (m_editPoint != NULL && m_editPoint->Parent() == NULL) {
2132  delete m_editPoint;
2133  m_editPoint = NULL;
2134  }
2135  m_editPoint = new ControlPoint;
2136  *m_editPoint = *point;
2137 
2138  // If navTool modfify button pressed, m_leftFile needs to be reset
2139  // TODO: better way - have 2 slots
2140  if (sender() != this) m_leftFile.clear();
2141  loadPoint();
2142  m_qnetTool->setVisible(true);
2143  m_qnetTool->raise();
2144  loadTemplateFile(m_pointEditor->templateFileName());
2145 
2146  // emit signal so the nav tool can update edit point
2147  emit editPointChanged(m_editPoint->GetId());
2148 
2149  // New point loaded, make sure Save Measure Button text is default
2150  m_savePoint->setPalette(m_saveDefaultPalette);
2151  }
2152 
2153 
2164  bool located = true;
2165 
2166  // Use apriori surface point to find location on ground source. If
2167  // apriori surface point does not exist use reference measure
2168  double lat = 0.;
2169  double lon = 0.;
2170  if (m_editPoint->HasAprioriCoordinates()) {
2171  SurfacePoint sPt = m_editPoint->GetAprioriSurfacePoint();
2172  lat = sPt.GetLatitude().degrees();
2173  lon = sPt.GetLongitude().degrees();
2174  }
2175  else {
2176  ControlMeasure m = *(m_editPoint->GetRefMeasure());
2177  int camIndex = m_serialNumberList->serialNumberIndex(m.GetCubeSerialNumber());
2178  Camera *cam;
2179  cam = m_controlNet->Camera(camIndex);
2180  cam->SetImage(m.GetSample(),m.GetLine());
2181  lat = cam->UniversalLatitude();
2182  lon = cam->UniversalLongitude();
2183  }
2184 
2185  // Try to locate point position on current ground source,
2186  // TODO ???if doesn't exist,???
2187  if (!m_groundGmap->SetUniversalGround(lat,lon)) {
2188  located = false;
2189  QString message = "This point does not exist on the ground source.\n";
2190  message += "Latitude = " + QString::number(lat);
2191  message += " Longitude = " + QString::number(lon);
2192  message += "\n A ground measure will not be created.";
2193  QMessageBox::warning(m_qnetTool, "Warning", message);
2194  }
2195 
2196  return located;
2197  }
2198 
2199 
2210 
2211  // This measure will be deleted when the ControlPoint is saved to the
2212  // ControlNet.
2213  ControlMeasure *groundMeasure = new ControlMeasure;
2214  groundMeasure->SetCubeSerialNumber(m_groundSN);
2215  groundMeasure->SetType(ControlMeasure::Candidate);
2216  groundMeasure->SetCoordinate(m_groundGmap->Sample(),m_groundGmap->Line());
2217  m_editPoint->Add(groundMeasure);
2218 
2219  return groundMeasure;
2220  }
2221 
2222 
2247 
2248  // Write pointId
2249  QString CPId = m_editPoint->GetId();
2250  QString ptId("Point ID: ");
2251  ptId += (QString) CPId;
2252  m_ptIdValue->setText(ptId);
2253 
2254  // Write point type
2255 // QString ptType("Point Type: ");
2256 // ptType += (QString) m_editPoint->GetPointTypeString();
2257 // m_pointType->setText(ptType);
2258  m_pointType->setCurrentIndex((int) m_editPoint->GetType());
2259 
2260  // Write number of measures
2261  QString ptsize = "Number of Measures: " +
2262  QString::number(m_editPoint->GetNumMeasures());
2263  m_numMeasures->setText(ptsize);
2264 
2265  // Set EditLock box correctly
2266  m_lockPoint->setChecked(m_editPoint->IsEditLocked());
2267 
2268  // Set ignore box correctly
2269  m_ignorePoint->setChecked(m_editPoint->IsIgnored());
2270 
2271  // Clear combo boxes
2272  m_leftCombo->clear();
2273  m_rightCombo->clear();
2274  m_pointFiles.clear();
2275 
2276  // Find in point and delete, it will be re-created with current
2277  // ground source if this is a fixed point
2278  if (m_editPoint->HasSerialNumber(m_groundSN)) {
2279  m_editPoint->Delete(m_groundSN);
2280  }
2281 
2282  // If fixed, add ground source file to combos, create a measure for
2283  // the ground source, load reference on left, ground source on right
2284  if (m_groundOpen && (m_editPoint->GetType() != ControlPoint::Free)) {
2285 
2286  if (findPointLocation()) {
2287  // Create a temporary measure to hold the ground point info for ground source
2288  // This measure will be deleted when the ControlPoint is saved to the
2289  // ControlNet.
2290  // TODO: Does open ground source match point ground source
2292  }
2293  }
2294 
2295  // Load a radius source if there isn't a radius source already open, and there is a ground source
2296  if (m_groundOpen && !m_demOpen) {
2298  }
2299 
2300 
2301  // Need all files for this point
2302  for (int i=0; i<m_editPoint->GetNumMeasures(); i++) {
2303  ControlMeasure &m = *(*m_editPoint)[i];
2304  QString file = m_serialNumberList->fileName(m.GetCubeSerialNumber());
2305  m_pointFiles<<file;
2306  QString tempFileName = FileName(file).name();
2307  m_leftCombo->addItem(tempFileName);
2308  m_rightCombo->addItem(tempFileName);
2309  if (m_editPoint->IsReferenceExplicit() &&
2310  (QString)m.GetCubeSerialNumber() == m_editPoint->GetReferenceSN()) {
2311  m_leftCombo->setItemData(i,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
2312  m_rightCombo->setItemData(i,QFont("DejaVu Sans", 12, QFont::Bold), Qt::FontRole);
2313  }
2314  }
2315 
2316 
2317  // TODO: WHAT HAPPENS IF THERE IS ONLY ONE MEASURE IN THIS CONTROLPOINT??
2318  // Assuming combo loaded in same order as measures in the control point-is
2319  // this a safe assumption???
2320  //
2321  // Find the file from the cubeViewport that was originally used to select
2322  // the point, this will be displayed on the left ChipViewport, unless the
2323  // point was selected on the ground source image. In this case, simply
2324  // load the first measure on the left.
2325  int leftIndex = 0;
2326  int rightIndex = 0;
2327  // Check for reference
2328  if (m_editPoint->IsReferenceExplicit()) {
2329  leftIndex = m_editPoint->IndexOfRefMeasure();
2330  }
2331  else {
2332  if ((m_editPoint->GetType() == ControlPoint::Free) && !m_leftFile.isEmpty()) {
2333  QString baseFileName = FileName(m_leftFile).name();
2334  leftIndex = m_leftCombo->findText(baseFileName);
2335  // Sanity check
2336  if (leftIndex < 0 ) leftIndex = 0;
2337  }
2338  }
2339 
2340  // Determine index for right measure.
2341  // First, try to find correct ground. If no correct ground, set right index to either 0 or 1,
2342  // depending on value of the left index.
2343  if (m_groundOpen && (m_editPoint->GetType() != ControlPoint::Free)) {
2344  rightIndex = m_rightCombo->findText((QString)m_groundFile);
2345  }
2346  if (rightIndex <= 0) {
2347  if (leftIndex == 0) {
2348  rightIndex = 1;
2349  }
2350  else {
2351  rightIndex = 0;
2352  }
2353  }
2354 
2355  // Handle pts with a single measure, for now simply put measure on left/right
2356  // Evenutally put on left with black on right??
2357  if (rightIndex > m_editPoint->GetNumMeasures()-1) rightIndex = 0;
2358  m_rightCombo->setCurrentIndex(rightIndex);
2359  m_leftCombo->setCurrentIndex(leftIndex);
2360  // Initialize pointEditor with measures
2361  selectLeftMeasure(leftIndex);
2362  selectRightMeasure(rightIndex);
2363 
2365 
2366  loadMeasureTable();
2367  }
2368 
2369 
2370 
2371 
2372 
2381  if (m_measureWindow == NULL) {
2382  m_measureWindow = new QMainWindow();
2383  m_measureTable = new QTableWidget();
2384  m_measureTable->setMinimumWidth(1600);
2385  m_measureTable->setAlternatingRowColors(true);
2386  m_measureWindow->setCentralWidget(m_measureTable);
2387  }
2388  else {
2389  m_measureTable->clear();
2390  m_measureTable->setSortingEnabled(false);
2391  }
2392  m_measureTable->setRowCount(m_editPoint->GetNumMeasures());
2393  m_measureTable->setColumnCount(NUMCOLUMNS);
2394 
2395  QStringList labels;
2396  for (int i=0; i<NUMCOLUMNS; i++) {
2397  labels<<measureColumnToString((MeasureColumns)i);
2398  }
2399  m_measureTable->setHorizontalHeaderLabels(labels);
2400 
2401  // Fill in values
2402  for (int row=0; row<m_editPoint->GetNumMeasures(); row++) {
2403  int column = 0;
2404  ControlMeasure &m = *(*m_editPoint)[row];
2405 
2406  QString file = m_serialNumberList->fileName(m.GetCubeSerialNumber());
2407  QTableWidgetItem *tableItem = new QTableWidgetItem(QString(file));
2408  m_measureTable->setItem(row,column++,tableItem);
2409 
2410  tableItem = new QTableWidgetItem(QString(m.GetCubeSerialNumber()));
2411  m_measureTable->setItem(row,column++,tableItem);
2412 
2413  tableItem = new QTableWidgetItem();
2414  tableItem->setData(0,m.GetSample());
2415  m_measureTable->setItem(row,column++,tableItem);
2416 
2417  tableItem = new QTableWidgetItem();
2418  tableItem->setData(0,m.GetLine());
2419  m_measureTable->setItem(row,column++,tableItem);
2420 
2421  if (m.GetAprioriSample() == Null) {
2422  tableItem = new QTableWidgetItem("Null");
2423  }
2424  else {
2425  tableItem = new QTableWidgetItem();
2426  tableItem->setData(0,m.GetAprioriSample());
2427  }
2428  m_measureTable->setItem(row,column++,tableItem);
2429 
2430  if (m.GetAprioriLine() == Null) {
2431  tableItem = new QTableWidgetItem("Null");
2432  }
2433  else {
2434  tableItem = new QTableWidgetItem();
2435  tableItem->setData(0,m.GetAprioriLine());
2436  }
2437  m_measureTable->setItem(row,column++,tableItem);
2438 
2439  if (m.GetSampleResidual() == Null) {
2440  tableItem = new QTableWidgetItem(QString("Null"));
2441  }
2442  else {
2443  tableItem = new QTableWidgetItem();
2444  tableItem->setData(0,m.GetSampleResidual());
2445  }
2446  m_measureTable->setItem(row,column++,tableItem);
2447 
2448  if (m.GetLineResidual() == Null) {
2449  tableItem = new QTableWidgetItem(QString("Null"));
2450  }
2451  else {
2452  tableItem = new QTableWidgetItem();
2453  tableItem->setData(0,m.GetLineResidual());
2454  }
2455  m_measureTable->setItem(row,column++,tableItem);
2456 
2457  if (m.GetResidualMagnitude() == Null) {
2458  tableItem = new QTableWidgetItem(QString("Null"));
2459  }
2460  else {
2461  tableItem = new QTableWidgetItem();
2462  tableItem->setData(0,m.GetResidualMagnitude());
2463  }
2464  m_measureTable->setItem(row,column++,tableItem);
2465 
2466  double sampleShift = m.GetSampleShift();
2467  if (sampleShift == Null) {
2468  tableItem = new QTableWidgetItem(QString("Null"));
2469  }
2470  else {
2471  tableItem = new QTableWidgetItem();
2472  tableItem->setData(0,sampleShift);
2473  }
2474  m_measureTable->setItem(row,column++,tableItem);
2475 
2476  double lineShift = m.GetLineShift();
2477  if (lineShift == Null) {
2478  tableItem = new QTableWidgetItem(QString("Null"));
2479  }
2480  else {
2481  tableItem = new QTableWidgetItem();
2482  tableItem->setData(0,lineShift);
2483  }
2484  m_measureTable->setItem(row,column++,tableItem);
2485 
2486  double pixelShift = m.GetPixelShift();
2487  if (pixelShift == Null) {
2488  tableItem = new QTableWidgetItem(QString("Null"));
2489  }
2490  else {
2491  tableItem = new QTableWidgetItem();
2492  tableItem->setData(0,pixelShift);
2493  }
2494  m_measureTable->setItem(row,column++,tableItem);
2495 
2496  double goodnessOfFit = m.GetLogData(
2498  if (goodnessOfFit == Null) {
2499  tableItem = new QTableWidgetItem(QString("Null"));
2500  }
2501  else {
2502  tableItem = new QTableWidgetItem();
2503  tableItem->setData(0,goodnessOfFit);
2504  }
2505  m_measureTable->setItem(row,column++,tableItem);
2506 
2507  if (m.IsIgnored()) tableItem = new QTableWidgetItem("True");
2508  if (!m.IsIgnored()) tableItem = new QTableWidgetItem("False");
2509  m_measureTable->setItem(row,column++,tableItem);
2510 
2512  tableItem = new QTableWidgetItem("True");
2514  tableItem = new QTableWidgetItem("False");
2515  m_measureTable->setItem(row,column++,tableItem);
2516 
2517  tableItem = new QTableWidgetItem(
2519  m_measureTable->setItem(row,column,tableItem);
2520 
2521  // If reference measure set font on this row to bold
2522  if (m_editPoint->IsReferenceExplicit() &&
2523  (QString)m.GetCubeSerialNumber() == m_editPoint->GetReferenceSN()) {
2524  QFont font;
2525  font.setBold(true);
2526 
2527  for (int col=0; col<m_measureTable->columnCount(); col++)
2528  m_measureTable->item(row, col)->setFont(font);
2529  }
2530 
2531  }
2532 
2533  m_measureTable->resizeColumnsToContents();
2534  m_measureTable->resizeRowsToContents();
2535  m_measureTable->setSortingEnabled(true);
2536  m_measureWindow->show();
2537  }
2538 
2539 
2540 
2541  QString QnetTool::measureColumnToString(QnetTool::MeasureColumns column) {
2542  switch (column) {
2543  case FILENAME:
2544  return "FileName";
2545  case CUBESN:
2546  return "Serial #";
2547  case SAMPLE:
2548  return "Sample";
2549  case LINE:
2550  return "Line";
2551  case SAMPLERESIDUAL:
2552  return "Sample Residual";
2553  case LINERESIDUAL:
2554  return "Line Residual";
2555  case RESIDUALMAGNITUDE:
2556  return "Residual Magnitude";
2557  case SAMPLESHIFT:
2558  return "Sample Shift";
2559  case LINESHIFT:
2560  return "Line Shift";
2561  case PIXELSHIFT:
2562  return "Pixel Shift";
2563  case GOODNESSOFFIT:
2564  return "Goodness of Fit";
2565  case IGNORED:
2566  return "Ignored";
2567  case EDITLOCK:
2568  return "Edit Lock";
2569  case TYPE:
2570  return "Measure Type";
2571  case APRIORISAMPLE:
2572  return "Apriori Sample";
2573  case APRIORILINE:
2574  return "Apriori Line";
2575  }
2576  throw IException(IException::Programmer,
2577  "Invalid measure column passed to measureColumnToString", _FILEINFO_);
2578  }
2579 
2580 
2581  ControlNet *QnetTool::controlNet() {
2582  return m_controlNet;
2583  }
2584 
2585 
2586  const ControlNet *QnetTool::controlNet() const {
2587  return m_controlNet;
2588  }
2589 
2590 
2591  SerialNumberList *QnetTool::serialNumberList() {
2592  return m_serialNumberList;
2593  }
2594 
2595 
2596  const SerialNumberList *QnetTool::serialNumberList() const {
2597  return m_serialNumberList;
2598  }
2599 
2600 
2601  Workspace *QnetTool::workspace() const {
2602  return m_workspace;
2603  }
2604 
2605 
2618 
2619  QString s;
2620 
2621  SurfacePoint aprioriPoint = m_editPoint->GetAprioriSurfacePoint();
2622  if (aprioriPoint.GetLatitude().degrees() == Null) {
2623  s = "Apriori Latitude: Null";
2624  }
2625  else {
2626  s = "Apriori Latitude: " +
2627  QString::number(aprioriPoint.GetLatitude().degrees());
2628  }
2629  m_pointAprioriLatitude->setText(s);
2630  if (aprioriPoint.GetLongitude().degrees() == Null) {
2631  s = "Apriori Longitude: Null";
2632  }
2633  else {
2634  s = "Apriori Longitude: " +
2635  QString::number(aprioriPoint.GetLongitude().degrees());
2636  }
2637  m_pointAprioriLongitude->setText(s);
2638  if (aprioriPoint.GetLocalRadius().meters() == Null) {
2639  s = "Apriori Radius: Null";
2640  }
2641  else {
2642  s = "Apriori Radius: " +
2643  QString::number(aprioriPoint.GetLocalRadius().meters(),'f',2) +
2644  " <meters>";
2645  }
2646  m_pointAprioriRadius->setText(s);
2647 
2648  if (aprioriPoint.Valid()) {
2649  vector<Distance> targRadii = m_controlNet->GetTargetRadii();
2650  aprioriPoint.SetRadii(targRadii[0],targRadii[1],targRadii[2]);
2651 
2652  if (aprioriPoint.GetLatSigmaDistance().meters() == Null) {
2653  s = "Apriori Latitude Sigma: Null";
2654  }
2655  else {
2656  s = "Apriori Latitude Sigma: " +
2657  QString::number(aprioriPoint.GetLatSigmaDistance().meters()) +
2658  " <meters>";
2659  }
2660  m_pointAprioriLatitudeSigma->setText(s);
2661  if (aprioriPoint.GetLonSigmaDistance().meters() == Null) {
2662  s = "Apriori Longitude Sigma: Null";
2663  }
2664  else {
2665  s = "Apriori Longitude Sigma: " +
2666  QString::number(aprioriPoint.GetLonSigmaDistance().meters()) +
2667  " <meters>";
2668  }
2669  m_pointAprioriLongitudeSigma->setText(s);
2670  if (aprioriPoint.GetLocalRadiusSigma().meters() == Null) {
2671  s = "Apriori Radius Sigma: Null";
2672  }
2673  else {
2674  s = "Apriori Radius Sigma: " +
2675  QString::number(aprioriPoint.GetLocalRadiusSigma().meters()) +
2676  " <meters>";
2677  }
2678  m_pointAprioriRadiusSigma->setText(s);
2679  }
2680  else {
2681  s = "Apriori Latitude Sigma: Null";
2682  m_pointAprioriLatitudeSigma->setText(s);
2683  s = "Apriori Longitude Sigma: Null";
2684  m_pointAprioriLongitudeSigma->setText(s);
2685  s = "Apriori Radius Sigma: Null";
2686  m_pointAprioriRadiusSigma->setText(s);
2687  }
2688 
2689 
2690  SurfacePoint point = m_editPoint->GetAdjustedSurfacePoint();
2691  if (point.GetLatitude().degrees() == Null) {
2692  s = "Adjusted Latitude: Null";
2693  }
2694  else {
2695  s = "Adjusted Latitude: " + QString::number(point.GetLatitude().degrees());
2696  }
2697  m_pointLatitude->setText(s);
2698  if (point.GetLongitude().degrees() == Null) {
2699  s = "Adjusted Longitude: Null";
2700  }
2701  else {
2702  s = "Adjusted Longitude: " + QString::number(point.GetLongitude().degrees());
2703  }
2704  m_pointLongitude->setText(s);
2705  if (point.GetLocalRadius().meters() == Null) {
2706  s = "Adjusted Radius: Null";
2707  }
2708  else {
2709  s = "Adjusted Radius: " +
2710  QString::number(point.GetLocalRadius().meters(),'f',2) + " <meters>";
2711  }
2712  m_pointRadius->setText(s);
2713 
2714 
2715 
2716  }
2717 
2718 
2719 
2730  int curIndex = m_rightCombo->currentIndex();
2731  if (curIndex < m_rightCombo->count() - 1) {
2732  // update the right measure list index and select that measure
2733  m_rightCombo->setCurrentIndex(curIndex + 1);
2734  selectRightMeasure(curIndex+1);
2735  }
2736  }
2737 
2738 
2749  int curIndex = m_rightCombo->currentIndex();
2750  if (curIndex > 0) {
2751  // update the right measure list index and select that measure
2752  m_rightCombo->setCurrentIndex(curIndex - 1);
2753  selectRightMeasure(curIndex-1);
2754  }
2755  }
2756 
2757 
2758 
2771  QString file = m_pointFiles[index];
2772 
2773  QString serial = m_serialNumberList->serialNumber(file);
2774 
2775  // Make sure to clear out leftMeasure before making a copy of the selected
2776  // measure.
2777  if (m_leftMeasure != NULL) {
2778  delete m_leftMeasure;
2779  m_leftMeasure = NULL;
2780  }
2781  m_leftMeasure = new ControlMeasure();
2782  // Find measure for each file
2783  *m_leftMeasure = *((*m_editPoint)[serial]);
2784 
2785  // If m_leftCube is not null, delete before creating new one
2786  m_leftCube.reset(new Cube(file, "r"));
2787 
2788  // Update left measure of pointEditor
2789  m_pointEditor->setLeftMeasure (m_leftMeasure, m_leftCube.data(),
2790  m_editPoint->GetId());
2792 
2793  }
2794 
2795 
2806  QString file = m_pointFiles[index];
2807 
2808  QString serial = m_serialNumberList->serialNumber(file);
2809 
2810  // Make sure to clear out rightMeasure before making a copy of the selected
2811  // measure.
2812  if (m_rightMeasure != NULL) {
2813  delete m_rightMeasure;
2814  m_rightMeasure = NULL;
2815  }
2816  m_rightMeasure = new ControlMeasure();
2817  // Find measure for each file
2818  *m_rightMeasure = *((*m_editPoint)[serial]);
2819 
2820  // If m_rightCube is not null, delete before creating new one
2821  m_rightCube.reset(new Cube(file, "r"));
2822 
2823  // Update right measure of pointEditor
2824  m_pointEditor->setRightMeasure (m_rightMeasure, m_rightCube.data(),
2825  m_editPoint->GetId());
2827 
2828  }
2829 
2830 
2831 
2832 
2849 
2850  // Set editLock measure box correctly
2851  m_lockLeftMeasure->setChecked(IsMeasureLocked(
2852  m_leftMeasure->GetCubeSerialNumber()));
2853  // Set ignore measure box correctly
2854  m_ignoreLeftMeasure->setChecked(m_leftMeasure->IsIgnored());
2855 
2856  QString s = "Reference: ";
2857  if (m_editPoint->IsReferenceExplicit() &&
2858  (QString(m_leftMeasure->GetCubeSerialNumber()) == m_editPoint->GetReferenceSN())) {
2859  s += "True";
2860  }
2861  else {
2862  s += "False";
2863  }
2864  m_leftReference->setText(s);
2865 
2866  s = "Measure Type: ";
2867  if (m_leftMeasure->GetType() == ControlMeasure::Candidate) s+= "Candidate";
2868  if (m_leftMeasure->GetType() == ControlMeasure::Manual) s+= "Manual";
2869  if (m_leftMeasure->GetType() == ControlMeasure::RegisteredPixel) s+= "RegisteredPixel";
2870  if (m_leftMeasure->GetType() == ControlMeasure::RegisteredSubPixel) s+= "RegisteredSubPixel";
2871  m_leftMeasureType->setText(s);
2872 
2873  if (m_leftMeasure->GetSampleResidual() == Null) {
2874  s = "Sample Residual: Null";
2875  }
2876  else {
2877  s = "Sample Residual: " + QString::number(m_leftMeasure->GetSampleResidual());
2878  }
2879  m_leftSampError->setText(s);
2880  if (m_leftMeasure->GetLineResidual() == Null) {
2881  s = "Line Residual: Null";
2882  }
2883  else {
2884  s = "Line Residual: " + QString::number(m_leftMeasure->GetLineResidual());
2885  }
2886  m_leftLineError->setText(s);
2887 
2888  if (m_leftMeasure->GetSampleShift() == Null) {
2889  s = "Sample Shift: Null";
2890  }
2891  else {
2892  s = "Sample Shift: " + QString::number(m_leftMeasure->GetSampleShift());
2893  }
2894  m_leftSampShift->setText(s);
2895 
2896  if (m_leftMeasure->GetLineShift() == Null) {
2897  s = "Line Shift: Null";
2898  }
2899  else {
2900  s = "Line Shift: " + QString::number(m_leftMeasure->GetLineShift());
2901  }
2902  m_leftLineShift->setText(s);
2903 
2904  double goodnessOfFit = m_leftMeasure->GetLogData(
2905  ControlMeasureLogData::GoodnessOfFit).GetNumericalValue();
2906  if (goodnessOfFit == Null) {
2907  s = "Goodness of Fit: Null";
2908  }
2909  else {
2910  s = "Goodness of Fit: " + QString::number(goodnessOfFit);
2911  }
2912  m_leftGoodness->setText(s);
2913 
2914  }
2915 
2916 
2917 
2937 
2938  // Set editLock measure box correctly
2939  m_lockRightMeasure->setChecked(IsMeasureLocked(
2940  m_rightMeasure->GetCubeSerialNumber()));
2941  // Set ignore measure box correctly
2942  m_ignoreRightMeasure->setChecked(m_rightMeasure->IsIgnored());
2943 
2944  QString s = "Reference: ";
2945  if (m_editPoint->IsReferenceExplicit() &&
2946  (QString(m_rightMeasure->GetCubeSerialNumber()) == m_editPoint->GetReferenceSN())) {
2947  s += "True";
2948  }
2949  else {
2950  s += "False";
2951  }
2952 
2953  m_rightReference->setText(s);
2954 
2955  s = "Measure Type: ";
2956  if (m_rightMeasure->GetType() == ControlMeasure::Candidate) s+= "Candidate";
2957  if (m_rightMeasure->GetType() == ControlMeasure::Manual) s+= "Manual";
2958  if (m_rightMeasure->GetType() == ControlMeasure::RegisteredPixel) s+= "RegisteredPixel";
2959  if (m_rightMeasure->GetType() == ControlMeasure::RegisteredSubPixel) s+= "RegisteredSubPixel";
2960  m_rightMeasureType->setText(s);
2961 
2962  if (m_rightMeasure->GetSampleResidual() == Null) {
2963  s = "Sample Residual: Null";
2964  }
2965  else {
2966  s = "Sample Residual: " + QString::number(m_rightMeasure->GetSampleResidual());
2967  }
2968  m_rightSampError->setText(s);
2969  if (m_rightMeasure->GetLineResidual() == Null) {
2970  s = "Line Residual: Null";
2971  }
2972  else {
2973  s = "Line Residual: " + QString::number(m_rightMeasure->GetLineResidual());
2974  }
2975  m_rightLineError->setText(s);
2976 
2977  if (m_rightMeasure->GetSampleShift() == Null) {
2978  s = "Sample Shift: Null";
2979  }
2980  else {
2981  s = "Sample Shift: " + QString::number(m_rightMeasure->GetSampleShift());
2982  }
2983  m_rightSampShift->setText(s);
2984 
2985  if (m_rightMeasure->GetLineShift() == Null) {
2986  s = "Line Shift: Null";
2987  }
2988  else {
2989  s = "Line Shift: " + QString::number(m_rightMeasure->GetLineShift());
2990  }
2991  m_rightLineShift->setText(s);
2992 
2993  double goodnessOfFit = m_rightMeasure->GetLogData(
2994  ControlMeasureLogData::GoodnessOfFit).GetNumericalValue();
2995  if (goodnessOfFit == Null) {
2996  s = "Goodness of Fit: Null";
2997  }
2998  else {
2999  s = "Goodness of Fit: " + QString::number(goodnessOfFit);
3000  }
3001  m_rightGoodness->setText(s);
3002 
3003  }
3004 
3005 
3021 
3022  // Create list of list box of all files highlighting those that
3023  // contain the point, but that do not already have a measure.
3024  QStringList pointFiles;
3025 
3026  // Initialize camera for all images in control network,
3027  // TODO:: Needs to be moved to QnetFileTool.cpp
3028  Camera *cam;
3029 
3030  // Use lat/lon of first measure
3031  double lat;
3032  double lon;
3033 
3034  ControlMeasure m = *(m_editPoint->GetRefMeasure());
3035  int camIndex = m_serialNumberList->serialNumberIndex(m.GetCubeSerialNumber());
3036  cam = m_controlNet->Camera(camIndex);
3037  //cam = m.Camera();
3038  cam->SetImage(m.GetSample(),m.GetLine());
3039  lat = cam->UniversalLatitude();
3040  lon = cam->UniversalLongitude();
3041 
3042  for (int i=0; i<m_serialNumberList->size(); i++) {
3043  cam = m_controlNet->Camera(i);
3044  if (m_serialNumberList->serialNumber(i) == m_groundSN) continue;
3045  if (cam->SetUniversalGround(lat,lon)) {
3046  // Make sure point is within image boundary
3047  double samp = cam->Sample();
3048  double line = cam->Line();
3049  if (samp >= 1 && samp <= cam->Samples() &&
3050  line >= 1 && line <= cam->Lines()) {
3051  pointFiles<<m_serialNumberList->fileName(i);
3052  }
3053  }
3054  }
3055 
3056  QnetNewMeasureDialog *newMeasureDialog = new QnetNewMeasureDialog(this);
3057  newMeasureDialog->setFiles(*m_editPoint,pointFiles);
3058  if (newMeasureDialog->exec()) {
3059  QStringList selectedFiles = newMeasureDialog->selectedFiles();
3060  foreach (QString selectedFile, selectedFiles) {
3061  // Create measure for any file selected
3062  ControlMeasure *m = new ControlMeasure;
3063  // Find serial number for this file
3064  QString sn = m_serialNumberList->serialNumber(selectedFile);
3065  m->SetCubeSerialNumber(sn);
3066  int camIndex =
3067  m_serialNumberList->fileNameIndex(selectedFile);
3068  cam = m_controlNet->Camera(camIndex);
3069  cam->SetUniversalGround(lat,lon);
3070  m->SetCoordinate(cam->Sample(),cam->Line());
3071  m->SetAprioriSample(cam->Sample());
3072  m->SetAprioriLine(cam->Line());
3075  m_editPoint->Add(m);
3076  }
3077  loadPoint();
3078  m_qnetTool->setVisible(true);
3079  m_qnetTool->raise();
3080 
3082  m_pointEditor->templateFileName());
3083 
3084 
3085  // emit signal so the nav tool can update edit point
3086  emit editPointChanged(m_editPoint->GetId());
3088  }
3089  }
3090 
3091 
3102  bool QnetTool::eventFilter(QObject *o, QEvent *e) {
3103  if(e->type() != QEvent::Leave) return false;
3104  if(o == m_leftCombo->view()) {
3106  m_leftCombo->hidePopup();
3107  }
3108  if (o == m_rightCombo->view()) {
3110  m_rightCombo->hidePopup();
3111  }
3112  return true;
3113  }
3114 
3115 
3123  void QnetTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) {
3124  drawAllMeasurments (vp,painter);
3125 
3126  }
3127 
3128 
3142  void QnetTool::paintAllViewports(QString pointId) {
3143 
3144  // Take care of drawing things on all viewPorts.
3145  // Calling update will cause the Tool class to call all registered tools
3146  // if point has been deleted, this will remove it from the main window
3147  MdiCubeViewport *vp;
3148  for (int i=0; i<(int)cubeViewportList()->size(); i++) {
3149  vp = (*(cubeViewportList()))[i];
3150  vp->viewport()->update();
3151  }
3152  }
3153 
3176  void QnetTool::drawAllMeasurments(MdiCubeViewport *vp, QPainter *painter) {
3177  // Without a controlnetwork there are no points, or if new net, no points
3178  if (m_controlNet == 0 || m_controlNet->GetNumPoints() == 0) return;
3179 
3180  // Don't show the measurments on cubes not in the serial number list
3181  // TODO: Should we show them anyway
3182  // TODO: Should we add the SN to the viewPort
3183  QString serialNumber = SerialNumber::Compose(*vp->cube(), true);
3184 
3185  if (serialNumber == m_groundSN) {
3186  drawGroundMeasures(vp, painter);
3187  return;
3188  }
3189  if (!m_controlNet->GetCubeSerials().contains(
3190  serialNumber)) return;
3191  if (!m_serialNumberList->hasSerialNumber(serialNumber)) return;
3192  QList<ControlMeasure *> measures =
3193  m_controlNet->GetMeasuresInCube(serialNumber);
3194  // loop through all measures contained in this cube
3195  for (int i = 0; i < measures.count(); i++) {
3196  ControlMeasure *m = measures[i];
3197  // Find the measurments on the viewport
3198  double samp = m->GetSample();
3199  double line = m->GetLine();
3200  int x, y;
3201  vp->cubeToViewport(samp, line, x, y);
3202  // if the point is ignored,
3203  if (m->Parent()->IsIgnored()) {
3204  painter->setPen(QColor(255, 255, 0)); // set point marker yellow
3205  }
3206  // point is not ignored, but measure matching this image is ignored,
3207  else if (m->IsIgnored()) {
3208  painter->setPen(QColor(255, 255, 0)); // set point marker yellow
3209  }
3210  // Neither point nor measure is not ignored and the measure is fixed,
3211  else if (m->Parent()->GetType() != ControlPoint::Free) {
3212  painter->setPen(Qt::magenta);// set point marker magenta
3213  }
3214  else {
3215  painter->setPen(Qt::green); // set all other point markers green
3216  }
3217  // draw points
3218  painter->drawLine(x - 5, y, x + 5, y);
3219  painter->drawLine(x, y - 5, x, y + 5);
3220  }
3221  // if QnetTool is open,
3222  if (m_editPoint != NULL) {
3223  // and the selected point is in the image,
3224  if (m_editPoint->HasSerialNumber(serialNumber)) {
3225  // find the measurement
3226  double samp = (*m_editPoint)[serialNumber]->GetSample();
3227  double line = (*m_editPoint)[serialNumber]->GetLine();
3228  int x, y;
3229  vp->cubeToViewport(samp, line, x, y);
3230  // set point marker red
3231  QBrush brush(Qt::red);
3232  // set point marker bold - line width 2
3233  QPen pen(brush, 2);
3234  // draw the selected point in each image last so it's on top of the rest of the points
3235  painter->setPen(pen);
3236  painter->drawLine(x - 5, y, x + 5, y);
3237  painter->drawLine(x, y - 5, x, y + 5);
3238  }
3239  }
3240  }
3241 
3242 
3243 
3244 
3254  void QnetTool::drawGroundMeasures(MdiCubeViewport *vp, QPainter *painter) {
3255 
3256  // loop through control network looking for fixed and constrained points
3257  for (int i = 0; i < m_controlNet->GetNumPoints(); i++) {
3258  ControlPoint &p = *((*m_controlNet)[i]);
3259  if (p.GetType() == ControlPoint::Free) continue;
3260  if (!p.HasAprioriCoordinates()) continue;
3261 
3262  // Find the measure on the ground image
3263  if (m_groundGmap->SetGround(p.GetAprioriSurfacePoint().GetLatitude(),
3264  p.GetAprioriSurfacePoint().GetLongitude())) {
3265  double samp = m_groundGmap->Sample();
3266  double line = m_groundGmap->Line();
3267  int x, y;
3268  vp->cubeToViewport(samp, line, x, y);
3269  // if the point is ignored,
3270  if (p.IsIgnored()) {
3271  painter->setPen(QColor(255, 255, 0)); // set point marker yellow
3272  }
3273  else if (p.GetType() != ControlPoint::Free) {
3274  painter->setPen(Qt::magenta);// set point marker magenta
3275  }
3276  else if (&p == m_editPoint) {
3277  // set point marker red
3278  QBrush brush(Qt::red);
3279  // set point marker bold - line width 2
3280  QPen pen(brush, 2);
3281  }
3282  else {
3283  painter->setPen(Qt::green); // set all other point markers green
3284  }
3285  // draw points
3286  painter->drawLine(x - 5, y, x + 5, y);
3287  painter->drawLine(x, y - 5, x, y + 5);
3288  }
3289  }
3290  }
3291 
3292 
3293 
3307 
3308  if (m_templateModified) {
3309  int r = QMessageBox::warning(m_qnetTool, tr("OK to continue?"),
3310  tr("The currently opened registration template has been modified.\n"
3311  "Save changes?"),
3312  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
3313  QMessageBox::Yes);
3314 
3315  if (r == QMessageBox::Yes)
3317  else if (r == QMessageBox::Cancel)
3318  return false;
3319  }
3320 
3321  return true;
3322  }
3323 
3324 
3331 
3332  if (!okToContinue())
3333  return;
3334 
3335  QString filename = QFileDialog::getOpenFileName(m_qnetTool,
3336  "Select a registration template", ".",
3337  "Registration template files (*.def *.pvl);;All files (*)");
3338 
3339  if (filename.isEmpty())
3340  return;
3341 
3342  if (m_pointEditor->setTemplateFile(filename)) {
3343  loadTemplateFile(filename);
3344  }
3345  }
3346 
3347 
3353  void QnetTool::loadTemplateFile(QString fn) {
3354 
3355  QFile file(FileName(fn).expanded());
3356  if (!file.open(QIODevice::ReadOnly)) {
3357  QString msg = "Failed to open template file \"" + fn + "\"";
3358  QMessageBox::warning(m_qnetTool, "IO Error", msg);
3359  return;
3360  }
3361 
3362  QTextStream stream(&file);
3363  m_templateEditor->setText(stream.readAll());
3364  file.close();
3365 
3366  QScrollBar * sb = m_templateEditor->verticalScrollBar();
3367  sb->setValue(sb->minimum());
3368 
3369  m_templateModified = false;
3370  m_saveTemplateFile->setEnabled(false);
3371  m_templateFileNameLabel->setText("Template File: " + fn);
3372  }
3373 
3374 
3377  m_templateModified = true;
3378  m_saveTemplateFile->setEnabled(true);
3379  }
3380 
3381 
3384 
3385  if (!m_templateModified)
3386  return;
3387 
3388  QString filename = m_pointEditor->templateFileName();
3389 
3390  writeTemplateFile(filename);
3391  }
3392 
3393 
3396 
3397  QString filename = QFileDialog::getSaveFileName(m_qnetTool,
3398  "Save registration template", ".",
3399  "Registration template files (*.def *.pvl);;All files (*)");
3400 
3401  if (filename.isEmpty())
3402  return;
3403 
3404  writeTemplateFile(filename);
3405  }
3406 
3407 
3413  void QnetTool::writeTemplateFile(QString fn) {
3414 
3415  QString contents = m_templateEditor->toPlainText();
3416 
3417  // catch errors in Pvl format when populating pvl object
3418  stringstream ss;
3419  ss << contents;
3420  try {
3421  Pvl pvl;
3422  ss >> pvl;
3423  }
3424  catch(IException &e) {
3425  QString message = e.toString();
3426  QMessageBox::warning(m_qnetTool, "Error", message);
3427  return;
3428  }
3429 
3430  QString expandedFileName(FileName(fn).expanded());
3431 
3432  QFile file(expandedFileName);
3433 
3434  if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
3435  QString msg = "Failed to save template file to \"" + fn + "\"\nDo you "
3436  "have permission?";
3437  QMessageBox::warning(m_qnetTool, "IO Error", msg);
3438  return;
3439  }
3440 
3441  // now save contents
3442  QTextStream stream(&file);
3443  stream << contents;
3444  file.close();
3445 
3446  if (m_pointEditor->setTemplateFile(fn)) {
3447  m_templateModified = false;
3448  m_saveTemplateFile->setEnabled(false);
3449  m_templateFileNameLabel->setText("Template File: " + fn);
3450  }
3451  }
3452 
3453 
3468  try{
3469  // Get the template file from the ControlPointEditor object
3470  Pvl templatePvl(m_pointEditor->templateFileName());
3471  // Create registration dialog window using PvlEditDialog class
3472  // to view and/or edit the template
3473  PvlEditDialog registrationDialog(templatePvl);
3474  registrationDialog.setWindowTitle("View or Edit Template File: "
3475  + templatePvl.fileName());
3476  registrationDialog.resize(550,360);
3477  registrationDialog.exec();
3478  }
3479  catch (IException &e) {
3480  QString message = e.toString();
3481  QMessageBox::information(m_qnetTool, "Error", message);
3482  }
3483  }
3484 
3485 
3486 
3494  m_pointEditor->saveChips();
3495  }
3496 
3497 
3498  void QnetTool::showHideTemplateEditor() {
3499 
3500  if (!m_templateEditorWidget)
3501  return;
3502 
3503  m_templateEditorWidget->setVisible(!m_templateEditorWidget->isVisible());
3504  }
3505 
3506 
3507 
3520  void QnetTool::updatePointInfo(QString pointId) {
3521  if (m_editPoint == NULL) return;
3522  if (pointId != m_editPoint->GetId()) return;
3523  // The edit point has been changed by SetApriori, so m_editPoint needs
3524  // to possibly update some values. Need to retain measures from m_editPoint
3525  // because they might have been updated, but not yet saved to the network
3526  // ("Save Point").
3527  ControlPoint *updatedPoint = m_controlNet->GetPoint(pointId);
3528  m_editPoint->SetEditLock(updatedPoint->IsEditLocked());
3529  m_editPoint->SetIgnored(updatedPoint->IsIgnored());
3530  m_editPoint->SetAprioriSurfacePoint(updatedPoint->GetAprioriSurfacePoint());
3531 
3532  // Set EditLock box correctly
3533  m_lockPoint->setChecked(m_editPoint->IsEditLocked());
3534 
3535  // Set ignore box correctly
3536  m_ignorePoint->setChecked(m_editPoint->IsIgnored());
3537 
3539 
3540  }
3541 
3542 
3543 
3544 
3561 
3562 
3563  // Check point being edited, make sure it still exists, if not ???
3564  // Update ignored checkbox??
3565  if (m_editPoint != NULL) {
3566  try {
3567  QString id = m_ptIdValue->text().remove("Point ID: ");
3568  m_controlNet->GetPoint(id);
3569  }
3570  catch (IException &) {
3571  delete m_editPoint;
3572  m_editPoint = NULL;
3573  emit editPointChanged("");
3574  m_qnetTool->setVisible(false);
3575  m_measureWindow->setVisible(false);
3576  }
3577  }
3578 
3579  if (m_editPoint == NULL) {
3580  paintAllViewports("");
3581  }
3582  else {
3583  paintAllViewports(m_editPoint->GetId());
3584  }
3585  }
3586 
3587 
3595  void QnetTool::showNavWindow(bool checked){
3596  emit showNavTool();
3597  }
3598 
3612  QWidget *QnetTool::createToolBarWidget (QStackedWidget *parent) {
3613  QWidget *hbox = new QWidget(parent);
3614 
3615  QToolButton *showNavToolButton = new QToolButton();
3616  showNavToolButton->setText("Show Nav Tool");
3617  showNavToolButton->setToolTip("Shows the Navigation Tool Window");
3618  QString text =
3619  "<b>Function:</b> This button will bring up the Navigation Tool window that allows \
3620  the user to view, modify, ignore, delete, or filter points and cubes.";
3621  showNavToolButton->setWhatsThis(text);
3622  connect(showNavToolButton,SIGNAL(clicked(bool)),this,SLOT(showNavWindow(bool)));
3623 
3624  QHBoxLayout *layout = new QHBoxLayout(hbox);
3625  layout->setMargin(0);
3626  layout->addWidget(showNavToolButton);
3627  layout->addStretch(1);
3628  hbox->setLayout(layout);
3629  return hbox;
3630  }
3631 
3632 
3633 
3634 
3654 
3655  QString filter = "Isis cubes (*.cub *.cub.*);;";
3656  filter += "Detached labels (*.lbl);;";
3657  filter += "All (*)";
3658 
3659  QString ground = QFileDialog::getOpenFileName((QWidget*)parent(),
3660  "Open ground source",
3661  ".",
3662  filter);
3663  if (ground.isEmpty()) return;
3664 
3665  // First off, find serial number of new ground, it is needed for a couple of error checks.
3666  QString newGroundSN = SerialNumber::Compose(ground, true);
3667 
3668  // If new ground same file as old ground file simply set as active window.
3669  if (m_groundOpen && m_groundFile == FileName(ground).name()) {
3670  // See if ground source is already opened in a cubeviewport. If so, simply
3671  // activate the viewport and return.
3672  MdiCubeViewport *vp;
3673  for (int i=0; i<(int)cubeViewportList()->size(); i++) {
3674  vp = (*(cubeViewportList()))[i];
3675  if (vp->cube()->fileName() == ground) {
3676  m_workspace->mdiArea()->setActiveSubWindow(
3677  (QMdiSubWindow *)vp->parentWidget()->parent());
3678  return;
3679  }
3680  }
3681  }
3682 
3683  // Make sure there are not serial number conflicts. If there are serial number conflicts,
3684  // simply return, retaining current ground source.
3685  if (newGroundSN != m_groundSN && m_serialNumberList->hasSerialNumber(newGroundSN)) {
3686  // TODO If it already exists, are the files different? Now what?
3687  // For now, do not allow.
3688  QString message = "A cube in the cube list has the same serial number as this ground file. ";
3689  message += "If this ground source is a level 1, un-projected cube, it is probably included ";
3690  message += "in the cube list. If the ground source is a projected version of a cube in ";
3691  message += "the list and has the Instrument Group in the labels, the un-projected and ";
3692  message += "projected cube will have the same serial number. \n";
3693  message += "Because of duplicate serial numbers this cube cannot be used as a ground ";
3694  message += "source.\n\n";
3695  message += "NOTE: If this cube is the reference cube you can select points in ";
3696  message += "the Navigator window, then select the Set Apriori button to use this cube to ";
3697  message += "set the apriori latitude, longitude and radius.";
3698  QMessageBox::critical(m_qnetTool, "Cannot set ground source", message);
3699  return;
3700  }
3701 
3702  // So far, so good. If previous ground, clear out ground source info.
3703  if (m_groundOpen) {
3704  // ....otherwise if new ground source, close old. We only want a single
3705  // ground source opened at once. Delete old ground source from left/right
3706  // combo if it's there, and delete from serial number list.
3707  clearGroundSource ();
3708  }
3709 
3710  QApplication::setOverrideCursor(Qt::WaitCursor);
3711 
3712  // Create new ground cube, if failure, there will be not ground source, clear all ground
3713  // source data. (Cannot call clearGroundSource because it assumes a ground was successfully
3714  // loaded)
3715  m_groundCube.reset(NULL);
3716  m_groundGmap.reset(NULL);
3717 
3718  try {
3719  QScopedPointer<Cube> newGroundCube(new Cube(ground, "r"));
3720  QScopedPointer<UniversalGroundMap> newGroundGmap(new UniversalGroundMap(*newGroundCube));
3721 
3722  m_groundFile = FileName(newGroundCube->fileName()).name();
3723  m_groundCube.reset(newGroundCube.take());
3724  m_groundGmap.reset(newGroundGmap.take());
3725 
3726  m_serialNumberList->add(ground, true);
3727  }
3728  catch (IException &e) {
3729  QApplication::restoreOverrideCursor();
3730  QMessageBox::critical(m_qnetTool, "Error", e.toString());
3731 
3732  m_groundFile.clear();
3733 
3734  // Re-load point w/o ground source
3735  if (m_editPoint) {
3736  loadPoint();
3737  }
3738 
3739  emit refreshNavList();
3740  return;
3741  }
3742 
3743  m_groundSN = newGroundSN;
3744  m_groundSourceFile = ground;
3745  m_groundOpen = true;
3746 
3747  m_workspace->addCubeViewport(m_groundCube.data());
3748 
3749  // Get viewport so connect can be made when ground source viewport closed to clean up
3750  // ground source
3751  MdiCubeViewport *vp;
3752  for (int i=0; i<(int)cubeViewportList()->size(); i++) {
3753  vp = (*(cubeViewportList()))[i];
3754  if (vp->cube()->fileName() == ground) {
3755  connect(vp, SIGNAL(viewportClosed(CubeViewport *)),
3756  this, SLOT(groundViewportClosed(CubeViewport *)), Qt::UniqueConnection);
3757  }
3758  }
3759 
3760  if (!m_demOpen) {
3761  // If there isn't a radius source already open and there is a point selected
3762  if (m_editPoint != NULL) {
3764  }
3765 
3766  // Determine file type of ground for setting AprioriSurfacePointSource
3767  // and AprioriRadiusSource.
3768  else if (m_groundCube->hasTable("ShapeModelStatistics")) {
3769  m_groundSurfacePointSource = ControlPoint::SurfacePointSource::Basemap;
3770  if (!m_demOpen) {
3771  m_groundRadiusSource = ControlPoint::RadiusSource::DEM;
3772  m_radiusSourceFile = ground;
3773  }
3774  }
3775  // Is this a level 1 or level 2?
3776  else {
3777  try {
3778  ProjectionFactory::CreateFromCube(*m_groundCube);
3779  m_groundSurfacePointSource = ControlPoint::SurfacePointSource::Basemap;
3780  if (!m_demOpen) {
3781  m_groundRadiusSource = ControlPoint::RadiusSource::Ellipsoid;
3782  m_radiusSourceFile = "";
3783  }
3784  }
3785  catch (IException &) {
3786  try {
3787  CameraFactory::Create(*m_groundCube);
3788  m_groundSurfacePointSource = ControlPoint::SurfacePointSource::Reference;
3789  if (!m_demOpen) {
3790  PvlGroup kernels = m_groundCube->group("Kernels");
3791  QString shapeFile = kernels ["ShapeModel"];
3792  if (shapeFile.contains("dem")) {
3793  m_groundRadiusSource = ControlPoint::RadiusSource::DEM;
3794  m_radiusSourceFile = shapeFile;
3795  }
3796  else {
3797  m_groundRadiusSource = ControlPoint::RadiusSource::Ellipsoid;
3798  // Find pck file from Kernels group
3799  m_radiusSourceFile = (QString) kernels["TargetAttitudeShape"];
3800  }
3801  }
3802  }
3803  catch (IException &) {
3804  QString message = "Cannot create either Camera or Projections ";
3805  message += "for the ground source file. Check the validity of the ";
3806  message += " cube labels. The cube must either be projected or ";
3807  message += " run through spiceinit.";
3808  QMessageBox::critical(m_qnetTool, "Error", message);
3809  // Clear out everything relating to ground source
3810  clearGroundSource ();
3811  QApplication::restoreOverrideCursor();
3812  emit refreshNavList();
3813  return;
3814  }
3815  }
3816  }
3817  }
3818 
3819  if (m_editPoint != NULL &&
3820  (m_editPoint->GetType() != ControlPoint::Free)) loadPoint();
3821 
3822 
3823  emit refreshNavList();
3824  QApplication::restoreOverrideCursor();
3825  }
3826 
3827 
3836 
3837  if (m_groundFile.isEmpty()) {
3838  QString message = "You must enter a ground source before opening a Dem.";
3839  QMessageBox::critical(m_qnetTool, "Error", message);
3840  return;
3841  }
3842 
3843  QString filter = "Isis cubes (*.cub *.cub.*);;";
3844  filter += "Detached labels (*.lbl);;";
3845  filter += "All (*)";
3846  QString dem = QFileDialog::getOpenFileName((QWidget*)parent(),
3847  "Open DEM",
3848  ".",
3849  filter);
3850  if (dem.isEmpty()) return;
3851 
3852  initDem(dem);
3853 
3854  }
3855 
3864  //Get the reference image's shape model
3865  QString referenceSN = m_editPoint->GetReferenceSN();
3866  QString referenceFileName = m_serialNumberList->fileName(referenceSN);
3867  QScopedPointer<Cube> referenceCube(new Cube(referenceFileName, "r"));
3868  PvlGroup kernels = referenceCube->group("Kernels");
3869  QString shapeFile = kernels["ShapeModel"];
3870 
3871  // If the reference measure has a shape model cube then set that as the radius
3872  // This will NOT WORK for shape model files (not the default of Null or Ellipsoid)
3873  // that are not cubes
3874  if (shapeFile.contains(".cub")) {
3875  if (shapeFile.contains("dem")) {
3876  m_groundRadiusSource = ControlPoint::RadiusSource::DEM;
3877  }
3878  else {
3879  m_groundRadiusSource = ControlPoint::RadiusSource::Ellipsoid;
3880  }
3881 
3882  m_radiusSourceFile = shapeFile;
3883 
3884  // Open shape file for reading radius later
3885  initDem(shapeFile); //This will write the labels for us
3886  }
3887 
3888  // If no shape model then use the ABC of the target body
3889  else {
3890  m_groundRadiusSource = ControlPoint::RadiusSource::Ellipsoid;
3891  Spice *refSpice = new Spice(*referenceCube);
3892  Distance refRadii[3];
3893  refSpice->radii(refRadii);
3894  m_demFile = QString::number(refRadii[0].meters()) + ", " +
3895  QString::number(refRadii[1].meters()) + ", " +
3896  QString::number(refRadii[2].meters());
3897 
3898  m_radiusSourceFile = "";
3899 
3900  // Write out the labels
3901  m_groundFileNameLabel->setText("Ground Source File: " + m_groundFile);
3902  m_radiusFileNameLabel->setText("Radius Source: " + m_demFile);
3903  }
3904  }
3905 
3906  void QnetTool::initDem (QString demFile) {
3907 
3908  // If a DEM is already opened, check if new is same as old. If new,
3909  // close old, open new.
3910  QApplication::setOverrideCursor(Qt::WaitCursor);
3911  if (m_demOpen) {
3912  if (m_demFile == demFile) {
3913  QApplication::restoreOverrideCursor();
3914  return;
3915  }
3916 
3917  m_demCube.reset(NULL);
3918  m_demFile.clear();
3919  }
3920 
3921  try {
3922  QScopedPointer<Cube> newDemCube(new Cube(demFile, "r"));
3923 
3924  m_demFile = FileName(newDemCube->fileName()).name();
3925  m_demCube.reset(newDemCube.take());
3926  }
3927  catch (IException &e) {
3928  QMessageBox::critical(m_qnetTool, "Error", e.toString());
3929  QApplication::restoreOverrideCursor();
3930  return;
3931  }
3932  m_demOpen = true;
3933 
3934  // Make sure this is a dem
3935  if (!m_demCube->hasTable("ShapeModelStatistics")) {
3936  QString message = m_demFile + " is not a DEM.";
3937  QMessageBox::critical(m_qnetTool, "Error", message);
3938  m_demCube.reset(NULL);
3939  m_demOpen = false;
3940  m_demFile.clear();
3941  QApplication::restoreOverrideCursor();
3942  return;
3943  }
3944  m_groundRadiusSource = ControlPoint::RadiusSource::DEM;
3945  m_groundFileNameLabel->setText("Ground Source File: " + m_groundFile);
3946  m_radiusFileNameLabel->setText("Radius Source File: " + m_demFile);
3947  m_radiusSourceFile = demFile;
3948 
3949  QApplication::restoreOverrideCursor();
3950  }
3951 
3952 
3953 
3961 
3962  // Only continue to clearGroundSource if the viewport is not already closed
3963  // Otherwise, it could be called twice
3964  clearGroundSource();
3965  }
3966 
3967 
3968 
3969  void QnetTool::clearGroundSource () {
3970 
3971  m_leftCombo->removeItem(m_leftCombo->findText(m_groundFile));
3972  m_rightCombo->removeItem(m_rightCombo->findText(m_groundFile));
3973 
3974  // Close viewport containing ground source
3975  MdiCubeViewport *vp;
3976  for (int i=0; i<(int)cubeViewportList()->size(); i++) {
3977  vp = (*(cubeViewportList()))[i];
3978  if (vp->cube() == m_groundCube.data()) {
3979  // disconnect signal to avoid recursive situartion. When a viewport is closed, a signal
3980  // is emitted which would then call groundViewportClosed, then this method again.
3981  disconnect(vp, SIGNAL(viewportClosed(CubeViewport *)),
3982  this, SLOT(groundViewportClosed(CubeViewport *)));
3983  vp->parentWidget()->parentWidget()->close();
3984  QApplication::processEvents();
3985  break;
3986  }
3987  }
3988  // If we could not find the ground source in the open viewports, user might
3989  // have closed the viewport , reset ground source variables and re-open.
3990  m_groundOpen = false;
3991  m_groundCube.take();
3992  m_groundFile.clear();
3993  m_groundGmap.reset(NULL);
3994 
3995  m_groundFileNameLabel->setText("Ground Source File: ");
3996  if (!m_demOpen) {
3997  m_radiusFileNameLabel->setText("Radius Source File: " + m_demFile);
3998  }
3999 
4000  // Remove from serial number list
4001  m_serialNumberList->Delete(m_groundSN);
4002 
4003  // If the loaded point is a fixed point, see if there is a temporary measure
4004  // holding the coordinate information for the currentground source. If so,
4005  // delete this measure and re-load point
4006  if (m_editPoint && m_editPoint->GetType() != ControlPoint::Free &&
4007  m_editPoint->HasSerialNumber(m_groundSN)) {
4008  m_editPoint->Delete(m_groundSN);
4009  m_groundSN = "";
4010  loadPoint();
4011  }
4012  else {
4013  m_groundSN = "";
4014  }
4015  }
4016 
4017 
4018 
4019 
4020 
4028  double QnetTool::demRadius(double latitude, double longitude) {
4029 
4030  if (!m_demOpen) return Null;
4031 
4032  UniversalGroundMap *demMap = new UniversalGroundMap(*m_demCube);
4033  if (!demMap->SetUniversalGround(latitude, longitude)) {
4034  delete demMap;
4035  demMap = NULL;
4036  return Null;
4037  }
4038 
4039  // Use bilinear interpolation to read radius from DEM
4040  // Use bilinear interpolation from dem
4041  Interpolator *interp = new Interpolator(Interpolator::BiLinearType);
4042 
4043  // Buffer used to read from the model
4044  Portal *portal = new Portal(interp->Samples(), interp->Lines(),
4045  m_demCube->pixelType(),
4046  interp->HotSample(), interp->HotLine());
4047  portal->SetPosition(demMap->Sample(), demMap->Line(), 1);
4048  m_demCube->read(*portal);
4049  double radius = interp->Interpolate(demMap->Sample(), demMap->Line(),
4050  portal->DoubleBuffer());
4051  delete demMap;
4052  demMap = NULL;
4053  delete interp;
4054  interp = NULL;
4055  delete portal;
4056  portal = NULL;
4057 
4058 // cout.width(15);
4059 // cout.precision(4);
4060 // cout<<"DEM Radius = "<<fixed<<radius<<endl;
4061  return radius;
4062  }
4063 
4064 
4065 
4072 
4073  QColor qc = Qt::red;
4074  QPalette p = m_savePoint->palette();
4075  p.setColor(QPalette::ButtonText,qc);
4076  m_savePoint->setPalette(p);
4077 
4078  }
4079 
4080 
4081 
4094  bool QnetTool::IsMeasureLocked (QString serialNumber) {
4095 
4096  if (m_editPoint == NULL) return false;
4097 
4098  // Reference implicitly editLocked
4099  if (m_editPoint->IsEditLocked() && m_editPoint->IsReferenceExplicit() &&
4100  (m_editPoint->GetReferenceSN() == serialNumber)) {
4101  return true;
4102  }
4103  // Return measures explicit editLocked value
4104  else {
4105  return m_editPoint->GetMeasure(serialNumber)->IsEditLocked();
4106  }
4107 
4108  }
4109 
4110 
4111 
4118  FileName config("$HOME/.Isis/qnet/QnetTool.config");
4119  QSettings settings(config.expanded(), QSettings::NativeFormat);
4120  QPoint pos = settings.value("pos", QPoint(300, 100)).toPoint();
4121  QSize size = settings.value("size", QSize(900, 500)).toSize();
4122  m_qnetTool->resize(size);
4123  m_qnetTool->move(pos);
4124  }
4125 
4126 
4134  /*We do not want to write the settings unless the window is
4135  visible at the time of closing the application*/
4136  if(!m_qnetTool->isVisible()) return;
4137  FileName config("$HOME/.Isis/qnet/QnetTool.config");
4138  QSettings settings(config.expanded(), QSettings::NativeFormat);
4139  settings.setValue("pos", m_qnetTool->pos());
4140  settings.setValue("size", m_qnetTool->size());
4141  }
4142 
4143 
4144 
4145  void QnetTool::enterWhatsThisMode() {
4146  QWhatsThis::enterWhatsThisMode();
4147  }
4148 
4149 
4150 }
This class defines a body-fixed surface point.
Definition: SurfacePoint.h:86
Status SetType(MeasureType type)
Set how the coordinate was obtained.
Cube display widget for certain Isis MDI applications.
void loadGroundMeasure()
Load ground measure into right side and add to file combo boxes.
Definition: QnetTool.cpp:1189
PointType GetType() const
CubeViewportList * cubeViewportList() const
Return the list of cubeviewports.
Definition: Tool.cpp:390
void setIgnorePoint(bool ignore)
Set point&#39;s &quot;Ignore&quot; keyword to the value of the input parameter.
Definition: QnetTool.cpp:1243
bool checkReference()
Change which measure is the reference.
Definition: QnetTool.cpp:864
double HotSample()
Returns the sample coordinate of the center pixel in the buffer for the interpolator.
int serialNumberIndex(const QString &sn)
Return a list index given a serial number.
void setLockLeftMeasure(bool ignore)
Set the &quot;EditLock&quot; keyword of the measure shown in the left viewport to the value of the input parame...
Definition: QnetTool.cpp:1276
void updateSurfacePointInfo()
Update the Surface Point Information in the QnetTool window.
Definition: QnetTool.cpp:2617
UniversalGroundMap * universalGroundMap() const
Return the universal ground map associated with the cube (NULL implies none)
Definition: CubeViewport.h:243
void Delete(const QString &sn)
Remove the specified serial number from the list.
const double Null
Value for an Isis Null pixel.
Definition: SpecialPixel.h:109
static Isis::Projection * CreateFromCube(Isis::Cube &cube)
This method is a helper method.
void Add(ControlMeasure *measure)
Add a measurement to the control point, taking ownership of the measure in the process.
(e.g., autoseed, interest) AKA predicted, unmeasured, unverified
QGroupBox * createControlPointGroupBox()
Definition: QnetTool.cpp:265
void updateNet(QString cNetFileName)
Updates the Control Network displayed in the Qnet Tool title bar.
Definition: QnetTool.cpp:1457
bool hasSerialNumber(QString sn)
Determines whether or not the requested serial number exists in the list.
double Sample() const
Returns the current line value of the camera model or projection.
void modifyPoint(ControlPoint *point)
Modify control point.
Definition: QnetTool.cpp:2111
A Constrained point is a Control Point whose lat/lon/radius is somewhat established and should not be...
Definition: ControlPoint.h:361
A Fixed point is a Control Point whose lat/lon is well established and should not be changed...
Definition: ControlPoint.h:356
double degrees() const
Get the angle in units of Degrees.
Definition: Angle.h:245
double Interpolate(const double isamp, const double iline, const double buf[])
Performs an interpolation on the data according to the parameters set in the constructor.
File name manipulation and expansion.
Definition: FileName.h:111
Universal Ground Map.
Distance GetLocalRadius() const
Return the radius of the surface point.
QWidget * createToolBarWidget(QStackedWidget *parent)
This method creates the widgets for the tool bar.
Definition: QnetTool.cpp:3612
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.
void mouseButtonRelease(QPoint p, Qt::MouseButton s)
Handle mouse events on CubeViewport.
Definition: QnetTool.cpp:1523
double GetResidualMagnitude() const
Return Residual magnitude.
Buffer for containing a two dimensional section of an image.
Definition: Portal.h:52
void saveChips()
Slot which calls ControlPointEditor slot to save chips.
Definition: QnetTool.cpp:3493
void radii(Distance r[3]) const
Returns the radii of the body in km.
Definition: Spice.cpp:850
void openReferenceRadius()
Open a radius source using the shape model of the reference measure of m_editPoint.
Definition: QnetTool.cpp:3863
void drawGroundMeasures(MdiCubeViewport *vp, QPainter *painter)
Draw all Fixed or Constrained points on the ground source viewport.
Definition: QnetTool.cpp:3254
QString serialNumber(const QString &filename)
Return a serial number given a filename.
PointType
These are the valid &#39;types&#39; of point.
Definition: ControlPoint.h:349
double UniversalLatitude() const
Returns the planetocentric latitude, in degrees, at the surface intersection point in the body fixed ...
Definition: Sensor.cpp:225
bool findPointLocation()
Attempt to find the control point&#39;s location on the ground source.
Definition: QnetTool.cpp:2163
void nextRightMeasure()
Selects the next right measure when activated by key shortcut.
Definition: QnetTool.cpp:2729
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:59
void setFiles(QStringList pointFiles)
double * DoubleBuffer() const
Returns the value of the shape buffer.
Definition: Buffer.h:153
void openTemplateFile()
prompt user for a registration template file to open.
Definition: QnetTool.cpp:3330
void paintViewport(MdiCubeViewport *cvp, QPainter *painter)
Take care of drawing things on a viewPort.
Definition: QnetTool.cpp:3123
void setPointType(int pointType)
Set the point type.
Definition: QnetTool.cpp:1123
double GetNumericalValue() const
Get the value associated with this log data.
int fileNameIndex(const QString &filename)
Return a list index given a filename.
Status SetChooserName(QString name)
Set the point&#39;s chooser name.
void saveNet()
Signal to save control net.
Definition: QnetTool.cpp:1408
void setTemplateModified()
called when the template file is modified by the template editor
Definition: QnetTool.cpp:3376
double UniversalLatitude() const
Returns the universal latitude of the camera model or projection.
Widget to display Isis cubes for qt apps.
Definition: CubeViewport.h:121
Registered to whole pixel (e.g.,pointreg)
Registered to sub-pixel (e.g., pointreg)
double Line() const
Returns the current line value of the camera model or projection.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:154
void selectLeftMeasure(int index)
Select left measure.
Definition: QnetTool.cpp:2770
void refresh()
Refresh all necessary widgets in QnetTool including the PointEditor and CubeViewports.
Definition: QnetTool.cpp:3560
void createFixedPoint(double lat, double lon)
Create new Fixed control point.
Definition: QnetTool.cpp:1788
Distance measurement, usually in meters.
Definition: Distance.h:47
Longitude GetLongitude() const
Return the body-fixed longitude for the surface point.
QGroupBox * createLeftMeasureGroupBox()
Definition: QnetTool.cpp:331
void savePoint()
Save edit point to the Control Network.
Definition: QnetTool.cpp:1064
void paintAllViewports(QString pointId)
This method will repaint the given Point ID in each viewport Note: The pointId parameter is here even...
Definition: QnetTool.cpp:3142
void SetRadii(const Distance &majorRadius, const Distance &minorRadius, const Distance &polarRadius)
Reset the radii of the surface body of the surface point.
A Free point is a Control Point that identifies common measurements between two or more cubes...
Definition: ControlPoint.h:369
Distance GetLonSigmaDistance() const
Return the longiitude sigma in meters.
bool okToContinue()
Allows user to set a new template file.
Definition: QnetTool.cpp:3306
static QString Compose(Pvl &label, bool def2filename=false)
Compose a SerialNumber from a PVL.
bool HasSerialNumber(QString serialNumber) const
Return true if given serial number exists in point.
QString fileName(const QString &sn)
Return a filename given a serial number.
This was called the Qisis MainWindow.
void updateLeftMeasureInfo()
Definition: QnetTool.cpp:2848
bool SetUniversalGround(const double latitude, const double longitude)
Sets the lat/lon values to get the sample/line values.
Definition: Camera.cpp:392
double UniversalLongitude() const
Returns the positive east, 0-360 domain longitude, in degrees, at the surface intersection point in t...
Definition: Sensor.cpp:248
QAction * toolPadAction(ToolPad *pad)
Adds the Tie tool action to the tool pad.
Definition: QnetTool.cpp:1478
bool SetImage(const double sample, const double line)
Sets the sample/line values of the image to get the lat/lon values.
Definition: Camera.cpp:166
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:52
void createQnetTool(QWidget *parent)
create the main window for editing control points
Definition: QnetTool.cpp:131
double HotLine()
Returns the line coordinate of the center pixel in the buffer for the interpolator.
void addMeasure()
Add measure to point.
Definition: QnetTool.cpp:3020
void loadTemplateFile(QString)
Updates the current template file being used.
Definition: QnetTool.cpp:3353
double meters() const
Get the distance in meters.
Definition: Distance.cpp:97
MdiCubeViewport * cubeViewport() const
Return the current cubeviewport.
Definition: Tool.h:211
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition: Angle.h:69
Cube * cube() const
Return the cube associated with viewport.
Definition: CubeViewport.h:228
a control network
Definition: ControlNet.h:207
QString GetId() const
Return the Id of the control point.
Hand Measured (e.g., qnet)
Status SetCamera(Isis::Camera *camera)
Set pointer to camera associated with a measure.
int Samples()
Returns the number of samples needed by the interpolator.
void setFiles(ControlPoint point, QStringList pointFiles)
Latitude GetLatitude() const
Return the body-fixed latitude for the surface point.
Pixel value mapper.
Definition: Stretch.h:72
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
void saveTemplateFileAs()
save the contents of template editor to a file chosen by the user
Definition: QnetTool.cpp:3395
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
void createPoint(double lat, double lon)
Create new control point.
Definition: QnetTool.cpp:1675
ControlMeasure * createTemporaryGroundMeasure()
Create a temporary measure to hold the ground point info for ground source.
Definition: QnetTool.cpp:2209
double Sample()
Returns the current sample number.
Definition: Camera.cpp:2752
void writeSettings() const
This method is called when the Main window is closed or hidden to write the size and location setting...
Definition: QnetTool.cpp:4133
Status SetAprioriSurfacePoint(SurfacePoint aprioriSP)
This updates the apriori surface point.
void readSettings()
This method is called from the constructor so that when the Main window is created, it know&#39;s it&#39;s size and location.
Definition: QnetTool.cpp:4117
double UniversalLongitude() const
Returns the universal longitude of the camera model or projection.
void colorizeSaveButton()
Turn &quot;Save Point&quot; button text to red.
Definition: QnetTool.cpp:4071
A single control point.
Definition: ControlPoint.h:339
static Camera * Create(Cube &cube)
Creates a Camera object using Pvl Specifications.
void createMenus()
Customize dropdown menus below title bar.
Definition: QnetTool.cpp:626
void viewportToCube(int x, int y, double &sample, double &line) const
Convert a viewport x/y to a cube sample/line (may be outside the cube)
void setLockRightMeasure(bool ignore)
Set the &quot;EditLock&quot; keyword of the measure shown in the right viewport to the value of the input param...
Definition: QnetTool.cpp:1347
void previousRightMeasure()
Selects the previous right measure when activated by key shortcut.
Definition: QnetTool.cpp:2748
void loadPoint()
Load point into QnetTool.
Definition: QnetTool.cpp:2246
Container for cube-like labels.
Definition: Pvl.h:135
bool eventFilter(QObject *o, QEvent *e)
Event filter for QnetTool.
Definition: QnetTool.cpp:3102
void setIgnoreRightMeasure(bool ignore)
Set the &quot;Ignore&quot; keyword of the measure shown in the right viewport to the value of the input paramet...
Definition: QnetTool.cpp:1387
void createTemplateEditorWidget()
Creates the Widget which contains the template editor and its toolbar.
Definition: QnetTool.cpp:475
bool IsEditLocked() const
Return value for p_editLock or implicit lock on reference measure.
void SetPosition(const double sample, const double line, const int band)
Sets the line and sample position of the buffer.
Definition: Portal.h:109
void saveAsNet()
Signal to save the control net.
Definition: QnetTool.cpp:1424
void writeTemplateFile(QString)
write the contents of the template editor to the file provided.
Definition: QnetTool.cpp:3413
void deletePoint(ControlPoint *point)
Delete control point.
Definition: QnetTool.cpp:1962
Status SetType(PointType newType)
Updates the control point&#39;s type.
void loadMeasureTable()
Load measure information into the measure table.
Definition: QnetTool.cpp:2380
bool SetImage(double sample, double line)
Returns whether the sample/line postion was set successfully in the camera model or projection...
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
void measureSaved()
This method is connected with the measureSaved() signal from ControlPointEdit.
Definition: QnetTool.cpp:724
void drawAllMeasurments(MdiCubeViewport *vp, QPainter *painter)
Draw all measurments which are on this viewPort.
Definition: QnetTool.cpp:3176
Status
This is a return status for many of the mutating (setter) method calls.
Definition: ControlPoint.h:378
GoodnessOfFit is pointreg information for reference measures.
void setIgnoreLeftMeasure(bool ignore)
Set the &quot;Ignore&quot; keyword of the measure shown in the left viewport to the value of the input paramete...
Definition: QnetTool.cpp:1317
int Lines()
Returns the number of lines needed by the interpolator.
Pixel interpolator.
Definition: Interpolator.h:51
void setLockPoint(bool ignore)
Set point&#39;s &quot;EditLock&quot; keyword to the value of the input parameter.
Definition: QnetTool.cpp:1224
void viewTemplateFile()
Allows the user to view the template file that is currently set.
Definition: QnetTool.cpp:3467
void cubeToViewport(double sample, double line, int &x, int &y) const
Convert a cube sample/line to a viewport x/y (may be outside the viewport)
void setFiles(QStringList pointFiles)
Set files found containing selected point.
double Line()
Returns the current line number.
Definition: Camera.cpp:2772
QString toString() const
Returns a string representation of this exception.
Definition: IException.cpp:553
Distance GetLatSigmaDistance() const
Return the latitude sigma in meters.
static QString UserName()
Returns the user name.
Isis exception class.
Definition: IException.h:99
QString toolIconDir() const
returns the path to the icon directory.
Definition: Tool.h:127
Status SetChooserName()
Set chooser name to a user who last changed the coordinate.
bool SetUniversalGround(double lat, double lon)
Returns whether the lat/lon position was set successfully in the camera model or projection.
void showNavWindow(bool checked)
Emits a signal to displays the Navigation window.
Definition: QnetTool.cpp:3595
Base class for the Qisis tools.
Definition: Tool.h:81
a control measurement
PvlEditDialog creates a QDialog window in which a QTextEdit box displays the contents of a pvl file...
Definition: PvlEditDialog.h:39
QString GetCubeSerialNumber() const
Return the serial number of the cube containing the coordinate.
Status SetCubeSerialNumber(QString newSerialNumber)
Set cube serial number.
Status SetCoordinate(double sample, double line)
Set the coordinate of the measurement.
Base class for the Qisis main windows.
Definition: MainWindow.h:24
QString fileName() const
Returns the opened cube&#39;s filename.
Definition: Cube.cpp:1160
Obtain SPICE information for a spacecraft.
Definition: Spice.h:282
The distance is being specified in meters.
Definition: Distance.h:56
Point Editor Widget.
int Delete(ControlMeasure *measure)
Remove a measurement from the control point, deleting reference measure is allowed.
void openGround()
Open a ground source for selecting fixed points.
Definition: QnetTool.cpp:3653
void updateRightMeasureInfo()
Definition: QnetTool.cpp:2936
void createActions()
Creates the menu actions for Qnet Tool.
Definition: QnetTool.cpp:505
void groundViewportClosed(CubeViewport *)
Slot called when the ground source cube viewport is closed.
Definition: QnetTool.cpp:3960
void saveTemplateFile()
save the file opened in the template editor
Definition: QnetTool.cpp:3383
Serial Number list generator.
double demRadius(double latitude, double longitude)
Return a radius values from the dem using bilinear interpolation.
Definition: QnetTool.cpp:4028
QSplitter * createTopSplitter()
creates everything above the ControlPointEdit
Definition: QnetTool.cpp:236
static QString PointTypeToString(PointType type)
Obtain a string representation of a given PointType.
QGroupBox * createRightMeasureGroupBox()
Creates the right measure group box.
Definition: QnetTool.cpp:403
void selectRightMeasure(int index)
Select right measure.
Definition: QnetTool.cpp:2805
void updatePointInfo(QString pointId)
Update the current editPoint information in the Point Editor labels.
Definition: QnetTool.cpp:3520
bool IsMeasureLocked(QString serialNumber)
Check for implicitly locked measure in m_editPoint.
Definition: QnetTool.cpp:4094
void openDem()
Open a DEM for ground source radii.
Definition: QnetTool.cpp:3835
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
static QString MeasureTypeToString(MeasureType type)
Return the String Control Measure type.
This is returned when the operation requires Edit Lock to be false but it is currently true...
Definition: ControlPoint.h:393
IO Handler for Isis Cubes.
Definition: Cube.h:158

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