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"
60 new QMap< MdiCubeViewport *, FeatureNomenclature *>;
70 "in your opened cube files. This tool <strong>requires</strong> an "
71 "active internet connection, projection or camera information, and a "
72 "calculatable ground range to function. The larger the ground range ("
73 "covered area on a planet), the longer it will take to populate the "
74 "nomenclature for a particular cube.<br/><br/>"
75 "<font color='red'>**WARNING**</font> The accuracy of this tool is not "
76 "perfect, features <strong>can and will be mislabeled</strong> if you "
77 "have not properly controlled your images to the control network that "
78 "identifies the latitude/longitude values of a feature. Please use the "
79 "nomenclature website to verify a label is correct for a feature. "
80 "<br/><br/>See the IAU Gazetteer of Planetary Nomenclature website for "
81 "more information.<br/>"
82 "<a href='http://planetarynames.wr.usgs.gov/'>"
83 "http://planetarynames.wr.usgs.gov/</a>";
85 connect(
this, SIGNAL(toolActivated()),
116 m_action = menu->addAction(
"Show Nomenclature");
120 connect(
m_action, SIGNAL(triggered(
bool)),
138 painter->setFont(fontToUse);
220 vp->viewport()->update();
239 vp->viewport()->update();
257 vp->viewport()->update();
274 (*m_foundNomenclature)[i].applyExtentType(
m_extentType);
280 vp->viewport()->update();
303 QStackedWidget *parent) {
312 QLabel *foundFeaturesLabel =
new QLabel(
"Found Features:");
315 QComboBox::AdjustToContents);
340 QHBoxLayout *layout =
new QHBoxLayout;
341 layout->setMargin(0);
343 layout->addWidget(foundFeaturesLabel);
349 layout->addStretch(1);
350 wrapperWidget->setLayout(layout);
351 return wrapperWidget;
366 action->setIcon(QPixmap(
toolIconDir() +
"/nomenclature.png"));
367 action->setToolTip(
"Nomenclature (N)");
368 action->setShortcut(Qt::Key_N);
369 action->setObjectName(
"nomenclatureToolButton");
372 "<b>Function:</b> Display nomenclature on the visible images.\n"
373 "<p/><b>Hint:</b> While this tool is active, you can left and right "
374 "click on any of the named features for additional options."
375 "<p/><b>Shortcut:</b> N";
376 action->setWhatsThis(text);
391 QPoint p, Qt::MouseButton s) {
434 qobject_cast<QWidget *>(parent()));
435 configDialog->setAttribute(Qt::WA_DeleteOnClose);
436 configDialog->show();
477 viewport->viewport()->update();
487 if (newState == Qt::Unchecked) {
491 else if (newState == Qt::Checked) {
499 vp->viewport()->update();
513 (*m_foundNomenclature)[i].handleViewChanged(
this);
534 QMessageBox::warning(qobject_cast<QWidget *>(parent()),
552 if (viewport == vp ||
553 (vp->isLinked() && viewport->
isLinked())) {
570 QList<FeatureNomenclature::Feature> features;
584 QProgressDialog updatingFeaturesProgress(
585 tr(
"Projecting Features for [%1]").arg(vp->cube()->fileName().section(
'/',-1)),
588 updatingFeaturesProgress.setWindowModality(Qt::WindowModal);
592 for (
int i = 0; i < features.count(); i++) {
593 feature = features[i];
595 int progress = floor(100 * (
double)i / (
double)features.count());
597 if (progress != updatingFeaturesProgress.value())
598 updatingFeaturesProgress.setValue(progress);
600 if (updatingFeaturesProgress.wasCanceled()) {
611 QString displayName = feature.
cleanName() +
614 QString targetName = feature.
target().toUpper();
621 while (!foundInsertPos) {
623 foundInsertPos =
true;
628 QString insertPosTarget = insetPosData.toMap()[
"Target"].toString();
630 if (targetName < insertPosTarget) {
631 foundInsertPos =
true;
633 else if (targetName == insertPosTarget) {
634 if (!insetPosData.toMap()[
"Viewport"].isNull()) {
635 foundInsertPos = displayName.compare(
637 Qt::CaseInsensitive) < 0;
647 "Target"].toString() != targetName) {
648 QMap<QString, QVariant> data;
649 data[
"Target"] = targetName;
652 if (controlNet !=
"")
653 controlNet =
" (" + controlNet +
")";
656 targetName + controlNet,
672 QMap<QString, QVariant> data;
673 data[
"Feature"] = QVariant::fromValue<FeatureNomenclature::Feature>(
675 data[
"Viewport"] = qVariantFromValue(vp);
676 data[
"Target"] = qVariantFromValue(targetName);
679 qVariantFromValue(data));
682 updatingFeaturesProgress.setValue( features.count() );
698 QList<MdiCubeViewport *> removedViewports =
702 removedViewports.removeOne(vp);
712 bool removedAViewport =
false;
716 removedAViewport =
true;
719 if (removedAViewport) {
743 target = vp->camera()->target()->name();
745 else if (vp->projection()) {
746 PvlGroup mappingGrp = vp->projection()->Mapping();
748 if (mappingGrp.hasKeyword(
"TargetName"))
749 target = mappingGrp[
"TargetName"][0];
756 if (ugm->GroundRange(vp->cube(), minLat, maxLat, minLon, maxLon) &&
762 (*m_nomenclatureSearchers)[vp] = searcher;
764 (*m_nomenclatureSearchers)[vp]->queryFeatures(target.toUpper(),
815 QDialog *detailsDialog =
new QDialog(qobject_cast<QWidget *>(parent()));
816 detailsDialog->setAttribute(Qt::WA_DeleteOnClose);
818 QVBoxLayout *mainLayout =
new QVBoxLayout;
819 detailsDialog->setLayout(mainLayout);
821 mainLayout->addWidget(feature.
toWidget());
825 QHBoxLayout *buttonsAreaLayout =
new QHBoxLayout;
826 buttonsAreaWrapper->setLayout(buttonsAreaLayout);
828 buttonsAreaLayout->addStretch();
829 QPushButton *okayBtn =
new QPushButton(
"&Ok");
830 okayBtn->setIcon(QIcon::fromTheme(
"dialog-ok"));
831 connect(okayBtn, SIGNAL(clicked()),
832 detailsDialog, SLOT(accept()));
833 buttonsAreaLayout->addWidget(okayBtn);
835 mainLayout->addWidget(buttonsAreaWrapper);
837 detailsDialog->show();
860 if (isCurrentlyLoading) {
894 (*m_nomenclatureSearchers)[vp]->deleteLater();
925 return &(*m_foundNomenclature)[i];
944 return &(*m_foundNomenclature)[i];
971 QList<MdiCubeViewport *>
973 QList<MdiCubeViewport *> result;
990 FileName config(
"$HOME/.Isis/qview/nomenclature.config");
992 config.expanded(), QSettings::NativeFormat);
1012 FileName config(
"$HOME/.Isis/qview/nomenclature.config");
1014 config.expanded(), QSettings::NativeFormat);
1016 settings.setValue(
"fontColor", qVariantFromValue(*
m_fontColor));
1048 m_centerLine =
Null;
1049 m_centerSample =
Null;
1050 m_featureEdgeLineSamples = NULL;
1053 m_featureEdgeLineSamples =
new QList< QPair<double, double> >;
1055 m_feature = feature;
1058 m_gmap = vp->universalGroundMap();
1059 Latitude centerLat = m_feature.centerLatitude();
1060 Longitude centerLon = m_feature.centerLongitude();
1061 if (m_gmap && m_gmap->SetGround(centerLat, centerLon)) {
1062 m_centerSample = m_gmap->Sample();
1063 m_centerLine = m_gmap->Line();
1078 m_centerLine = other.m_centerLine;
1079 m_centerSample = other.m_centerSample;
1080 m_featureEdgeLineSamples = NULL;
1083 m_featureEdgeLineSamples =
new QList< QPair<double, double> >(
1084 *other.m_featureEdgeLineSamples);
1086 m_feature = other.m_feature;
1097 m_centerLine =
Null;
1098 m_centerSample =
Null;
1101 delete m_featureEdgeLineSamples;
1102 m_featureEdgeLineSamples = NULL;
1112 return (m_centerSample !=
Null && m_centerLine !=
Null);
1123 return QPair<double, double>(m_centerSample, m_centerLine);
1132 QList< QPair<double, double> >
1134 return *m_featureEdgeLineSamples;
1159 Latitude centerLat = m_feature.centerLatitude();
1160 Longitude centerLon = m_feature.centerLongitude();
1162 m_featureEdgeLineSamples->clear();
1168 QList<Latitude> edgeLats;
1169 QList<Longitude> edgeLons;
1171 edgeLats.append(m_feature.northernLatitude());
1172 edgeLats.append(m_feature.centerLatitude());
1173 edgeLats.append(m_feature.southernLatitude());
1175 edgeLons.append(m_feature.easternLongitude());
1176 edgeLons.append(m_feature.centerLongitude());
1177 edgeLons.append(m_feature.westernLongitude());
1179 int edgeLatCount = edgeLats.count();
1180 int edgeLonCount = edgeLons.count();
1182 for (
int latIndex = 0; latIndex < edgeLatCount; latIndex++) {
1183 for (
int lonIndex = 0; lonIndex < edgeLonCount; lonIndex++) {
1184 Latitude &lat = edgeLats[latIndex];
1187 if (lat.isValid() && lon.isValid() &&
1188 (lat != centerLat || lon != centerLon) &&
1189 m_gmap->SetGround(lat, lon)) {
1190 m_featureEdgeLineSamples->append(
1191 QPair<double, double>(m_gmap->Sample(), m_gmap->Line()));
1198 QList< QPair<Latitude, Longitude> > edgeLatLons;
1201 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1202 m_feature.centerLongitude()));
1203 edgeLatLons.append(qMakePair(m_feature.centerLatitude(),
1204 m_feature.westernLongitude()));
1205 edgeLatLons.append(qMakePair(m_feature.centerLatitude(),
1206 m_feature.easternLongitude()));
1207 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1208 m_feature.centerLongitude()));
1212 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1213 m_feature.easternLongitude()));
1214 edgeLatLons.append(qMakePair(m_feature.northernLatitude(),
1215 m_feature.westernLongitude()));
1216 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1217 m_feature.westernLongitude()));
1218 edgeLatLons.append(qMakePair(m_feature.southernLatitude(),
1219 m_feature.easternLongitude()));
1222 int edgeLatLonCount = edgeLatLons.count();
1224 for (
int edgeIndex = 0; edgeIndex < edgeLatLonCount; edgeIndex++) {
1225 Latitude &lat = edgeLatLons[edgeIndex].first;
1226 Longitude &lon = edgeLatLons[edgeIndex].second;
1228 if (lat.isValid() && lon.isValid() &&
1229 (lat != centerLat || lon != centerLon) &&
1230 m_gmap->SetGround(lat, lon)) {
1231 m_featureEdgeLineSamples->append(
1232 QPair<double, double>(m_gmap->Sample(), m_gmap->Line()));
1245 std::swap(m_centerLine, other.m_centerLine);
1246 std::swap(m_centerSample, other.m_centerSample);
1247 std::swap(m_featureEdgeLineSamples, other.m_featureEdgeLineSamples);
1248 std::swap(m_feature, other.m_feature);
1249 std::swap(m_gmap, other.m_gmap);
1286 m_fullDisplayRect = NULL;
1287 m_edgePoints = NULL;
1289 m_textRect =
new QRect;
1290 m_fullDisplayRect =
new QRect;
1291 m_edgePoints =
new QList<QPoint>;
1306 QRect textRect, QRect fullDisplayRect, QList<QPoint> edgePoints) {
1308 m_fullDisplayRect = NULL;
1309 m_edgePoints = NULL;
1311 m_textRect =
new QRect(textRect);
1312 m_fullDisplayRect =
new QRect(fullDisplayRect);
1313 m_edgePoints =
new QList<QPoint>(edgePoints);
1324 m_fullDisplayRect = NULL;
1325 m_edgePoints = NULL;
1327 m_textRect =
new QRect(*other.m_textRect);
1328 m_fullDisplayRect =
new QRect(*other.m_fullDisplayRect);
1329 m_edgePoints =
new QList<QPoint>(*other.m_edgePoints);
1340 delete m_fullDisplayRect;
1341 m_fullDisplayRect = NULL;
1343 delete m_edgePoints;
1344 m_edgePoints = NULL;
1366 return *m_fullDisplayRect;
1378 return *m_edgePoints;
1390 std::swap(m_textRect, other.m_textRect);
1391 std::swap(m_fullDisplayRect, other.m_fullDisplayRect);
1392 std::swap(m_edgePoints, other.m_edgePoints);
1416 m_sourceViewport = NULL;
1418 m_featureScreenAreas = NULL;
1419 m_viewportCubeRange = NULL;
1421 m_features =
new QList<FeaturePosition>;
1422 m_featureScreenAreas =
new QList<FeatureDisplayPosition>;
1423 m_viewportCubeRange =
new QPair<QPointF, QPointF>;
1438 m_sourceViewport = sourceViewport;
1440 m_featureScreenAreas = NULL;
1441 m_viewportCubeRange = NULL;
1443 m_features =
new QList<FeaturePosition>;
1444 m_featureScreenAreas =
new QList<FeatureDisplayPosition>;
1445 m_viewportCubeRange =
new QPair<QPointF, QPointF>;
1447 qSort(features.begin(), features.end(),
1450 for (
int i = 0; i < features.count(); i++) {
1452 if (display.isValid()) {
1453 m_features->append(display);
1457 handleViewChanged(tool);
1468 m_sourceViewport = other.m_sourceViewport;
1470 m_featureScreenAreas = NULL;
1471 m_viewportCubeRange = NULL;
1473 m_features =
new QList<FeaturePosition>(*other.m_features);
1474 m_featureScreenAreas =
new QList<FeatureDisplayPosition>(
1475 *other.m_featureScreenAreas);
1476 m_viewportCubeRange =
new QPair<QPointF, QPointF>(
1477 *other.m_viewportCubeRange);
1485 m_sourceViewport = NULL;
1490 delete m_featureScreenAreas;
1491 m_featureScreenAreas = NULL;
1493 delete m_viewportCubeRange;
1494 m_viewportCubeRange = NULL;
1504 for (
int i = 0; i < m_features->count(); i++) {
1505 (*m_features)[i].applyExtentType(
vectorType);
1520 int foundIndex = -1;
1521 for (
int i = 0; foundIndex == -1 && i < m_features->count(); i++) {
1522 if (displayName == m_features->at(i).feature().displayName()) {
1527 if (foundIndex != -1) {
1528 m_features->prepend(m_features->takeAt(foundIndex));
1529 m_featureScreenAreas->prepend(m_featureScreenAreas->takeAt(foundIndex));
1533 m_sourceViewport->setScale(m_sourceViewport->scale(),
1534 m_features->first().center().first,
1535 m_features->first().center().second);
1536 m_sourceViewport->viewport()->update();
1547 QList<FeatureNomenclature::Feature>
1549 QList<FeatureNomenclature::Feature> featureList;
1551 for (
int i = 0; i < m_features->count(); i++)
1552 featureList.append((*m_features)[i].feature());
1563 QList<FeatureNomenclatureTool::FeaturePosition>
1565 QList<FeatureNomenclatureTool::FeaturePosition> positionList;
1567 for (
int i = 0; i < m_features->count(); i++)
1568 positionList.append((*m_features)[i]);
1570 return positionList;
1581 return m_sourceViewport;
1596 if (viewportCubeRange() == *m_viewportCubeRange) {
1598 for (
int i = 0; i < m_features->count() &&
1599 i < m_featureScreenAreas->count(); i++) {
1604 QRect fullArea = pos.displayArea();
1606 if (!fullArea.isNull() && fullArea != textArea && showVectors) {
1608 QRect startRect = textArea.adjusted(-2, -2, 2, 2);
1609 QLineF topTextBorder(startRect.topLeft(), startRect.topRight());
1610 QLineF rightTextBorder(startRect.topRight(), startRect.bottomRight());
1611 QLineF bottomTextBorder(startRect.bottomLeft(),
1612 startRect.bottomRight());
1613 QLineF leftTextBorder(startRect.topLeft(), startRect.bottomLeft());
1615 QList<QLine> vectors;
1618 foreach (QPoint point, pos.edgePoints()) {
1619 QLineF fullVector(textArea.center(), point);
1620 QPoint newVectorStart;
1622 QPointF intersectionPoint;
1624 if (point.y() < textArea.top()) {
1625 if (topTextBorder.intersect(fullVector, &intersectionPoint) ==
1626 QLineF::BoundedIntersection) {
1627 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1628 qRound(intersectionPoint.y()));
1632 if (point.x() > textArea.right()) {
1633 if (rightTextBorder.intersect(fullVector, &intersectionPoint) ==
1634 QLineF::BoundedIntersection) {
1635 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1636 qRound(intersectionPoint.y()));
1640 if (point.y() > textArea.bottom()) {
1641 if (bottomTextBorder.intersect(fullVector, &intersectionPoint) ==
1642 QLineF::BoundedIntersection) {
1643 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1644 qRound(intersectionPoint.y()));
1648 if (point.x() < textArea.left()) {
1649 if (leftTextBorder.intersect(fullVector, &intersectionPoint) ==
1650 QLineF::BoundedIntersection) {
1651 newVectorStart = QPoint(qRound(intersectionPoint.x()),
1652 qRound(intersectionPoint.y()));
1656 if (!newVectorStart.isNull() &&
1657 QLineF(newVectorStart, point).length() > 10) {
1658 vectors.append(QLine(newVectorStart, point));
1662 foreach (QLine vector, vectors) {
1663 painter->drawLine(vector);
1666 Angle normalAngle(-1 * QLineF(vector).normalVector().angle(),
1670 double deltaX = magnitude * cos(normalAngle.radians());
1671 double deltaY = magnitude * sin(normalAngle.radians());
1673 QPoint normalStart(vector.x2() + deltaX, vector.y2() + deltaY);
1674 QPoint normalEnd(vector.x2() - deltaX, vector.y2() - deltaY);
1675 painter->drawLine(normalStart, normalEnd);
1679 Angle leftHead = vectorAngle - arrowheadAngle;
1680 Angle rightHead = vectorAngle + arrowheadAngle;
1682 int arrowheadMag = 10;
1683 deltaX = arrowheadMag * cos(leftHead.radians());
1684 deltaY = arrowheadMag * sin(leftHead.radians());
1686 vector.p2(), vector.p2() - QPoint(deltaX, deltaY));
1688 deltaX = arrowheadMag * cos(rightHead.radians());
1689 deltaY = arrowheadMag * sin(rightHead.radians());
1691 vector.p2(), vector.p2() - QPoint(deltaX, deltaY));
1696 if (pos.edgePoints().count() == 4) {
1697 QPolygon boundingPoly(pos.edgePoints().toVector());
1698 painter->drawPolygon(boundingPoly);
1703 if (!textArea.isNull()) {
1704 QString featureName = feature.
name();
1705 painter->drawText(textArea, featureName);
1722 for (
int i = 0; i < m_featureScreenAreas->count(); i++) {
1723 QRect screenArea = m_featureScreenAreas->at(i).displayArea();
1725 if (screenArea.contains(p)) {
1727 if (s == Qt::LeftButton) {
1728 tool->showFeatureDetails(feature);
1730 else if (s == Qt::RightButton) {
1734 title->setEnabled(
false);
1735 menu.addSeparator();
1737 QAction *details = menu.addAction(
"Details...");
1738 QAction *website = menu.addAction(
"Website...");
1739 menu.addSeparator();
1740 QAction *center = menu.addAction(
"Center on Feature");
1741 QAction *copyUrl = menu.addAction(
"Copy Website URL");
1745 QAction *selectedAction = menu.exec(
1746 m_sourceViewport->viewport()->mapToGlobal(p) +
1747 QPoint(0, 20), details);
1749 if (selectedAction == details) {
1750 tool->showFeatureDetails(feature);
1752 else if (selectedAction == website) {
1753 tool->showFeatureWebsite(feature);
1755 else if (selectedAction == center) {
1756 tool->centerOnFeature(m_sourceViewport, feature);
1758 else if (selectedAction == copyUrl) {
1759 QApplication::clipboard()->setText(
1776 m_featureScreenAreas->clear();
1779 fontToUse.setPointSize(tool->fontSize());
1780 QFontMetrics fontMetrics(fontToUse);
1783 QList<QRect> rectsToAvoid;
1785 for (
int i = 0; i < m_features->count(); i++) {
1790 if ( !tool->m_showApprovedOnly ||
1793 double sample = (*m_features)[i].center().first;
1794 double line = (*m_features)[i].center().second;
1798 m_sourceViewport->cubeToViewport(sample, line,
1799 viewportX, viewportY);
1801 QString featureName = feature.
name();
1802 QRect textDisplayArea(QPoint(viewportX, viewportY),
1803 QSize(fontMetrics.width(featureName) + 4,
1804 fontMetrics.height()));
1806 textDisplayArea.moveTopLeft(textDisplayArea.topLeft() -
1807 QPoint(textDisplayArea.width() / 2, textDisplayArea.height() / 2));
1809 bool canDisplay =
false;
1810 if (textDisplayArea.left() < m_sourceViewport->width() &&
1811 textDisplayArea.right() > 0 &&
1812 textDisplayArea.top() < m_sourceViewport->height() &&
1813 textDisplayArea.bottom() > 0) {
1817 QRect fullDisplayArea = textDisplayArea;
1818 QPair<double, double> edge;
1819 QList<QPoint> edgeScreenPoints;
1821 if (canDisplay && tool->vectorType() !=
None) {
1822 QList< QPair<double, double> > edges = (*m_features)[i].edges();
1823 foreach (edge, edges) {
1824 m_sourceViewport->cubeToViewport(edge.first, edge.second,
1825 viewportX, viewportY);
1826 edgeScreenPoints.append(QPoint(viewportX, viewportY));
1829 if (tool->vectorType() !=
Box) {
1830 foreach (QPoint screenPoint, edgeScreenPoints) {
1831 fullDisplayArea = fullDisplayArea.united(
1832 QRect(screenPoint.x() - 3, screenPoint.y() - 3, 6, 6));
1835 else if (edges.count() == 4) {
1837 QPolygon boundingPoly(edgeScreenPoints.toVector());
1839 if (boundingPoly.intersected(textDisplayArea) == QPolygon(textDisplayArea,
true)) {
1840 fullDisplayArea = boundingPoly.boundingRect();
1847 foreach (QRect rectToAvoid, rectsToAvoid) {
1848 if (canDisplay && fullDisplayArea.intersects(rectToAvoid)) {
1855 rectsToAvoid.append(fullDisplayArea);
1860 *m_viewportCubeRange = viewportCubeRange();
1872 std::swap(m_sourceViewport, other.m_sourceViewport);
1873 std::swap(m_features, other.m_features);
1874 std::swap(m_featureScreenAreas, other.m_featureScreenAreas);
1875 std::swap(m_viewportCubeRange, other.m_viewportCubeRange);
1902 QPair<QPointF, QPointF>
1906 sourceViewport()->viewportToCube(1, 1, minValues.rx(), minValues.ry());
1909 sourceViewport()->viewportToCube(sourceViewport()->viewport()->width(),
1910 sourceViewport()->viewport()->height(),
1911 maxValues.rx(), maxValues.ry());
1913 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.