1#include "MeasureTool.h"
11#include <QStackedWidget>
13#include <QTableWidget>
16#include <geos/geom/Geometry.h>
17#include <geos/geom/Point.h>
24#include "MdiCubeViewport.h"
25#include "Projection.h"
26#include "RingPlaneProjection.h"
27#include "TProjection.h"
28#include "SurfacePoint.h"
56 "Start\nLatitude:Start\nLongitude:End\nLatitude:End\nLongitude",
57 "Ground Range", -1, Qt::Horizontal,
"Start Latitude/Longitude to End Latitude/Longitude");
59 "Pixel Range", -1, Qt::Horizontal,
"Start Sample/Line to End Sample/Line");
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");
91 action->setIcon(QPixmap(
toolIconDir() +
"/measure.png"));
92 action->setToolTip(
"Measure (M)");
93 action->setShortcut(Qt::Key_M);
96 "<b>Function:</b> Measure features in active viewport \
97 <p><b>Shortcut:</b> M</p> ";
98 action->setWhatsThis(text);
114 QToolButton *measureButton =
new QToolButton(hbox);
115 measureButton->setText(
"Table");
116 measureButton->setToolTip(
"Record Measurement Data in Table");
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);
147 QString text2 =
"<b>Function: </b> Shows the length of the line drawn on \
152 m_showAllSegments =
new QCheckBox(hbox);
153 m_showAllSegments->setText(
"Show All Segments");
162 connect(rubberBandTool(), SIGNAL(modeChanged()),
this, SLOT(
updateUnitsCombo()));
164 QHBoxLayout *layout =
new QHBoxLayout(hbox);
165 layout->setMargin(0);
169 layout->addWidget(measureButton);
170 layout->addWidget(m_showAllSegments);
171 layout->addStretch(1);
172 hbox->setLayout(layout);
183 if (miComboUnit >= 0) {
188 m_showAllSegments->setEnabled(
false);
190 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode) {
196 if (miComboUnit < 0 || miComboUnit > 3) {
200 else if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
202 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
203 m_showAllSegments->setEnabled(
true);
209 if (miComboUnit < 0 || miComboUnit > 2) {
213 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
216 if (miComboUnit > 1 || miComboUnit < 0) {
224 if (miComboUnit < 0 || miComboUnit > 2) {
266 if (cvp->isLinked()) {
292 if (rubberBandTool()->currentMode() != RubberBandTool::AngleMode &&
m_unitsComboBox->currentIndex() != 2) {
294 QMessageBox::information((
QWidget *)parent(),
"Error",
295 "File must have a Camera Model or Projection to measure in km or m");
445 int requiredRows = m_distanceSegments.size() + row;
450 for (
int r = 0; r < rowDiff; r++) {
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++) {
460 if (m_startLatSegments[i] !=
Null && m_startLonSegments[i] !=
Null) {
469 if (m_endLatSegments[i] !=
Null && m_endLonSegments[i] !=
Null) {
478 if (m_startSampSegments[i] !=
Null && m_startLineSegments[i] !=
Null) {
487 if (m_endSampSegments[i] !=
Null && m_endLineSegments[i] !=
Null) {
496 if (m_pixDistSegments[i] !=
Null) {
503 if (m_distanceSegments[i] !=
Null) {
518 if (distanceSum !=
Null) {
557 void MeasureTool::addRow() {
561 QTableWidgetItem *item =
new QTableWidgetItem(
"");
565 QAbstractItemView::PositionAtBottom);
584 cvp->cube()->fileName()).
expanded();
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();
608 for (
int startIndex = 0; startIndex < rubberBandTool()->
vertices().size() - 1; startIndex++) {
609 QPoint start = rubberBandTool()->
vertices()[startIndex];
610 QPoint end = rubberBandTool()->
vertices()[startIndex + 1];
612 setDistances(cvp, start, end);
614 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
615 if (m_distanceSegments.size() < 75) {
616 m_distanceSegments.append(
m_kmDist);
630 if (rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode &&
631 m_pixDistSegments.size()) {
636 for (
int i = 1; i < m_pixDistSegments.size(); i++) {
642 thisDistance).kilometers();
644 thisDistance).meters();
648 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
653 geos::geom::Geometry *polygon = rubberBandTool()->
geometry();
654 if (polygon != NULL) {
656 m_pixArea = polygon->getArea() / pow(cvp->scale(), 2);
657 geos::geom::Point *center = polygon->getCentroid().release();
659 cvp->viewportToCube((
int)center->getX(), (
int)center->getY(), sample, line);
661 if (cvp->camera() != NULL) {
662 cvp->camera()->SetImage(sample, line);
669 if (cvp->projection() != NULL) {
670 cvp->projection()->SetWorld(sample, line);
678 if (rubberBandTool()->currentMode() == RubberBandTool::RectangleMode) {
679 setDistances(cvp, rubberBandTool()->vertices()[0],
680 rubberBandTool()->vertices()[2]);
686 if (m_showAllSegments->isChecked() &&
687 rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
705 double radius =
Null;
711 if (cvp->projection() != NULL) projType = cvp->projection()->
projectionType();
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)) {
722 if (cvp->projection() != NULL) {
725 if (cvp->projection()->IsSky()) {
732 tproj = (TProjection *) cvp->projection();
737 rproj = (RingPlaneProjection *) cvp->projection();
744 if (cvp->projection()->IsSky()) {
745 m_endLat = tproj->UniversalLatitude();
746 m_endLon = tproj->UniversalLongitude();
749 m_endLat = tproj->UniversalLatitude();
750 m_endLon = tproj->UniversalLongitude();
753 m_endLat = rproj->UniversalRingRadius();
754 m_endLon = rproj->UniversalRingLongitude();
760 radius = tproj->LocalRadius();
763 radius = rproj->RingRadius();
768 else if (cvp->camera() != NULL &&
771 m_startLat = cvp->camera()->UniversalLatitude();
772 m_startLon = cvp->camera()->UniversalLongitude();
776 m_endLat = cvp->camera()->UniversalLatitude();
777 m_endLon = cvp->camera()->UniversalLongitude();
779 radius = cvp->camera()->LocalRadius().meters();
787 double pixDist = sqrt(lineDif * lineDif + sampDif * sampDif);
796 SurfacePoint startPoint;
797 SurfacePoint endPoint;
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);
805 Distance distance = startPoint.GetDistanceToPoint(endPoint, radiusDist);
810 if (cvp->camera() != NULL) {
814 double slantDist = 0;
816 slantDist = cvp->camera()->SlantDistance();
819 double ra1 = cvp->camera()->RightAscension() *
DEG2RAD;
820 double dec1 = cvp->camera()->Declination()*
DEG2RAD;
823 if ((!statusStart)&&statusEnd) {
824 slantDist = cvp->camera()->SlantDistance();
828 if (!(statusStart||statusEnd)) {
832 double ra2 = cvp->camera()->RightAscension() *
DEG2RAD;
833 double dec2 = cvp->camera()->Declination()*
DEG2RAD;
835 double dRA = (ra1 - ra2);
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;
848 if (rubberBandTool()->currentMode() == RubberBandTool::LineMode ||
849 rubberBandTool()->currentMode() == RubberBandTool::SegmentedLineMode) {
878 else if (rubberBandTool()->currentMode() == RubberBandTool::AngleMode) {
double radians() const
Convert an angle to a double.
double degrees() const
Get the angle in units of Degrees.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Distance measurement, usually in meters.
@ Pixels
The distance is being specified in pixels.
@ Kilometers
The distance is being specified in kilometers.
@ Meters
The distance is being specified in meters.
double meters() const
Get the distance in meters.
File name manipulation and expansion.
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Cube display widget for certain Isis MDI applications.
bool isLinked() const
Is the viewport linked with other viewports.
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
@ RingPlane
These projections are used to map ring planes.
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.
@ SegmentedLine
Segmented Line.
@ RotatedRectangle
RotatedRectangle.
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.
This is free and unencumbered software released into the public domain.
const double DEG2RAD
Multiplier for converting from degrees to radians.
const double Null
Value for an Isis Null pixel.