1#include "FeatureNomenclatureTool.h"
10#include <QDesktopServices>
16#include <QProgressBar>
22#include <geos/geom/Coordinate.h>
23#include <geos/geom/CoordinateSequence.h>
24#include <geos/geom/MultiPolygon.h>
28#include "ImagePolygon.h"
31#include "MdiCubeViewport.h"
32#include "NomenclatureToolConfigDialog.h"
33#include "PolygonTools.h"
61 new QMap< MdiCubeViewport *, FeatureNomenclature *>;
71 "in your opened cube files. This tool <strong>requires</strong> an "
72 "active internet connection, projection or camera information, and a "
73 "calculatable ground range to function. The larger the ground range ("
74 "covered area on a planet), the longer it will take to populate the "
75 "nomenclature for a particular cube.<br/><br/>"
76 "<font color='red'>**WARNING**</font> The accuracy of this tool is not "
77 "perfect, features <strong>can and will be mislabeled</strong> if you "
78 "have not properly controlled your images to the control network that "
79 "identifies the latitude/longitude values of a feature. Please use the "
80 "nomenclature website to verify a label is correct for a feature. "
81 "<br/><br/>See the IAU Gazetteer of Planetary Nomenclature website for "
82 "more information.<br/>"
83 "<a href='http://planetarynames.wr.usgs.gov/'>"
84 "http://planetarynames.wr.usgs.gov/</a>";
86 connect(
this, SIGNAL(toolActivated()),
117 m_action = menu->addAction(
"Show Nomenclature");
121 connect(
m_action, SIGNAL(triggered(
bool)),
139 painter->setFont(fontToUse);
221 vp->viewport()->update();
240 vp->viewport()->update();
258 vp->viewport()->update();
275 (*m_foundNomenclature)[i].applyExtentType(
m_extentType);
281 vp->viewport()->update();
304 QStackedWidget *parent) {
313 QLabel *foundFeaturesLabel =
new QLabel(
"Found Features:");
316 QComboBox::AdjustToContents);
341 QHBoxLayout *layout =
new QHBoxLayout;
342 layout->setMargin(0);
344 layout->addWidget(foundFeaturesLabel);
350 layout->addStretch(1);
351 wrapperWidget->setLayout(layout);
352 return wrapperWidget;
367 action->setIcon(QPixmap(
toolIconDir() +
"/nomenclature.png"));
368 action->setToolTip(
"Nomenclature (N)");
369 action->setShortcut(Qt::Key_N);
370 action->setObjectName(
"nomenclatureToolButton");
373 "<b>Function:</b> Display nomenclature on the visible images.\n"
374 "<p/><b>Hint:</b> While this tool is active, you can left and right "
375 "click on any of the named features for additional options."
376 "<p/><b>Shortcut:</b> N";
377 action->setWhatsThis(text);
392 QPoint p, Qt::MouseButton s) {
435 qobject_cast<QWidget *>(parent()));
436 configDialog->setAttribute(Qt::WA_DeleteOnClose);
437 configDialog->show();
478 viewport->viewport()->update();
488 if (newState == Qt::Unchecked) {
492 else if (newState == Qt::Checked) {
500 vp->viewport()->update();
514 (*m_foundNomenclature)[i].handleViewChanged(
this);
535 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
553 if (viewport == vp ||
554 (vp->isLinked() && viewport->
isLinked())) {
571 QList<FeatureNomenclature::Feature> features;
585 QProgressDialog updatingFeaturesProgress(
586 tr(
"Projecting Features for [%1]").arg(vp->cube()->fileName().section(
'/',-1)),
589 updatingFeaturesProgress.setWindowModality(Qt::WindowModal);
593 for (
int i = 0; i < features.count(); i++) {
594 feature = features[i];
596 int progress = floor(100 * (
double)i / (
double)features.count());
598 if (progress != updatingFeaturesProgress.value())
599 updatingFeaturesProgress.setValue(progress);
601 if (updatingFeaturesProgress.wasCanceled()) {
612 QString displayName = feature.
cleanName() +
615 QString targetName = feature.
target().toUpper();
622 while (!foundInsertPos) {
624 foundInsertPos =
true;
629 QString insertPosTarget = insetPosData.toMap()[
"Target"].toString();
631 if (targetName < insertPosTarget) {
632 foundInsertPos =
true;
634 else if (targetName == insertPosTarget) {
635 if (!insetPosData.toMap()[
"Viewport"].isNull()) {
636 foundInsertPos = displayName.compare(
638 Qt::CaseInsensitive) < 0;
648 "Target"].toString() != targetName) {
649 QMap<QString, QVariant> data;
650 data[
"Target"] = targetName;
653 if (controlNet !=
"")
654 controlNet =
" (" + controlNet +
")";
657 targetName + controlNet,
673 QMap<QString, QVariant> data;
674 data[
"Feature"] = QVariant::fromValue<FeatureNomenclature::Feature>(
676 data[
"Viewport"] = QVariant::fromValue(vp);
677 data[
"Target"] = QVariant::fromValue(targetName);
680 QVariant::fromValue(data));
683 updatingFeaturesProgress.setValue( features.count() );
699 QList<MdiCubeViewport *> removedViewports =
703 removedViewports.removeOne(vp);
713 bool removedAViewport =
false;
717 removedAViewport =
true;
720 if (removedAViewport) {
744 target = vp->camera()->target()->name();
746 else if (vp->projection()) {
747 PvlGroup mappingGrp = vp->projection()->Mapping();
749 if (mappingGrp.hasKeyword(
"TargetName"))
750 target = mappingGrp[
"TargetName"][0];
757 if (ugm->GroundRange(vp->cube(), minLat, maxLat, minLon, maxLon) &&
763 (*m_nomenclatureSearchers)[vp] = searcher;
765 (*m_nomenclatureSearchers)[vp]->queryFeatures(target.toUpper(),
816 QDialog *detailsDialog =
new QDialog(qobject_cast<QWidget *>(parent()));
817 detailsDialog->setAttribute(Qt::WA_DeleteOnClose);
819 QVBoxLayout *mainLayout =
new QVBoxLayout;
820 detailsDialog->setLayout(mainLayout);
822 mainLayout->addWidget(feature.
toWidget());
826 QHBoxLayout *buttonsAreaLayout =
new QHBoxLayout;
827 buttonsAreaWrapper->setLayout(buttonsAreaLayout);
829 buttonsAreaLayout->addStretch();
830 QPushButton *okayBtn =
new QPushButton(
"&Ok");
831 okayBtn->setIcon(QIcon::fromTheme(
"dialog-ok"));
832 connect(okayBtn, SIGNAL(clicked()),
833 detailsDialog, SLOT(accept()));
834 buttonsAreaLayout->addWidget(okayBtn);
836 mainLayout->addWidget(buttonsAreaWrapper);
838 detailsDialog->show();
861 if (isCurrentlyLoading) {
895 (*m_nomenclatureSearchers)[vp]->deleteLater();
926 return &(*m_foundNomenclature)[i];
945 return &(*m_foundNomenclature)[i];
972 QList<MdiCubeViewport *>
974 QList<MdiCubeViewport *> result;
991 FileName config(
"$HOME/.Isis/qview/nomenclature.config");
993 config.expanded(), QSettings::NativeFormat);
1013 FileName config(
"$HOME/.Isis/qview/nomenclature.config");
1015 config.expanded(), QSettings::NativeFormat);
1017 settings.setValue(
"fontColor", QVariant::fromValue(*
m_fontColor));
1049 m_centerLine =
Null;
1050 m_centerSample =
Null;
1051 m_featureEdgeLineSamples = NULL;
1054 m_featureEdgeLineSamples =
new QList< QPair<double, double> >;
1056 m_feature = feature;
1059 m_gmap = vp->universalGroundMap();
1060 Latitude centerLat = m_feature.centerLatitude();
1061 Longitude centerLon = m_feature.centerLongitude();
1062 if (m_gmap && m_gmap->SetGround(centerLat, centerLon)) {
1063 m_centerSample = m_gmap->Sample();
1064 m_centerLine = m_gmap->Line();
1079 m_centerLine = other.m_centerLine;
1080 m_centerSample = other.m_centerSample;
1081 m_featureEdgeLineSamples = NULL;
1084 m_featureEdgeLineSamples =
new QList< QPair<double, double> >(
1085 *other.m_featureEdgeLineSamples);
1087 m_feature = other.m_feature;
1098 m_centerLine =
Null;
1099 m_centerSample =
Null;
1102 delete m_featureEdgeLineSamples;
1103 m_featureEdgeLineSamples = NULL;
1113 return (m_centerSample !=
Null && m_centerLine !=
Null);
1124 return QPair<double, double>(m_centerSample, m_centerLine);
1133 QList< QPair<double, double> >
1135 return *m_featureEdgeLineSamples;
1160 Latitude centerLat = m_feature.centerLatitude();
1161 Longitude centerLon = m_feature.centerLongitude();
1163 m_featureEdgeLineSamples->clear();
1169 QList<Latitude> edgeLats;
1170 QList<Longitude> edgeLons;
1172 edgeLats.append(m_feature.northernLatitude());
1173 edgeLats.append(m_feature.centerLatitude());
1174 edgeLats.append(m_feature.southernLatitude());
1176 edgeLons.append(m_feature.easternLongitude());
1177 edgeLons.append(m_feature.centerLongitude());
1178 edgeLons.append(m_feature.westernLongitude());
1180 int edgeLatCount = edgeLats.count();
1181 int edgeLonCount = edgeLons.count();
1183 for (
int latIndex = 0; latIndex < edgeLatCount; latIndex++) {
1184 for (
int lonIndex = 0; lonIndex < edgeLonCount; lonIndex++) {
1185 Latitude &lat = edgeLats[latIndex];
1188 if (lat.isValid() && lon.isValid() &&
1189 (lat != centerLat || lon != centerLon) &&
1190 m_gmap->SetGround(lat, lon)) {
1191 m_featureEdgeLineSamples->append(
1192 QPair<double, double>(m_gmap->Sample(), m_gmap->Line()));
1199 QList< QPair<Latitude, Longitude> > edgeLatLons;
1202 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1203 m_feature.centerLongitude()));
1204 edgeLatLons.append(qMakePair(m_feature.centerLatitude(),
1205 m_feature.westernLongitude()));
1206 edgeLatLons.append(qMakePair(m_feature.centerLatitude(),
1207 m_feature.easternLongitude()));
1208 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1209 m_feature.centerLongitude()));
1213 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1214 m_feature.easternLongitude()));
1215 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1216 m_feature.westernLongitude()));
1217 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1218 m_feature.westernLongitude()));
1219 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1220 m_feature.easternLongitude()));
1223 int edgeLatLonCount = edgeLatLons.count();
1225 for (
int edgeIndex = 0; edgeIndex < edgeLatLonCount; edgeIndex++) {
1226 Latitude &lat = edgeLatLons[edgeIndex].first;
1227 Longitude &lon = edgeLatLons[edgeIndex].second;
1229 if (lat.isValid() && lon.isValid() &&
1230 (lat != centerLat || lon != centerLon) &&
1231 m_gmap->SetGround(lat, lon)) {
1232 m_featureEdgeLineSamples->append(
1233 QPair<double, double>(m_gmap->Sample(), m_gmap->Line()));
1246 std::swap(m_centerLine, other.m_centerLine);
1247 std::swap(m_centerSample, other.m_centerSample);
1248 std::swap(m_featureEdgeLineSamples, other.m_featureEdgeLineSamples);
1249 std::swap(m_feature, other.m_feature);
1250 std::swap(m_gmap, other.m_gmap);
1287 m_fullDisplayRect = NULL;
1288 m_edgePoints = NULL;
1290 m_textRect =
new QRect;
1291 m_fullDisplayRect =
new QRect;
1292 m_edgePoints =
new QList<QPoint>;
1307 QRect textRect, QRect fullDisplayRect, QList<QPoint> edgePoints) {
1309 m_fullDisplayRect = NULL;
1310 m_edgePoints = NULL;
1312 m_textRect =
new QRect(textRect);
1313 m_fullDisplayRect =
new QRect(fullDisplayRect);
1314 m_edgePoints =
new QList<QPoint>(edgePoints);
1325 m_fullDisplayRect = NULL;
1326 m_edgePoints = NULL;
1328 m_textRect =
new QRect(*other.m_textRect);
1329 m_fullDisplayRect =
new QRect(*other.m_fullDisplayRect);
1330 m_edgePoints =
new QList<QPoint>(*other.m_edgePoints);
1341 delete m_fullDisplayRect;
1342 m_fullDisplayRect = NULL;
1344 delete m_edgePoints;
1345 m_edgePoints = NULL;
1367 return *m_fullDisplayRect;
1379 return *m_edgePoints;
1391 std::swap(m_textRect, other.m_textRect);
1392 std::swap(m_fullDisplayRect, other.m_fullDisplayRect);
1393 std::swap(m_edgePoints, other.m_edgePoints);
1417 m_sourceViewport = NULL;
1419 m_featureScreenAreas = NULL;
1420 m_viewportCubeRange = NULL;
1422 m_features =
new QList<FeaturePosition>;
1423 m_featureScreenAreas =
new QList<FeatureDisplayPosition>;
1424 m_viewportCubeRange =
new QPair<QPointF, QPointF>;
1439 m_sourceViewport = sourceViewport;
1441 m_featureScreenAreas = NULL;
1442 m_viewportCubeRange = NULL;
1444 m_features =
new QList<FeaturePosition>;
1445 m_featureScreenAreas =
new QList<FeatureDisplayPosition>;
1446 m_viewportCubeRange =
new QPair<QPointF, QPointF>;
1448 sort(features.begin(), features.end(),
1451 for (
int i = 0; i < features.count(); i++) {
1453 if (display.isValid()) {
1454 m_features->append(display);
1458 handleViewChanged(tool);
1469 m_sourceViewport = other.m_sourceViewport;
1471 m_featureScreenAreas = NULL;
1472 m_viewportCubeRange = NULL;
1474 m_features =
new QList<FeaturePosition>(*other.m_features);
1475 m_featureScreenAreas =
new QList<FeatureDisplayPosition>(
1476 *other.m_featureScreenAreas);
1477 m_viewportCubeRange =
new QPair<QPointF, QPointF>(
1478 *other.m_viewportCubeRange);
1486 m_sourceViewport = NULL;
1491 delete m_featureScreenAreas;
1492 m_featureScreenAreas = NULL;
1494 delete m_viewportCubeRange;
1495 m_viewportCubeRange = NULL;
1505 for (
int i = 0; i < m_features->count(); i++) {
1506 (*m_features)[i].applyExtentType(
vectorType);
1521 int foundIndex = -1;
1522 for (
int i = 0; foundIndex == -1 && i < m_features->count(); i++) {
1523 if (displayName == m_features->at(i).feature().displayName()) {
1528 if (foundIndex != -1) {
1529 m_features->prepend(m_features->takeAt(foundIndex));
1530 m_featureScreenAreas->prepend(m_featureScreenAreas->takeAt(foundIndex));
1534 m_sourceViewport->setScale(m_sourceViewport->scale(),
1535 m_features->first().center().first,
1536 m_features->first().center().second);
1537 m_sourceViewport->viewport()->update();
1548 QList<FeatureNomenclature::Feature>
1550 QList<FeatureNomenclature::Feature> featureList;
1552 for (
int i = 0; i < m_features->count(); i++)
1553 featureList.append((*m_features)[i].feature());
1564 QList<FeatureNomenclatureTool::FeaturePosition>
1566 QList<FeatureNomenclatureTool::FeaturePosition> positionList;
1568 for (
int i = 0; i < m_features->count(); i++)
1569 positionList.append((*m_features)[i]);
1571 return positionList;
1582 return m_sourceViewport;
1597 if (viewportCubeRange() == *m_viewportCubeRange) {
1599 for (
int i = 0; i < m_features->count() &&
1600 i < m_featureScreenAreas->count(); i++) {
1605 QRect fullArea = pos.displayArea();
1607 if (!fullArea.isNull() && fullArea != textArea && showVectors) {
1609 QRect startRect = textArea.adjusted(-2, -2, 2, 2);
1610 QLineF topTextBorder(startRect.topLeft(), startRect.topRight());
1611 QLineF rightTextBorder(startRect.topRight(), startRect.bottomRight());
1612 QLineF bottomTextBorder(startRect.bottomLeft(),
1613 startRect.bottomRight());
1614 QLineF leftTextBorder(startRect.topLeft(), startRect.bottomLeft());
1616 QList<QLine> vectors;
1619 foreach (QPoint point, pos.edgePoints()) {
1620 QLineF fullVector(textArea.center(), point);
1621 QPoint newVectorStart;
1623 QPointF intersectionPoint;
1625 if (point.y() < textArea.top()) {
1626 if (topTextBorder.intersects(fullVector, &intersectionPoint) ==
1627 QLineF::BoundedIntersection) {
1628 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1629 qRound(intersectionPoint.y()));
1633 if (point.x() > textArea.right()) {
1634 if (rightTextBorder.intersects(fullVector, &intersectionPoint) ==
1635 QLineF::BoundedIntersection) {
1636 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1637 qRound(intersectionPoint.y()));
1641 if (point.y() > textArea.bottom()) {
1642 if (bottomTextBorder.intersects(fullVector, &intersectionPoint) ==
1643 QLineF::BoundedIntersection) {
1644 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1645 qRound(intersectionPoint.y()));
1649 if (point.x() < textArea.left()) {
1650 if (leftTextBorder.intersects(fullVector, &intersectionPoint) ==
1651 QLineF::BoundedIntersection) {
1652 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1653 qRound(intersectionPoint.y()));
1657 if (!newVectorStart.isNull() &&
1658 QLineF(newVectorStart, point).length() > 10) {
1659 vectors.append(QLine(newVectorStart, point));
1663 foreach (QLine vector, vectors) {
1664 painter->drawLine(vector);
1667 Angle normalAngle(-1 * QLineF(vector).normalVector().angle(),
1671 double deltaX = magnitude * cos(normalAngle.radians());
1672 double deltaY = magnitude * sin(normalAngle.radians());
1674 QPoint normalStart(vector.x2() + deltaX, vector.y2() + deltaY);
1675 QPoint normalEnd(vector.x2() - deltaX, vector.y2() - deltaY);
1676 painter->drawLine(normalStart, normalEnd);
1680 Angle leftHead = vectorAngle - arrowheadAngle;
1681 Angle rightHead = vectorAngle + arrowheadAngle;
1683 int arrowheadMag = 10;
1684 deltaX = arrowheadMag * cos(leftHead.radians());
1685 deltaY = arrowheadMag * sin(leftHead.radians());
1687 vector.p2(), vector.p2() - QPoint(deltaX, deltaY));
1689 deltaX = arrowheadMag * cos(rightHead.radians());
1690 deltaY = arrowheadMag * sin(rightHead.radians());
1692 vector.p2(), vector.p2() - QPoint(deltaX, deltaY));
1697 if (pos.edgePoints().count() == 4) {
1698 QPolygon boundingPoly(pos.edgePoints().toVector());
1699 painter->drawPolygon(boundingPoly);
1704 if (!textArea.isNull()) {
1705 QString featureName = feature.
name();
1706 painter->drawText(textArea, featureName);
1723 for (
int i = 0; i < m_featureScreenAreas->count(); i++) {
1724 QRect screenArea = m_featureScreenAreas->at(i).displayArea();
1726 if (screenArea.contains(p)) {
1728 if (s == Qt::LeftButton) {
1729 tool->showFeatureDetails(feature);
1731 else if (s == Qt::RightButton) {
1735 title->setEnabled(
false);
1736 menu.addSeparator();
1738 QAction *details = menu.addAction(
"Details...");
1739 QAction *website = menu.addAction(
"Website...");
1740 menu.addSeparator();
1741 QAction *center = menu.addAction(
"Center on Feature");
1742 QAction *copyUrl = menu.addAction(
"Copy Website URL");
1746 QAction *selectedAction = menu.exec(
1747 m_sourceViewport->viewport()->mapToGlobal(p) +
1748 QPoint(0, 20), details);
1750 if (selectedAction == details) {
1751 tool->showFeatureDetails(feature);
1753 else if (selectedAction == website) {
1754 tool->showFeatureWebsite(feature);
1756 else if (selectedAction == center) {
1757 tool->centerOnFeature(m_sourceViewport, feature);
1759 else if (selectedAction == copyUrl) {
1760 QApplication::clipboard()->setText(
1777 m_featureScreenAreas->clear();
1780 fontToUse.setPointSize(tool->fontSize());
1781 QFontMetrics fontMetrics(fontToUse);
1784 QList<QRect> rectsToAvoid;
1786 for (
int i = 0; i < m_features->count(); i++) {
1791 if ( !tool->m_showApprovedOnly ||
1794 double sample = (*m_features)[i].center().first;
1795 double line = (*m_features)[i].center().second;
1799 m_sourceViewport->cubeToViewport(sample, line,
1800 viewportX, viewportY);
1802 QString featureName = feature.
name();
1803 QRect textDisplayArea(QPoint(viewportX, viewportY),
1804 QSize(fontMetrics.horizontalAdvance(featureName) + 4,
1805 fontMetrics.height()));
1807 textDisplayArea.moveTopLeft(textDisplayArea.topLeft() -
1808 QPoint(textDisplayArea.width() / 2, textDisplayArea.height() / 2));
1810 bool canDisplay =
false;
1811 if (textDisplayArea.left() < m_sourceViewport->width() &&
1812 textDisplayArea.right() > 0 &&
1813 textDisplayArea.top() < m_sourceViewport->height() &&
1814 textDisplayArea.bottom() > 0) {
1818 QRect fullDisplayArea = textDisplayArea;
1819 QPair<double, double> edge;
1820 QList<QPoint> edgeScreenPoints;
1822 if (canDisplay && tool->vectorType() !=
None) {
1823 QList< QPair<double, double> > edges = (*m_features)[i].edges();
1824 foreach (edge, edges) {
1825 m_sourceViewport->cubeToViewport(edge.first, edge.second,
1826 viewportX, viewportY);
1827 edgeScreenPoints.append(QPoint(viewportX, viewportY));
1830 if (tool->vectorType() !=
Box) {
1831 foreach (QPoint screenPoint, edgeScreenPoints) {
1832 fullDisplayArea = fullDisplayArea.united(
1833 QRect(screenPoint.x() - 3, screenPoint.y() - 3, 6, 6));
1836 else if (edges.count() == 4) {
1838 QPolygon boundingPoly(edgeScreenPoints.toVector());
1840 if (boundingPoly.intersected(textDisplayArea) == QPolygon(textDisplayArea,
true)) {
1841 fullDisplayArea = boundingPoly.boundingRect();
1848 foreach (QRect rectToAvoid, rectsToAvoid) {
1849 if (canDisplay && fullDisplayArea.intersects(rectToAvoid)) {
1856 rectsToAvoid.append(fullDisplayArea);
1861 *m_viewportCubeRange = viewportCubeRange();
1873 std::swap(m_sourceViewport, other.m_sourceViewport);
1874 std::swap(m_features, other.m_features);
1875 std::swap(m_featureScreenAreas, other.m_featureScreenAreas);
1876 std::swap(m_viewportCubeRange, other.m_viewportCubeRange);
1903 QPair<QPointF, QPointF>
1907 sourceViewport()->viewportToCube(1, 1, minValues.rx(), minValues.ry());
1910 sourceViewport()->viewportToCube(sourceViewport()->viewport()->width(),
1911 sourceViewport()->viewport()->height(),
1912 maxValues.rx(), maxValues.ry());
1914 return QPair<QPointF, QPointF>(minValues, maxValues);
Defines an angle and provides unit conversions.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
A named feature on a target.
QUrl referenceUrl() const
QString cleanName() const
QString controlNet() const
QWidget * toWidget() const
This converts the data in this feature to a widget.
QString displayName() const
Feature nomenclature database querier.
@ Approved
When this status is assigned to a feature, the displayed status will be "Adopted by the IAU" and the ...
static bool featureDiameterGreaterThan(const FeatureNomenclature::Feature &lhs, const FeatureNomenclature::Feature &rhs)
Compare the diameter of two features.
File name manipulation and expansion.
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
This class is designed to encapsulate the concept of a Latitude.
This class is designed to encapsulate the concept of a Longitude.
Cube display widget for certain Isis MDI applications.
bool isLinked() const
Is the viewport linked with other viewports.
Contains multiple PvlContainers.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.
const double Null
Value for an Isis Null pixel.
Namespace for the standard library.