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