Isis 3 Programmer Reference
FeatureNomenclature.cpp
1 #include "IsisDebug.h"
2 #include "FeatureNomenclature.h"
3 
4 #include <QDebug>
5 #include <QDomElement>
6 #include <QGridLayout>
7 #include <QLabel>
8 #include <QList>
9 #include <QMessageBox>
10 #include <QNetworkAccessManager>
11 #include <QNetworkRequest>
12 #include <QNetworkReply>
13 #include <QPair>
14 #include <QUrl>
15 #include <QUrlQuery>
16 
17 #include "Distance.h"
18 #include "IException.h"
19 #include "IString.h"
20 #include "iTime.h"
21 #include "Latitude.h"
22 #include "Longitude.h"
23 
24 namespace Isis {
25 
30  m_networkMgr = NULL;
31  m_request = NULL;
32  m_features = NULL;
33 
34  m_networkMgr = new QNetworkAccessManager;
35  connect(m_networkMgr, SIGNAL(finished(QNetworkReply *)),
36  this, SLOT(requestFinished(QNetworkReply *)));
37 
38  m_request = new QNetworkRequest;
39  m_request->setUrl(
40  QUrl("https://planetarynames.wr.usgs.gov/nomenclature/SearchResults"));
41  m_request->setRawHeader("User-Agent",
42  "Mozilla/5.0 (X11; Linux i686; rv:6.0) "
43  "Gecko/20100101 Firefox/6.0");
44  m_request->setHeader(QNetworkRequest::ContentTypeHeader,
45  "application/x-www-form-urlencoded");
46  m_lastQuery = true;
47  }
48 
49 
57  m_networkMgr = NULL;
58  m_request = NULL;
59  m_features = NULL;
60 
61  m_networkMgr = new QNetworkAccessManager;
62 
63  connect(m_networkMgr, SIGNAL(finished(QNetworkReply *)),
64  this, SLOT(requestFinished(QNetworkReply *)));
65 
66  m_request = new QNetworkRequest;
67  m_lastQuery = other.m_lastQuery;
68 
69  if (other.m_features)
70  m_features = new QList<Feature>(*other.m_features);
71  }
72 
73 
78  delete m_networkMgr;
79  m_networkMgr = NULL;
80 
81  delete m_request;
82  m_request = NULL;
83 
84  delete m_features;
85  m_features = NULL;
86  }
87 
88 
101  Latitude startLat, Longitude startLon,
102  Latitude endLat, Longitude endLon) {
103 
104  QList< QPair<Longitude, Longitude> > range = Longitude::to360Range(startLon, endLon);
105 
106  if (!range.isEmpty()) {
107  startLon = range[0].first;
108  endLon = range[0].second;
109  }
110 
111  if (range.size() > 1) {
112 
113  Longitude startLon2 = range[1].first;
114  Longitude endLon2 = range[1].second;
115 
116  runQuery(target, startLat, startLon, endLat, endLon);
117  runQuery(target, startLat, startLon2, endLat, endLon2);
118 
119  m_lastQuery = false;
120  }
121  else {
122  runQuery(target, startLat, startLon, endLat, endLon);
123 
124  m_lastQuery = true;
125  }
126  }
127 
128 
137  QList<Feature> featureList;
138 
139  if (m_features)
140  featureList = *m_features;
141 
142  return featureList;
143  }
144 
145 
153  return (m_features != NULL);
154  }
155 
156 
163  std::swap(m_networkMgr, other.m_networkMgr);
164  std::swap(m_request, other.m_request);
165  std::swap(m_features, other.m_features);
166  }
167 
168 
177  const FeatureNomenclature &rhs) {
178  FeatureNomenclature tmp(rhs);
179  swap(tmp);
180  return *this;
181  }
182 
183 
194  const FeatureNomenclature::Feature &lhs,
195  const FeatureNomenclature::Feature &rhs) {
196  Distance lhsDiameter = lhs.diameter();
197  Distance rhsDiameter = rhs.diameter();
198 
199  bool greaterThan = false;
200  if (lhsDiameter.isValid() && rhsDiameter.isValid()) {
201  greaterThan = (lhsDiameter > rhsDiameter);
202  }
203  else {
204  greaterThan = lhsDiameter.isValid();
205  }
206 
207  return greaterThan;
208  }
209 
210 
215  m_xmlRepresenation = NULL;
217  }
218 
219 
223  FeatureNomenclature::Feature::Feature(QDomElement searchResultFeature, IAUStatus status) {
224  m_xmlRepresenation = NULL;
225  m_xmlRepresenation = new QDomElement(searchResultFeature);
226  m_approvalStatus = status;
227  }
228 
229 
236  m_xmlRepresenation = NULL;
237  // QDomElement does a shallow copy.
238  m_approvalStatus = other.m_approvalStatus;
239  m_xmlRepresenation = new QDomElement(*other.m_xmlRepresenation);
240  }
241 
242 
247  delete m_xmlRepresenation;
248  m_xmlRepresenation = NULL;
249  }
250 
251 
260  QWidget *widget = new QWidget;
261 
262  QGridLayout *layout = new QGridLayout;
263  widget->setLayout(layout);
264 
265  int row = 0;
266 
267  QLabel *titleLabel = new QLabel("<h2>Feature Details</h2>");
268  layout->addWidget(titleLabel, row, 0, 1, 2);
269  row++;
270 
272  displayValues;
273 
275  displayValue;
276 
277  displayValue.first = "Feature Name:";
278  displayValue.second = &FeatureNomenclature::Feature::displayName;
279  displayValues.append(displayValue);
280 
281 // displayValue.first = "Feature Name (clean):";
282 // displayValue.second = &FeatureNomenclature::Feature::cleanName;
283 // displayValues.append(displayValue);
284 
285  displayValue.first = "Feature ID:";
286  displayValue.second = &FeatureNomenclature::Feature::id;
287  displayValues.append(displayValue);
288 
289  displayValue.first = "Target:";
290  displayValue.second = &FeatureNomenclature::Feature::target;
291  displayValues.append(displayValue);
292 
293  displayValue.first = "System:";
294  displayValue.second = &FeatureNomenclature::Feature::system;
295  displayValues.append(displayValue);
296 
297  displayValue.first = "Control Network:";
298  displayValue.second = &FeatureNomenclature::Feature::controlNet;
299  displayValues.append(displayValue);
300 
301  displayValue.first = "Diameter:";
302  displayValue.second = &FeatureNomenclature::Feature::diameterString;
303  displayValues.append(displayValue);
304 
305  displayValue.first = "Originating Continent:";
306  displayValue.second =
308  displayValues.append(displayValue);
309 
310  displayValue.first = "Originating Ethnicity:";
311  displayValue.second =
313  displayValues.append(displayValue);
314 
315  displayValue.first = "Feature Type:";
316  displayValue.second =
318  displayValues.append(displayValue);
319 
320  displayValue.first = "Center Latitude:";
321  displayValue.second =
323  displayValues.append(displayValue);
324 
325  displayValue.first = "Center Longitude:";
326  displayValue.second =
328  displayValues.append(displayValue);
329 
330  displayValue.first = "Northern Latitude:";
331  displayValue.second =
333  displayValues.append(displayValue);
334 
335  displayValue.first = "Southern Latitude:";
336  displayValue.second =
338  displayValues.append(displayValue);
339 
340  displayValue.first = "Eastern Longitude:";
341  displayValue.second =
343  displayValues.append(displayValue);
344 
345  displayValue.first = "Western Longitude:";
346  displayValue.second =
348  displayValues.append(displayValue);
349 
350  displayValue.first = "Approval Date:";
351  displayValue.second =
353  displayValues.append(displayValue);
354 
355  displayValue.first = "Approval Status:";
356  displayValue.second =
358  displayValues.append(displayValue);
359 
360  displayValue.first = "Last Updated:";
361  displayValue.second =
363  displayValues.append(displayValue);
364 
365  displayValue.first = "Reference:";
366  displayValue.second =
368  displayValues.append(displayValue);
369 
370  displayValue.first = "Origin:";
371  displayValue.second =
373  displayValues.append(displayValue);
374 
375  displayValue.first = "URL:";
376  displayValue.second =
378  displayValues.append(displayValue);
379 
380  for (int i = 0; i < displayValues.count(); i++) {
381  QLabel *titleLabel = new QLabel(displayValues[i].first);
382  QLabel *valueLabel = new QLabel( (this->*(displayValues[i].second))() );
383  valueLabel->setOpenExternalLinks(true);
384  valueLabel->setWordWrap(true);
385 
386  if (valueLabel->text() != "") {
387  layout->addWidget(titleLabel, row, 0);
388  layout->addWidget(valueLabel, row, 1);
389  }
390  else {
391  delete titleLabel;
392  delete valueLabel;
393  }
394 
395  row++;
396  }
397 
398  return widget;
399  }
400 
401 
406  return getTagText("id");
407  }
408 
409 
414  return getTagText("name");
415  }
416 
417 
422  return getTagText("cleanName");
423  }
424 
425 
432  QString targetStr = target();
433  QString cnet = "";
434 
435  if (targetStr.toUpper() == "MOON")
436  cnet = "LOLA";
437  else if (targetStr.toUpper() == "MARS")
438  cnet = "MDIM 2.1";
439  else if (targetStr.toUpper() == "MERCURY")
440  cnet = "Preliminary MESSENGER";
441 
442  return cnet;
443  }
444 
445 
450  QString nameString = name();
451  QString cleanNameString = cleanName();
452 
453  QString displayNameString = nameString;
454 
455  if (nameString != cleanNameString)
456  displayNameString = nameString + " (" + cleanNameString + ")";
457 
458  return displayNameString;
459  }
460 
461 
466  return getTagText("target");
467  }
468 
469 
474  return getTagText("system");
475  }
476 
477 
482  Distance result;
483 
484  try {
485  result = Distance(toDouble(getTagText("diameter")),
487  }
488  catch (IException &) {
489  }
490 
491  return result;
492  }
493 
494 
499  return diameter().toString();
500  }
501 
502 
507  Latitude result;
508 
509  try {
510  result = Latitude(toDouble(getTagText("centerlatitude")), Angle::Degrees);
511  }
512  catch (IException &) {
513  }
514 
515  return result;
516  }
517 
518 
523  return centerLatitude().toString();
524  }
525 
526 
531  Longitude result;
532 
533  try {
534  result = Longitude(toDouble(getTagText("centerlongitude")),
536  }
537  catch (IException &) {
538  }
539 
540  return result;
541  }
542 
543 
548  return centerLongitude().toString();
549  }
550 
551 
556  Latitude result;
557 
558  try {
559  result = Latitude(toDouble(getTagText("northernLatitude")), Angle::Degrees);
560  }
561  catch (IException &) {
562  }
563 
564  return result;
565  }
566 
567 
573  return northernLatitude().toString();
574  }
575 
576 
581  Latitude result;
582 
583  try {
584  result = Latitude(toDouble(getTagText("southernLatitude")), Angle::Degrees);
585  }
586  catch (IException &) {
587  }
588 
589  return result;
590  }
591 
592 
598  return southernLatitude().toString();
599  }
600 
601 
606  Longitude result;
607 
608  try {
609  result = Longitude(toDouble(getTagText("easternLongitude")),
611  }
612  catch (IException &) {
613  }
614 
615  return result;
616  }
617 
618 
624  return easternLongitude().toString();
625  }
626 
627 
632  Longitude result;
633 
634  try {
635  result = Longitude(toDouble(getTagText("westernLongitude")),
637  }
638  catch (IException &) {
639  }
640 
641  return result;
642  }
643 
644 
650  return westernLongitude().toString();
651  }
652 
653 
659  return getTagText("continent");
660  }
661 
662 
667  return getTagText("ethnicity");
668  }
669 
670 
675  return getTagText("approvalstatus");
676  }
677 
678 
683  return getTagText("approvaldate");
684  }
685 
686 
691  return getTagText("featuretype");
692  }
693 
694 
699  return getTagText("reference");
700  }
701 
702 
707  return getTagText("origin");
708  }
709 
710 
715  return getTagText("lastUpdated");
716  }
717 
718 
723  return QUrl("http://planetarynames.wr.usgs.gov/Feature/" + id());
724  }
725 
726 
731  return "<a href='" + referenceUrl().toString() + "'>" +
732  referenceUrl().toString() +
733  "</a>";
734  }
735 
736 
741  return m_approvalStatus;
742  }
743 
744 
751  std::swap(m_xmlRepresenation, other.m_xmlRepresenation);
752  std::swap(m_approvalStatus, other.m_approvalStatus);
753 
754  }
755 
756 
764  const Feature &rhs) {
765  Feature copy(rhs);
766  swap(copy);
767  return *this;
768  }
769 
770 
779  QString FeatureNomenclature::Feature::getTagText(QString tagName) const {
780  QString text;
781 
782  if (m_xmlRepresenation) {
783  QDomNodeList nodes =
784  m_xmlRepresenation->elementsByTagName(tagName);
785 
786  if (nodes.count())
787  text = nodes.at(0).toElement().text().trimmed();
788  }
789 
790  return text;
791  }
792 
793 
801  void FeatureNomenclature::requestFinished(QNetworkReply *reply) {
802  if (reply->error() == QNetworkReply::NoError) {
803 
804  QString errorMsg;
805  int errorLine;
806  int errorCol;
807 
808  QDomDocument xmlResultDocument;
809  if (xmlResultDocument.setContent(reply->readAll(),
810  &errorMsg, &errorLine, &errorCol)) {
811  for (QDomNode node = xmlResultDocument.firstChild();
812  !node.isNull();
813  node = node.nextSibling()) {
814  QDomElement element = node.toElement();
815  if (element.tagName() == "searchresults") {
816  readSearchResults(element);
817  }
818  }
819  }
820  else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 301) {
821  IString msg = "The URL has been permanently moved to " +
822  reply->attribute(QNetworkRequest::RedirectionTargetAttribute)
823  .toUrl().toString();
825  }
826  else {
827  QMessageBox::warning(NULL, "Failed to read nomenclature database result",
828  "An error occurred when parsing the data sent back "
829  "from the nomenclature database. "
830  "The XML result was invalid. The parse is [" +
831  errorMsg + "] on line [" +
832  QString::number(errorLine) +"], column [" +
833  QString::number(errorCol) + "]");
834  }
835  }
836  else {
837  QMessageBox::warning(NULL, "Failed to query nomenclature database",
838  "An error occurred when querying the nomenclature "
839  "database for features that intersect the queried "
840  "ground range. Please make sure you have an active "
841  "internet connection. The error returned was [" +
842  reply->errorString() + "]");
843  }
844 
845  reply->deleteLater();
846 
847  if (m_lastQuery) {
848  emit featuresIdentified(this);
849  }
850  m_lastQuery = true;
851  }
852 
853 
860  void FeatureNomenclature::readSearchResults(QDomElement xmlSearchResults) {
861  ASSERT(xmlSearchResults.tagName() == "searchresults");
862 
863  if (!m_features)
865 
866  for (QDomNode node = xmlSearchResults.firstChild();
867  !node.isNull();
868  node = node.nextSibling()) {
869  QDomElement element = node.toElement();
870  QString approvalID = element.childNodes().item(15).toElement().attribute("id");
871 
872  if (element.tagName() == "feature") {
873 
874  if(approvalID == "5") {
876  }
877  else if(approvalID == "6") {
879  }
880  else if(approvalID == "7") {
882  }
883  else {
885  }
886 
887  m_features->append(Feature(element, m_statusApproval));
888  }
889  }
890  }
891 
892 
907  void FeatureNomenclature::runQuery(QString target,
908  Latitude startLat, Longitude startLon,
909  Latitude endLat, Longitude endLon) {
910 
911  QUrlQuery formQuery;
912 
913  // List of XML fields we want from the server
914  formQuery.addQueryItem("additionalInfoColumn", "true");
915  formQuery.addQueryItem("approvalDateColumn", "true");
916  formQuery.addQueryItem("approvalStatusColumn", "true");
917  formQuery.addQueryItem("centerLatLonColumn", "true");
918  formQuery.addQueryItem("cleanFeatureNameColumn", "true");
919  formQuery.addQueryItem("contEthColumn", "true");
920  formQuery.addQueryItem("coordSystemColumn", "true");
921  formQuery.addQueryItem("diameterColumn", "true");
922  formQuery.addQueryItem("featureIDColumn", "true");
923  formQuery.addQueryItem("featureNameColumn", "true");
924  formQuery.addQueryItem("featureTypeCodeColumn", "true");
925  formQuery.addQueryItem("featureTypeColumn", "true");
926  formQuery.addQueryItem("lastUpdatedColumn", "true");
927  formQuery.addQueryItem("latLonColumn", "true");
928  formQuery.addQueryItem("originColumn", "true");
929  formQuery.addQueryItem("quadColumn", "true");
930  formQuery.addQueryItem("referenceColumn", "true");
931  formQuery.addQueryItem("targetColumn", "true");
932 
933  // Data units
934  formQuery.addQueryItem("is_0_360", "true");
935  formQuery.addQueryItem("is_planetographic", "false");
936  formQuery.addQueryItem("is_positive_east", "true");
937 
938  // Format parameters
939  formQuery.addQueryItem("displayType", "XML");
940  formQuery.addQueryItem("sort_asc", "true");
941  formQuery.addQueryItem("sort_column", "name");
942 
943  // Search critera (required even if blank)
944  formQuery.addQueryItem("approvalStatus", "");
945  formQuery.addQueryItem("beginDate", "");
946  formQuery.addQueryItem("continent", "");
947  formQuery.addQueryItem("endDate", "");
948  formQuery.addQueryItem("ethnicity", "");
949  formQuery.addQueryItem("feature", "");
950  formQuery.addQueryItem("featureType", "");
951  formQuery.addQueryItem("minFeatureDiameter", "");
952  formQuery.addQueryItem("maxFeatureDiameter", "");
953  formQuery.addQueryItem("reference", "");
954  formQuery.addQueryItem("system", "");
955 
956  formQuery.addQueryItem("target", target.toUpper());
957  formQuery.addQueryItem("easternLongitude",
958  QString::number(endLon.degrees()));
959  formQuery.addQueryItem("westernLongitude",
960  QString::number(startLon.degrees()));
961  formQuery.addQueryItem("northernLatitude",
962  QString::number(endLat.degrees()));
963  formQuery.addQueryItem("southernLatitude",
964  QString::number(startLat.degrees()));
965 
966  m_networkMgr->post(*m_request, formQuery.query(QUrl::FullyEncoded).toUtf8());
967  }
968 }
When this status is assigned to a feature, there will be no status displayed and the feature will not...
void queryFeatures(QString target, Latitude startLat, Longitude startLon, Latitude endLat, Longitude endLon)
Makes sure the longitudinal ranges are correct.
QNetworkRequest * m_request
Network request sent.
void readSearchResults(QDomElement)
This is a helper method for requestFinished.
When this status is assigned to a feature, the displayed status will be "Dropped, disallowed" and the...
IAUStatus m_statusApproval
The approval status of the feature from the database.
FeatureNomenclature()
Instantiate a feature nomenclature.
Feature nomenclature database querier.
IAUStatus m_approvalStatus
The approval status of the feature.
QList< Feature > features() const
This gives you the features found in all of the queries so far.
When this status is assigned to a feature, the displayed status will be "Adopted by the IAU" and the ...
void swap(Feature &other)
Swap the member data of this feature with another feature.
This class is designed to encapsulate the concept of a Latitude.
Definition: Latitude.h:63
The distance is being specified in kilometers.
Definition: Distance.h:58
~FeatureNomenclature()
Frees allocated memory.
Feature & operator=(const Feature &rhs)
Assign the values of this feature from the values of rhs.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:162
Feature()
Construct a feature with no data.
Distance measurement, usually in meters.
Definition: Distance.h:47
QList< Feature > * m_features
These are the features identified by the nomenclature database.
double degrees() const
Get the angle in units of Degrees.
Definition: Angle.h:249
QNetworkAccessManager * m_networkMgr
Network manager does request.
This class is designed to encapsulate the concept of a Longitude.
Definition: Longitude.h:52
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition: Angle.h:73
bool m_lastQuery
True if all queries have finished.
QString getTagText(QString tagName) const
Get the string value of an element of the XML.
When this status is assigned to a feature, the displayed status will be "Never approved by the IAU" a...
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
static QList< QPair< Longitude, Longitude > > to360Range(Longitude startLon, Longitude endLon)
Calculates where the longitude range is in 0-360.
Definition: Longitude.cpp:377
void runQuery(QString target, Latitude startLat, Longitude startLon, Latitude endLat, Longitude endLon)
Query the nomenclature database for features inside the given range on the target.
bool isValid() const
Test if this distance has been initialized or not.
Definition: Distance.cpp:204
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
void swap(FeatureNomenclature &other)
Swap the instances *this and other.
QWidget * toWidget() const
This converts the data in this feature to a widget.
QDomElement * m_xmlRepresenation
This is the XML returned by the nomenclature DB.
~Feature()
Clean up allocated memory by this feature.
Isis exception class.
Definition: IException.h:107
Adds specific functionality to C++ strings.
Definition: IString.h:181
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
void requestFinished(QNetworkReply *)
This is called when a query is done.
static bool featureDiameterGreaterThan(const FeatureNomenclature::Feature &lhs, const FeatureNomenclature::Feature &rhs)
Compare the diameter of two features.
void featuresIdentified(FeatureNomenclature *)
This is emitted when a query is completed.
bool hasResult() const
Test if any understandable results have been received from the nomenclature database.
FeatureNomenclature & operator=(const FeatureNomenclature &other)
This takes on the data from rhs.
A named feature on a target.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
IAUStatus
Enumeration of approval statuses.