Isis 3 Programmer Reference
MeasureTool.cpp
1#include "MeasureTool.h"
2
3#include <QApplication>
4#include <QCheckBox>
5#include <QFileDialog>
6#include <QHBoxLayout>
7#include <QLineEdit>
8#include <QMenu>
9#include <QMenuBar>
10#include <QMessageBox>
11#include <QStackedWidget>
12#include <QStatusBar>
13#include <QTableWidget>
14#include <QToolButton>
15
16#include <geos/geom/Geometry.h>
17#include <geos/geom/Point.h>
18
19#include "Camera.h"
20#include "Distance.h"
21#include "FileName.h"
22#include "Latitude.h"
23#include "Longitude.h"
24#include "MdiCubeViewport.h"
25#include "Projection.h"
26#include "RingPlaneProjection.h"
27#include "TProjection.h"
28#include "SurfacePoint.h"
29#include "ToolPad.h"
30#include "Constants.h"
31
32namespace Isis {
40 m_rubberBand = NULL;
41 m_tableWin = new TableMainWindow("Measurements", parent);
43
44 // Create the action for showing the table
45 m_action = new QAction(parent);
46 m_action->setText("Measuring ...");
47
48 connect(m_action, SIGNAL(triggered()), m_tableWin, SLOT(showTable()));
49 connect(m_action, SIGNAL(triggered()), m_tableWin, SLOT(raise()));
50 connect(m_action, SIGNAL(triggered()), m_tableWin, SLOT(syncColumns()));
51 //m_tableWin->installEventFilter(this);
52
53 m_tableWin->addToTable(false, "Feature\nName", "Feature Name");
54 m_tableWin->addToTable(false, "Feature\nType", "Feature Type");
56 "Start\nLatitude:Start\nLongitude:End\nLatitude:End\nLongitude",
57 "Ground Range", -1, Qt::Horizontal, "Start Latitude/Longitude to End Latitude/Longitude");
58 m_tableWin->addToTable(false, "Start\nSample:Start\nLine:End\nSample:End\nLine",
59 "Pixel Range", -1, Qt::Horizontal, "Start Sample/Line to End Sample/Line");
60 m_tableWin->addToTable(true, "Kilometer\nDistance", "Kilometer Distance");
61 m_tableWin->addToTable(false, "Meter\nDistance", "Meter Distance");
62 m_tableWin->addToTable(false, "Pixel\nDistance", "Pixel Distance");
63 m_tableWin->addToTable(false, "Degree\nAngle", "Degree Angle");
64 m_tableWin->addToTable(false, "Radian\nAngle", "Radian Angle");
65 m_tableWin->addToTable(false, "Kilometer\nArea", "Kilometer Area");
66 m_tableWin->addToTable(false, "Meter\nArea", "Meter Area");
67 m_tableWin->addToTable(false, "Pixel\nArea", "Pixel Area");
68 m_tableWin->addToTable(false, "Planar \nDistance", "Planar Kilometer Distance");
69 m_tableWin->addToTable(false, "Segments Sum\nkm", "Segments Sum", -1, Qt::Horizontal, "Sum of Segment lengths in kilometers");
70 m_tableWin->addToTable(false, "Segment Number", "Segment Number", -1, Qt::Horizontal, "Segment number of a segmented line");
71 m_tableWin->addToTable(false, "Path", "Path");
72 m_tableWin->addToTable(false, "FileName", "FileName");
73 m_tableWin->addToTable(false, "Notes", "Notes");
74
75 m_tableWin->setStatusMessage("Click, Drag, and Release to Measure a Line");
76
77 addRow();
78 }
79
80
90 QAction *action = new QAction(toolpad);
91 action->setIcon(QPixmap(toolIconDir() + "/measure.png"));
92 action->setToolTip("Measure (M)");
93 action->setShortcut(Qt::Key_M);
94
95 QString text =
96 "<b>Function:</b> Measure features in active viewport \
97 <p><b>Shortcut:</b> M</p> ";
98 action->setWhatsThis(text);
99
100 return action;
101 }
102
103
112 QWidget *MeasureTool::createToolBarWidget(QStackedWidget *parent) {
113 QWidget *hbox = new QWidget(parent);
114 QToolButton *measureButton = new QToolButton(hbox);
115 measureButton->setText("Table");
116 measureButton->setToolTip("Record Measurement Data in Table");
117 QString text =
118 "<b>Function:</b> This button will bring up a table that will record the \
119 starting and ending points of the line, along with the distance between \
120 the two points on the image. To measure the distance between two points, \
121 click on the first point and releasing the mouse at the second point. \
122 <p><b>Shortcut:</b> CTRL+M</p>";
123 measureButton->setWhatsThis(text);
124 measureButton->setShortcut(Qt::CTRL + Qt::Key_M);
125 connect(measureButton, SIGNAL(clicked()), m_tableWin, SLOT(showTable()));
126 connect(measureButton, SIGNAL(clicked()), m_tableWin, SLOT(syncColumns()));
127 connect(measureButton, SIGNAL(clicked()), m_tableWin, SLOT(raise()));
128 measureButton->setEnabled(true);
129
139 RubberBandComboBox::Line // default
140
141 );
142
143 m_distLineEdit = new QLineEdit(hbox);
144 m_distLineEdit->setText("");
145 m_distLineEdit->setMaxLength(12);
146 m_distLineEdit->setToolTip("Line Length");
147 QString text2 = "<b>Function: </b> Shows the length of the line drawn on \
148 the image.";
149 m_distLineEdit->setWhatsThis(text2);
150 m_distLineEdit->setReadOnly(true);
151
152 m_showAllSegments = new QCheckBox(hbox);
153 m_showAllSegments->setText("Show All Segments");
154
155 m_unitsComboBox = new QComboBox(hbox);
156 m_unitsComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
157
158 miComboUnit = -1;
159
161 connect(m_unitsComboBox, SIGNAL(activated(int)), this, SLOT(updateDistEdit()));
162 connect(rubberBandTool(), SIGNAL(modeChanged()), this, SLOT(updateUnitsCombo()));
163
164 QHBoxLayout *layout = new QHBoxLayout(hbox);
165 layout->setMargin(0);
166 layout->addWidget(m_rubberBand);
167 layout->addWidget(m_distLineEdit);
168 layout->addWidget(m_unitsComboBox);
169 layout->addWidget(measureButton);
170 layout->addWidget(m_showAllSegments);
171 layout->addStretch(1);
172 hbox->setLayout(layout);
173 return hbox;
174 }
175
176
182 // get the previous index if not initializing
183 if (miComboUnit >= 0) {
184 miComboUnit = m_unitsComboBox->currentIndex();
185 }
186
187 m_unitsComboBox->clear();
188 m_showAllSegments->setEnabled(false);
189
190 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode) {
191 m_unitsComboBox->addItem("km");
192 m_unitsComboBox->addItem("m");
193 m_unitsComboBox->addItem("pixels");
194 m_unitsComboBox->addItem("planar km");
195
196 if (miComboUnit < 0 || miComboUnit > 3) { // default && error checking
197 miComboUnit = 2;
198 }
199 }
200 else if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
201
202 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
203 m_showAllSegments->setEnabled(true);
204 }
205
206 m_unitsComboBox->addItem("km");
207 m_unitsComboBox->addItem("m");
208 m_unitsComboBox->addItem("pixels");
209 if (miComboUnit < 0 || miComboUnit > 2) { // default && error checking
210 miComboUnit = 2;
211 }
212 }
213 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
214 m_unitsComboBox->addItem("degrees");
215 m_unitsComboBox->addItem("radians");
216 if (miComboUnit > 1 || miComboUnit < 0) { // default && error checking
217 miComboUnit = 0;
218 }
219 }
220 else {
221 m_unitsComboBox->addItem("km^2");
222 m_unitsComboBox->addItem("m^2");
223 m_unitsComboBox->addItem("pix^2");
224 if (miComboUnit < 0 || miComboUnit > 2) { // default && error checking
225 miComboUnit = 2;
226 }
227 }
228
229 m_unitsComboBox->setCurrentIndex(miComboUnit);
230 }
231
232
240 menu->addAction(m_action);
241 }
242
243
251 m_numLinked = 0;
252
253 int currentRow = m_tableWin->currentRow();
254
255 while (currentRow >= m_tableWin->table()->rowCount()) {
256 addRow();
257 }
258
259 if (cvp == NULL) {
261 }
262 else {
263 updateDist(cvp, currentRow);
264 m_tableWin->table()->selectRow(currentRow);
265
266 if (cvp->isLinked()) {
267 for (int i = 0; i < (int)cubeViewportList()->size(); i++) {
268 d = (*(cubeViewportList()))[i];
269
270 if (d->isLinked() && d != cvp) {
271 m_numLinked++;
272
273 if (currentRow + m_numLinked >= m_tableWin->table()->rowCount()) {
274 addRow();
275 }
276
277 updateDist(d, currentRow + m_numLinked);
278 }
279 }
280 }
281 }
282 }
283
284
291
292 if (rubberBandTool()->currentMode() != RubberBandTool::AngleMode && m_unitsComboBox->currentIndex() != 2) {
293 if (cubeViewport()->camera() == NULL && cubeViewport()->projection() == NULL) {
294 QMessageBox::information((QWidget *)parent(), "Error",
295 "File must have a Camera Model or Projection to measure in km or m");
296 return;
297 }
298 }
299
300 if (!m_tableWin->table()->isVisible()) return;
301 if (m_tableWin->table()->item(m_tableWin->currentRow(), StartLineIndex)->text() == "N/A" &&
302 m_tableWin->table()->item(m_tableWin->currentRow(), AngleDegIndex)->text() == "N/A" &&
303 m_tableWin->table()->item(m_tableWin->currentRow(), AreaPixIndex)->text() == "N/A") return;
304
305 addRow();
306 m_tableWin->setCurrentRow(m_tableWin->table()->rowCount() - 1);
307
308 QApplication::sendPostedEvents(m_tableWin->table(), 0);
309 }
310
311
317 //m_tableWin->clearRow(m_tableWin->currentRow());
318 }
319
320
326 if (m_rubberBand) {
328 rubberBandTool()->setDrawActiveViewportOnly(false);
329 }
330 }
331
332
341
342 if (row >= m_tableWin->table()->rowCount()) {
343 return;
344 }
345
346 // Blank out the row to remove stuff left over from previous cvps
347 for (int c = 0; c < m_tableWin->table()->columnCount(); c++) {
348 m_tableWin->table()->item(row, c)->setText("");
349 }
350
351 // Write all the new info to the current row
352 if (m_startLat != Null && m_startLon != Null) {
353 m_tableWin->table()->item(row, StartLatIndex)->setText(QString::number(m_startLat));
354 m_tableWin->table()->item(row, StartLonIndex)->setText(QString::number(m_startLon));
355 }
356 else {
357 m_tableWin->table()->item(row, StartLatIndex)->setText("N/A");
358 m_tableWin->table()->item(row, StartLonIndex)->setText("N/A");
359 }
360
361 if (m_endLat != Null && m_endLon != Null) {
362 m_tableWin->table()->item(row, EndLatIndex)->setText(QString::number(m_endLat));
363 m_tableWin->table()->item(row, EndLonIndex)->setText(QString::number(m_endLon));
364 }
365 else {
366 m_tableWin->table()->item(row, EndLatIndex)->setText("N/A");
367 m_tableWin->table()->item(row, EndLonIndex)->setText("N/A");
368 }
369
370 if (m_mDist != Null && m_kmDist != Null) {
371 m_tableWin->table()->item(row, DistanceMIndex)->setText(QString::number(m_mDist));
372 m_tableWin->table()->item(row, DistanceKmIndex)->setText(QString::number(m_kmDist));
373 }
374 else {
375 m_tableWin->table()->item(row, DistanceKmIndex)->setText("N/A");
376 m_tableWin->table()->item(row, DistanceMIndex)->setText("N/A");
377 }
378
379 if (m_degAngle != Null && m_radAngle != Null) {
380 m_tableWin->table()->item(row, AngleDegIndex)->setText(QString::number(m_degAngle));
381 m_tableWin->table()->item(row, AngleRadIndex)->setText(QString::number(m_radAngle));
382 }
383 else {
384 m_tableWin->table()->item(row, AngleDegIndex)->setText("N/A");
385 m_tableWin->table()->item(row, AngleRadIndex)->setText("N/A");
386 }
387
388 if (m_startSamp != Null && m_startLine != Null) {
389 m_tableWin->table()->item(row, StartSampIndex)->setText(QString::number(m_startSamp));
390 m_tableWin->table()->item(row, StartLineIndex)->setText(QString::number(m_startLine));
391 }
392 else {
393 m_tableWin->table()->item(row, StartSampIndex)->setText("N/A");
394 m_tableWin->table()->item(row, StartLineIndex)->setText("N/A");
395 }
396
397 if (m_endSamp != Null && m_endLine != Null) {
398 m_tableWin->table()->item(row, EndSampIndex)->setText(QString::number(m_endSamp));
399 m_tableWin->table()->item(row, EndLineIndex)->setText(QString::number(m_endLine));
400 m_tableWin->table()->item(row, DistancePixIndex)->setText(QString::number(m_pixDist));
401 }
402 else {
403 m_tableWin->table()->item(row, EndSampIndex)->setText("N/A");
404 m_tableWin->table()->item(row, EndLineIndex)->setText("N/A");
405 m_tableWin->table()->item(row, DistancePixIndex)->setText("N/A");
406 }
407
408 if (m_pixArea != Null) {
409 m_tableWin->table()->item(row, AreaPixIndex)->setText(QString::number(m_pixArea));
410 }
411 else {
412 m_tableWin->table()->item(row, AreaPixIndex)->setText("N/A");
413 }
414
415 if (m_mArea != Null) {
416 m_tableWin->table()->item(row, AreaKmIndex)->setText(QString::number(m_kmArea));
417 m_tableWin->table()->item(row, AreaMIndex)->setText(QString::number(m_mArea));
418 }
419 else {
420 m_tableWin->table()->item(row, AreaKmIndex)->setText("N/A");
421 m_tableWin->table()->item(row, AreaMIndex)->setText("N/A");
422 }
423
424 if (m_kmPlanarDist != Null) {
425 m_tableWin->table()->item(row, PlanarDistanceIndex)->setText(QString::number(m_kmPlanarDist));
426 }
427 else {
428 m_tableWin->table()->item(row, PlanarDistanceIndex)->setText("N/A");
429 }
430
431 m_tableWin->table()->item(row, PathIndex)->setText(m_path);
432 m_tableWin->table()->item(row, FileNameIndex)->setText(m_fname);
433 }
434
435
436
445 int requiredRows = m_distanceSegments.size() + row;
446 int rowDiff = (int)(requiredRows - m_tableWin->table()->rowCount());
447
448 //Make sure we have all the necessary rows and items in each table cell.
449 if (requiredRows > m_tableWin->table()->rowCount()) {
450 for (int r = 0; r < rowDiff; r++) {
451 addRow();
452 }
453 }
454
455 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode &&
456 m_distanceSegments.size() > 0) {
457 double distanceSum = 0;
458 for (int i = 0; i < m_distanceSegments.size(); i++) {
459 //write a new row for each segment...
460 if (m_startLatSegments[i] != Null && m_startLonSegments[i] != Null) {
461 m_tableWin->table()->item(row + i, StartLatIndex)->setText(QString::number(m_startLatSegments[i]));
462 m_tableWin->table()->item(row + i, StartLonIndex)->setText(QString::number(m_startLonSegments[i]));
463 }
464 else {
465 m_tableWin->table()->item(row + i, StartLatIndex)->setText("N/A");
466 m_tableWin->table()->item(row + i, StartLonIndex)->setText("N/A");
467 }
468
469 if (m_endLatSegments[i] != Null && m_endLonSegments[i] != Null) {
470 m_tableWin->table()->item(row + i, EndLatIndex)->setText(QString::number(m_endLatSegments[i]));
471 m_tableWin->table()->item(row + i, EndLonIndex)->setText(QString::number(m_endLonSegments[i]));
472 }
473 else {
474 m_tableWin->table()->item(row + i, EndLatIndex)->setText("N/A");
475 m_tableWin->table()->item(row + i, EndLonIndex)->setText("N/A");
476 }
477
478 if (m_startSampSegments[i] != Null && m_startLineSegments[i] != Null) {
479 m_tableWin->table()->item(row + i, StartSampIndex)->setText(QString::number(m_startSampSegments[i]));
480 m_tableWin->table()->item(row + i, StartLineIndex)->setText(QString::number(m_startLineSegments[i]));
481 }
482 else {
483 m_tableWin->table()->item(row + i, StartSampIndex)->setText("N/A");
484 m_tableWin->table()->item(row + i, StartLineIndex)->setText("N/A");
485 }
486
487 if (m_endSampSegments[i] != Null && m_endLineSegments[i] != Null) {
488 m_tableWin->table()->item(row + i, EndSampIndex)->setText(QString::number(m_endSampSegments[i]));
489 m_tableWin->table()->item(row + i, EndLineIndex)->setText(QString::number(m_endLineSegments[i]));
490 }
491 else {
492 m_tableWin->table()->item(row + i, EndSampIndex)->setText("N/A");
493 m_tableWin->table()->item(row + i, EndLineIndex)->setText("N/A");
494 }
495
496 if (m_pixDistSegments[i] != Null) {
497 m_tableWin->table()->item(row + i, DistancePixIndex)->setText(QString::number(m_pixDistSegments[i]));
498 }
499 else {
500 m_tableWin->table()->item(row + i, DistancePixIndex)->setText("N/A");
501 }
502
503 if (m_distanceSegments[i] != Null) {
504 m_tableWin->table()->item(row + i, DistanceKmIndex)->setText(QString::number(m_distanceSegments[i]));
505 m_tableWin->table()->item(row + i, DistanceMIndex)->setText(QString::number(m_distanceSegments[i] * 1000.0));
506 }
507 else {
508 m_tableWin->table()->item(row + i, DistanceKmIndex)->setText("N/A");
509 m_tableWin->table()->item(row + i, DistanceMIndex)->setText("N/A");
510 }
511
512 m_tableWin->table()->item(row + i, PathIndex)->setText(m_path);
513 m_tableWin->table()->item(row + i, FileNameIndex)->setText(m_fname);
514
515 distanceSum = (Distance(distanceSum, Distance::Kilometers) +
516 Distance(m_distanceSegments[i], Distance::Kilometers)).kilometers();
517
518 if (distanceSum != Null) {
519 m_tableWin->table()->item(row + i, SegmentsSumIndex)->setText(QString::number(distanceSum));
520 }
521 else {
522 m_tableWin->table()->item(row + i, SegmentsSumIndex)->setText("N/A");
523 }
524
525 m_tableWin->table()->item(row + i, SegmentNumberIndex)->setText(QString::number(i + 1));
526 }
527 }
528 }
529
536 // Initialize the class data
538 m_endSamp = Null;
540 m_endLine = Null;
541 m_kmDist = Null;
542 m_mDist = Null;
543 m_pixDist = Null;
546 m_endLon = Null;
547 m_endLat = Null;
550 m_pixArea = Null;
551 m_kmArea = Null;
552 m_mArea = Null;
554 }
555
556
557 void MeasureTool::addRow() {
558 int newRowPos = m_tableWin->table()->rowCount();
559 m_tableWin->table()->insertRow(newRowPos);
560 for (int c = 0; c < m_tableWin->table()->columnCount(); c++) {
561 QTableWidgetItem *item = new QTableWidgetItem("");
562 m_tableWin->table()->setItem(newRowPos, c, item);
563 }
564 m_tableWin->table()->scrollToItem(m_tableWin->table()->item(newRowPos, 0),
565 QAbstractItemView::PositionAtBottom);
566 }
567
568
579 // Initialize class data
580 initData();
581
582 // Write out col 8 (the file name)
584 cvp->cube()->fileName()).expanded();
585 m_path = fname.path();
586 m_fname = fname.name();
587
588 m_pixDist = Null;
589 m_mDist = Null;
590 m_kmDist = Null;
591
592 // reset the distnace gui
593 m_distLineEdit->setText("");
594
595 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode ||
596 rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
597 m_distanceSegments.clear();
598 m_pixDistSegments.clear();
599 m_startSampSegments.clear();
600 m_endSampSegments.clear();
601 m_startLineSegments.clear();
602 m_endLineSegments.clear();
603 m_startLatSegments.clear();
604 m_endLatSegments.clear();
605 m_startLonSegments.clear();
606 m_endLonSegments.clear();
607
608 for (int startIndex = 0; startIndex < rubberBandTool()->vertices().size() - 1; startIndex++) {
609 QPoint start = rubberBandTool()->vertices()[startIndex];
610 QPoint end = rubberBandTool()->vertices()[startIndex + 1];
611
612 setDistances(cvp, start, end);
613
614 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
615 if (m_distanceSegments.size() < 75) {
616 m_distanceSegments.append(m_kmDist);
617 m_pixDistSegments.append(m_pixDist);
618 m_startSampSegments.append(m_startSamp);
619 m_endSampSegments.append(m_endSamp);
620 m_startLineSegments.append(m_startLine);
621 m_endLineSegments.append(m_endLine);
622 m_startLatSegments.append(m_startLat);
623 m_endLatSegments.append(m_endLat);
624 m_startLonSegments.append(m_startLon);
625 m_endLonSegments.append(m_endLon);
626 }
627 }
628 }
629
630 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode &&
631 m_pixDistSegments.size()) {
632 m_pixDist = m_pixDistSegments[0];
633 m_kmDist = m_distanceSegments[0];
635
636 for (int i = 1; i < m_pixDistSegments.size(); i++) {
638 Distance(m_pixDistSegments[i], Distance::Pixels)).pixels();
639
640 Distance thisDistance(m_distanceSegments[i], Distance::Kilometers);
642 thisDistance).kilometers();
644 thisDistance).meters();
645 }
646 }
647 }
648 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
649 m_radAngle = rubberBandTool()->angle().radians();
650 m_degAngle = rubberBandTool()->angle().degrees();
651 }
652 else {
653 geos::geom::Geometry *polygon = rubberBandTool()->geometry();
654 if (polygon != NULL) {
655 // pix area = screenpix^2 / scale^2
656 m_pixArea = polygon->getArea() / pow(cvp->scale(), 2);
657 geos::geom::Point *center = polygon->getCentroid().release();
658 double line, sample;
659 cvp->viewportToCube((int)center->getX(), (int)center->getY(), sample, line);
660
661 if (cvp->camera() != NULL) {
662 cvp->camera()->SetImage(sample, line);
663 // pix^2 * (m/pix)^2 = m^2
664 m_mArea = m_pixArea * pow(cvp->camera()->PixelResolution(), 2);
665 // m^2 * (km/m)^2 = km^2
666 m_kmArea = m_mArea * pow(1 / 1000.0, 2);
667 }
668
669 if (cvp->projection() != NULL) {
670 cvp->projection()->SetWorld(sample, line);
671 // pix^2 * (m/pix)^2 = m^2
672 m_mArea = m_pixArea * pow(cvp->projection()->Resolution(), 2);
673 // m^2 * (km/m)^2 = km^2
674 m_kmArea = m_mArea * pow(1 / 1000.0, 2);
675 }
676 }
677
678 if (rubberBandTool()->currentMode() == RubberBandTool::RectangleMode) {
679 setDistances(cvp, rubberBandTool()->vertices()[0],
680 rubberBandTool()->vertices()[2]);
681 }
682 }
683
685
686 if (m_showAllSegments->isChecked() &&
687 rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
688 updateRows(row);
689 }
690 else {
691 updateRow(row);
692 }
693 }
694
695
696 void MeasureTool::setDistances(MdiCubeViewport *cvp, QPoint lineStart,
697 QPoint lineEnd) {
698 // Convert rubber band line to cube coordinates
699 cvp->viewportToCube(lineStart.x(), lineStart.y(), m_startSamp, m_startLine);
700 cvp->viewportToCube(lineEnd.x(), lineEnd.y(), m_endSamp, m_endLine);
701
702 m_mDist = Null;
703 m_kmDist = Null;
705 double radius = Null;
706 TProjection *tproj = NULL;
707 RingPlaneProjection *rproj = NULL;
709
710 // Get set for dealing with projection types
711 if (cvp->projection() != NULL) projType = cvp->projection()->projectionType();
712
713 // Don't write anything if we are outside the cube
714 if ((m_startSamp >= 0.5) && (m_endSamp >= 0.5) &&
715 (m_startLine >= 0.5) && (m_endLine >= 0.5) &&
716 (m_startSamp <= cvp->cubeSamples() + 0.5) &&
717 (m_endSamp <= cvp->cubeSamples() + 0.5) &&
718 (m_startLine <= cvp->cubeLines() + 0.5) &&
719 (m_endLine <= cvp->cubeLines() + 0.5)) {
720 // Check if the image is projected (Projected Images also have camera
721 // except for mosaics)
722 if (cvp->projection() != NULL) {
723 if (cvp->projection()->SetWorld(m_startSamp, m_startLine)) {
724 // If our projection is sky, the lat & lons are switched
725 if (cvp->projection()->IsSky()) {
726
727 tproj = (TProjection *) cvp->projection();
728 m_startLat = tproj->UniversalLatitude();
729 m_startLon = tproj->UniversalLongitude();
730 }
731 else if (projType == Projection::Triaxial) {
732 tproj = (TProjection *) cvp->projection();
733 m_startLat = tproj->UniversalLatitude();
734 m_startLon = tproj->UniversalLongitude();
735 }
736 else { // RingPlaneProjection
737 rproj = (RingPlaneProjection *) cvp->projection();
738 m_startLat = rproj->UniversalRingRadius();
739 m_startLon = rproj->UniversalRingLongitude();
740 }
741
742 if (cvp->projection()->SetWorld(m_endSamp, m_endLine)) {
743 // If our projection is sky, the lat & lons are switched
744 if (cvp->projection()->IsSky()) {
745 m_endLat = tproj->UniversalLatitude();
746 m_endLon = tproj->UniversalLongitude();
747 }
748 else if (projType == Projection::Triaxial) {
749 m_endLat = tproj->UniversalLatitude();
750 m_endLon = tproj->UniversalLongitude();
751 } // RingPlaneProjection
752 else {
753 m_endLat = rproj->UniversalRingRadius();
754 m_endLon = rproj->UniversalRingLongitude();
755 }
756 }
757
758 // Calculate and write out the distance between the two points
759 if (projType != Projection::RingPlane) {
760 radius = tproj->LocalRadius();
761 }
762 else {
763 radius = rproj->RingRadius();
764 }
765 }
766 }
767 // Do we have a camera model?
768 else if (cvp->camera() != NULL &&
769 cvp->camera()->SetImage(m_startSamp, m_startLine)) {
770 // Write columns 2-3 (Start lat/lon)
771 m_startLat = cvp->camera()->UniversalLatitude();
772 m_startLon = cvp->camera()->UniversalLongitude();
773
774 if (cvp->camera()->SetImage(m_endSamp, m_endLine)) {
775 // Write columns 4-5 (End lat/lon)
776 m_endLat = cvp->camera()->UniversalLatitude();
777 m_endLon = cvp->camera()->UniversalLongitude();
778
779 radius = cvp->camera()->LocalRadius().meters();
780 }
781 }
782 }
783
784 // Calculate the pixel difference
785 double lineDif = m_startLine - m_endLine;
786 double sampDif = m_startSamp - m_endSamp;
787 double pixDist = sqrt(lineDif * lineDif + sampDif * sampDif);
788 m_pixDist = pixDist;
789
790 Latitude startLat(m_startLat, Angle::Degrees);
791 Longitude startLon(m_startLon, Angle::Degrees);
792 Latitude endLat(m_endLat, Angle::Degrees);
793 Longitude endLon(m_endLon, Angle::Degrees);
794 Distance radiusDist(radius, Distance::Meters);
795
796 SurfacePoint startPoint;
797 SurfacePoint endPoint;
798
799 if (startLat.isValid() && startLon.isValid() &&
800 endLat.isValid() && endLon.isValid() && radiusDist.isValid()) {
801 startPoint = SurfacePoint(startLat, startLon, radiusDist);
802 endPoint = SurfacePoint(endLat, endLon, radiusDist);
803 }
804
805 Distance distance = startPoint.GetDistanceToPoint(endPoint, radiusDist);
806
807 m_mDist = distance.meters();
808 m_kmDist = distance.kilometers();
809
810 if (cvp->camera() != NULL) {
811
812 // Make sure start line or end line setimage succeeds, otherwise fail.
813 bool statusStart = cvp->camera()->SetImage(m_startSamp, m_startLine);
814 double slantDist = 0;
815 if (statusStart) {
816 slantDist = cvp->camera()->SlantDistance();
817 }
818
819 double ra1 = cvp->camera()->RightAscension() * DEG2RAD;
820 double dec1 = cvp->camera()->Declination()* DEG2RAD;
821
822 bool statusEnd = cvp->camera()->SetImage(m_endSamp, m_endLine);
823 if ((!statusStart)&&statusEnd) {
824 slantDist = cvp->camera()->SlantDistance();
825 }
826
827 // Cannot calculate a planar distance with no point on the target.
828 if (!(statusStart||statusEnd)) {
829 return;
830 }
831
832 double ra2 = cvp->camera()->RightAscension() * DEG2RAD;
833 double dec2 = cvp->camera()->Declination()* DEG2RAD;
834
835 double dRA = (ra1 - ra2);
836
837 double angle = acos(sin(dec1)*sin(dec2) + cos(dec1)*cos(dec2)*cos(dRA));
838 double half_angle = angle/2.0;
839 double length = slantDist * sin(half_angle) * 2.0;
840
841 m_kmPlanarDist = length;
842 }
843 }
844
845
848 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode ||
849 rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
850 if (m_unitsComboBox->currentIndex() == 0) {
851 if (m_kmDist == Null) {
852 m_distLineEdit->setText("N/A");
853 }
854 else {
855 m_distLineEdit->setText(QString::number(m_kmDist));
856 }
857 }
858 else if (m_unitsComboBox->currentIndex() == 1) {
859 if (m_mDist == Null) {
860 m_distLineEdit->setText("N/A");
861 }
862 else {
863 m_distLineEdit->setText(QString::number(m_mDist));
864 }
865 }
866 else if (m_unitsComboBox->currentIndex() == 3) {
867 if (m_kmPlanarDist == Null) {
868 m_distLineEdit->setText("N/A");
869 }
870 else {
871 m_distLineEdit->setText(QString::number(m_kmPlanarDist));
872 }
873 }
874 else {
875 m_distLineEdit->setText(QString::number(m_pixDist));
876 }
877 }
878 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
879 if (m_unitsComboBox->currentIndex() == 0) {
880 m_distLineEdit->setText(QString::number(m_degAngle));
881 }
882 else {
883 m_distLineEdit->setText(QString::number(m_radAngle));
884 }
885 }
886 else {
887 if (m_unitsComboBox->currentIndex() == 0) {
888 if (m_kmArea == Null) {
889 m_distLineEdit->setText("N/A");
890 }
891 else {
892 m_distLineEdit->setText(QString::number(m_kmArea));
893 }
894 }
895 else if (m_unitsComboBox->currentIndex() == 1) {
896 if (m_mArea == Null) {
897 m_distLineEdit->setText("N/A");
898 }
899 else {
900 m_distLineEdit->setText(QString::number(m_mArea));
901 }
902 }
903 else {
904 if (m_pixArea != Null) {
905 m_distLineEdit->setText(QString::number(m_pixArea));
906 }
907 else {
908 m_distLineEdit->setText("N/A");
909 }
910 }
911 }
912 }
913
914
922 // cvp->repaint();
923 cvp->update();
924 }
925
926
932 m_distLineEdit->clear();
933 }
934
935}
936
double radians() const
Convert an angle to a double.
Definition Angle.h:226
double degrees() const
Get the angle in units of Degrees.
Definition Angle.h:232
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
Distance measurement, usually in meters.
Definition Distance.h:34
@ Pixels
The distance is being specified in pixels.
Definition Distance.h:47
@ Kilometers
The distance is being specified in kilometers.
Definition Distance.h:45
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
double meters() const
Get the distance in meters.
Definition Distance.cpp:85
File name manipulation and expansion.
Definition FileName.h:100
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition FileName.cpp:196
Cube display widget for certain Isis MDI applications.
bool isLinked() const
Is the viewport linked with other viewports.
double m_kmArea
area in kilometers
TableMainWindow * m_tableWin
table window
double m_startLat
starting latitude
double m_mDist
distance in meters
double m_pixDist
distance in pixels
@ StartSampIndex
Starting sample index.
@ AreaPixIndex
Area in pixels index.
@ DistanceKmIndex
Distance in kilometers index.
@ DistanceMIndex
Distance in meters index.
@ EndLonIndex
Ending longitude index.
@ FileNameIndex
FileName index.
@ AngleDegIndex
Angle in degrees index.
@ EndSampIndex
Ending sample index.
@ EndLineIndex
Ending line index.
@ AreaMIndex
Area in meters index.
@ AngleRadIndex
Angle in radians index.
@ SegmentsSumIndex
Segment lengths in kilometers.
@ SegmentNumberIndex
Segment number.
@ StartLonIndex
Starting longitude index.
@ EndLatIndex
Ending latitude index.
@ StartLineIndex
Starting line index.
@ StartLatIndex
Starting latitude index.
@ DistancePixIndex
Distance in pixels index.
@ AreaKmIndex
Area in kilometers index.
@ PathIndex
FileName path index.
@ PlanarDistanceIndex
Planar distance in kilometers.
double m_startSamp
starting sample
double m_endSamp
ending sample
QComboBox * m_unitsComboBox
Units selection.
Definition MeasureTool.h:90
double m_startLine
starting line
void updateDist(MdiCubeViewport *cvp, int row)
This method updates the distance variables.
RubberBandComboBox * m_rubberBand
rubberband combo box
void initData(void)
Initialize Class data.
QAction * m_action
Measure tool's action.
Definition MeasureTool.h:88
void updateTool()
Updates the measure tool.
int m_numLinked
number of linked viewports
double m_kmDist
distance in kilometers
double m_pixArea
area in pixels
virtual void rubberBandComplete()
Called when the rubberBanding by the user is finished.
double m_radAngle
angle in radians
virtual void mouseLeave()
Mouse leave event.
double m_mArea
area in meters
double m_endLine
ending line
void updateRows(int row)
This method is called instead of updateRows if the 'Show All Segment' checkbox is checked.
void updateDistEdit()
Change the value in the distance edit to match the units.
void enableRubberBandTool()
Enables/resets the rubberband tool.
QWidget * createToolBarWidget(QStackedWidget *parent)
Creates the widget (button) that goes on the tool bar.
double m_kmPlanarDist
distance estimate used when at least one point is on the body (km)
void updateUnitsCombo()
Updates the units combo box.
MeasureTool(QWidget *parent)
MeasureTool constructor.
void updateRow(int row)
This method updates the row in the table window with the current measure information.
void removeConnections(MdiCubeViewport *cvp)
Removes the connection on the given cube viewport.
double m_startLon
starting longitude
double m_endLat
ending latitude
QString m_fname
filename
QAction * toolPadAction(ToolPad *pad)
Add the measure tool action to the toolpad.
QLineEdit * m_distLineEdit
Distance line edit.
Definition MeasureTool.h:89
virtual void updateMeasure()
Updates the Measure specifications.
double m_degAngle
angle in degrees
void addTo(QMenu *menu)
Adds the measure action to the given menu.
double m_endLon
ending longitude
QString m_path
filename path
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition Projection.h:166
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
Definition Projection.h:166
@ RingPlane
These projections are used to map ring planes.
Definition Projection.h:168
ProjectionType projectionType() const
Returns an enum value for the projection type.
Base class for Map Projections of plane shapes.
Combo box for choosing a rubber band type.
void reset()
Resets the selection.
@ RotatedRectangle
RotatedRectangle.
geos::geom::Geometry * geometry()
void setDrawActiveViewportOnly(bool activeOnly=false)
This called to set whether rubber band is drawn on active viewport only rather than all linked viewpo...
QList< QPoint > vertices()
This method returns the vertices.
Base class for Map TProjections.
a subclass of the qisis mainwindow, tablemainwindow handles all of the table tasks.
QTableWidget * table() const
Returns the table.
void addToTable(bool setOn, const QString &heading, const QString &menuText="", int insertAt=-1, Qt::Orientation o=Qt::Horizontal, QString toolTip="")
Adds a new column to the table when a new curve is added to the plot.
void setCurrentRow(int row)
Sets the current row to row.
int currentRow() const
Returns the current row.
void setTrackListItems(bool track=false)
If this property is true, the class will keep track of the checked/unchecked items in the dock area w...
void clearRow(int row)
This method clears the text of the given row.
void setStatusMessage(QString message)
sets the status message in the lower lefthand corner of the window.
Base class for the Qisis tools.
Definition Tool.h:67
CubeViewportList * cubeViewportList() const
Return the list of cubeviewports.
Definition Tool.cpp:390
MdiCubeViewport * cubeViewport() const
Return the current cubeviewport.
Definition Tool.h:197
QString toolIconDir() const
returns the path to the icon directory.
Definition Tool.h:113
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double DEG2RAD
Multiplier for converting from degrees to radians.
Definition Constants.h:43
const double Null
Value for an Isis Null pixel.