Isis 3 Programmer Reference
ProcessExportPds4.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "ProcessExportPds4.h"
8
9#include <cmath>
10#include <iostream>
11#include <sstream>
12
13#include <QDomDocument>
14#include <QMap>
15#include <QRegularExpression>
16#include <QString>
17
18#include "Application.h"
19#include "FileName.h"
20#include "IException.h"
21#include "Projection.h"
22#include "ProjectionFactory.h"
23#include "Pvl.h"
24#include "PvlToXmlTranslationManager.h"
25
26using namespace std;
27
28namespace Isis {
29
30
36
37 m_lid = "";
38 m_versionId = "";
39 m_title = "";
40
41 m_imageType = StandardImage;
42
43 qSetGlobalQHashSeed(0); // hash seed to force consistent output
44
45 m_domDoc = new QDomDocument("");
46
47 // base xml file
48 // <?xml version="1.0" encoding="UTF-8"?>
49 QString xmlVersion = "version=\"1.0\" encoding=\"utf-8\"";
50 QDomProcessingInstruction xmlHeader =
51 m_domDoc->createProcessingInstruction("xml", xmlVersion);
52 m_domDoc->appendChild(xmlHeader);
53
54 // base pds4 schema location
55 m_schemaLocation = "http://pds.nasa.gov/pds4/pds/v1 http://pds.nasa.gov/pds4/pds/v1/PDS4_PDS_1B00.xsd";
56
57 QString xmlModel;
58 xmlModel += "href=\"http://pds.nasa.gov/pds4/pds/v1/PDS4_PDS_1B00.sch\" ";
59 xmlModel += "schematypens=\"http://purl.oclc.org/dsdl/schematron\"";
60 QDomProcessingInstruction header =
61 m_domDoc->createProcessingInstruction("xml-model", xmlModel);
62 m_domDoc->appendChild(header);
63
64 }
65
66
75
76
87
88
94 void ProcessExportPds4::setImageType(ImageType imageType) {
95 m_imageType = imageType;
96 }
97
98
109 if (InputCubes.size() == 0) {
110 QString msg("Must set an input cube before creating a PDS4 label.");
111 throw IException(IException::Programmer, msg, _FILEINFO_);
112 }
113 if (m_domDoc->documentElement().isNull()) {
114 QDomElement root = m_domDoc->createElement("Product_Observational");
115 root.setAttribute("xmlns", "http://pds.nasa.gov/pds4/pds/v1");
116 root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
117 root.setAttribute("xsi:schemaLocation",
118 "http://pds.nasa.gov/pds4/pds/v1 http://pds.nasa.gov/pds4/pds/v1");
119 m_domDoc->appendChild(root);
120 }
121
122 try {
123 // <Product_Observational>
124 // <Identification_Area>
126 }
127 catch (IException &e) {
128 QString msg = "Unable to translate and export identification information.";
129 throw IException(e, IException::Programmer, msg, _FILEINFO_);
130 }
131 try {
132 // <Product_Observational>
133 // <Observation_Area>
135 }
136 catch (IException &e) {
137 QString msg = "Unable to translate and export instrument information.";
138 throw IException(e, IException::Programmer, msg, _FILEINFO_);
139 }
140 try {
141 // <Product_Observational>
142 // <Observation_Area>
143 // <Discipline_Area>
144 // <disp:Display_Settings>
146 }
147 catch (IException &e) {
148 QString msg = "Unable to translate and export display settings.";
149 throw IException(e, IException::Programmer, msg, _FILEINFO_);
150 }
151
152 try {
153 // <Product_Observational>
154 // <Observation_Area>
155 // <Discipline_Area>
156 // <sp:Spectral_Characteristics> OR <img:Imaging>
158 }
159 catch (IException &e) {
160 QString msg = "Unable to translate and export spectral information.";
161 throw IException(e, IException::Programmer, msg, _FILEINFO_);
162 }
163
164 try {
165 // <Product_Observational>
166 // <Observation_Area>
167 // <Discipline_Area>
168 // <card:Cartography>
170 }
171 catch (IException &e) {
172 QString msg = "Unable to translate and export mapping group.";
173 throw IException(e, IException::Programmer, msg, _FILEINFO_);
174 }
175 try {
176 // <Product_Observational>
177 // <File_Area_Observational>
179 }
180 catch (IException &e) {
181 QString msg = "Unable to translate and export standard image information.";
182 throw IException(e, IException::Programmer, msg, _FILEINFO_);
183 }
184 }
185
186
192 Pvl *inputLabel = InputCubes[0]->label();
193 FileName translationFileName;
194
195 if (inputLabel->findObject("IsisCube").hasGroup("Instrument")) {
196
197 // Translate the Instrument group
198 translationFileName = "$ISISROOT/appdata/translations/pds4ExportInstrument.trn";
199 PvlToXmlTranslationManager instXlator(*inputLabel, translationFileName.expanded());
200 instXlator.Auto(*m_domDoc);
201
202 // If instrument and spacecraft values were translated, create the combined name
203 QDomElement obsAreaNode = m_domDoc->documentElement().firstChildElement("Observation_Area");
204
205 if ( !obsAreaNode.isNull() ) {
206
207 // fix start/stop times, if needed
208 QDomElement timeNode = obsAreaNode.firstChildElement("Time_Coordinates");
209 if (!timeNode.isNull()) {
210 QDomElement startTime = timeNode.firstChildElement("start_date_time");
211 if (startTime.text() == "") {
212 startTime.setAttribute("xsi:nil", "true");
213 }
214 else {
215 QString timeValue = startTime.text();
216 PvlToXmlTranslationManager::resetElementValue(startTime, timeValue + "Z");
217 }
218 QDomElement stopTime = timeNode.firstChildElement("stop_date_time");
219 if (stopTime.text() == "") {
220 stopTime.setAttribute("xsi:nil", "true");
221 }
222 else {
223 QString timeValue = stopTime.text();
224 PvlToXmlTranslationManager::resetElementValue(stopTime, timeValue + "Z");
225 }
226 }
227
228 QDomElement obsSysNode = obsAreaNode.firstChildElement("Observing_System");
229 if ( !obsSysNode.isNull() ) {
230 QString instrumentName;
231 QString spacecraftName;
232 QDomElement obsSysCompNode = obsSysNode.firstChildElement("Observing_System_Component");
233 while ( !obsSysCompNode.isNull()) {
234 QDomElement compTypeNode = obsSysCompNode.firstChildElement("type");
235 if ( compTypeNode.text().compare("Spacecraft") == 0 ) {
236 QString componentName = obsSysCompNode.firstChildElement("name").text();
237 if (QString::compare(componentName, "TBD", Qt::CaseInsensitive) != 0) {
238 spacecraftName = componentName;
239 }
240 }
241 else if ( compTypeNode.text().compare("Instrument") == 0 ) {
242 QString componentName = obsSysCompNode.firstChildElement("name").text();
243 if (QString::compare(componentName, "TBD", Qt::CaseInsensitive) != 0) {
244 instrumentName = componentName;
245 }
246 }
247 obsSysCompNode = obsSysCompNode.nextSiblingElement("Observing_System_Component");
248 }
249 QDomElement combinedNode = m_domDoc->createElement("name");
250 QString combinedValue = "TBD";
251 if ( !instrumentName.isEmpty() && !spacecraftName.isEmpty() ) {
252 combinedValue = spacecraftName + " " + instrumentName;
253 }
254 combinedNode.appendChild( m_domDoc->createTextNode(combinedValue) );
255 obsSysNode.insertBefore( combinedNode, obsSysNode.firstChild() );
256 }
257 }
258
259 // Translate the Target name
260 translationFileName = "$ISISROOT/appdata/translations/pds4ExportTargetFromInstrument.trn";
261 PvlToXmlTranslationManager targXlator(*inputLabel, translationFileName.expanded());
262 targXlator.Auto(*m_domDoc);
263
264 // Move target to just below Observing_System.
265 QDomElement targetIdNode = obsAreaNode.firstChildElement("Target_Identification");
266 obsAreaNode.insertAfter(targetIdNode, obsAreaNode.firstChildElement("Observing_System"));
267 }
268 else if (inputLabel->findObject("IsisCube").hasGroup("Mapping")) {
269
270 translationFileName = "$ISISROOT/appdata/translations/pds4ExportTargetFromMapping.trn";
271 PvlToXmlTranslationManager targXlator(*inputLabel, translationFileName.expanded());
272 targXlator.Auto(*m_domDoc);
273 }
274 else {
275 throw IException(IException::Unknown, "Unable to find a target in input cube.", _FILEINFO_);
276 }
277 }
278
279
285 QDomElement obsAreaNode = m_domDoc->documentElement().firstChildElement("Observation_Area");
286 if ( !obsAreaNode.isNull() ) {
287
288 // fix times
289 QDomElement timeNode = obsAreaNode.firstChildElement("Time_Coordinates");
290 if (!timeNode.isNull()) {
291 QDomElement startTime = timeNode.firstChildElement("start_date_time");
292 if (startTime.text() == "") {
293 startTime.setAttribute("xsi:nil", "true");
294 }
295 else {
296 QString timeValue = startTime.text();
297 if (!timeValue.contains("Z")) {
298 PvlToXmlTranslationManager::resetElementValue(startTime, timeValue + "Z");
299 }
300 }
301
302 QDomElement stopTime = timeNode.firstChildElement("stop_date_time");
303 if (stopTime.text() == "") {
304 stopTime.setAttribute("xsi:nil", "true");
305 }
306 else {
307 QString timeValue = stopTime.text();
308 if (!timeValue.contains("Z")) {
309 PvlToXmlTranslationManager::resetElementValue(stopTime, timeValue + "Z");
310 }
311 }
312 QStringList xmlPath;
313 xmlPath << "Product_Observational"
314 << "Observation_Area"
315 << "Discipline_Area"
316 << "geom:Geometry"
317 << "geom:Geometry_Orbiter"
318 << "geom:geometry_reference_time_utc";
319
320 QDomElement baseElement = m_domDoc->documentElement();
321 QDomElement geomRefTime = getElement(xmlPath, baseElement);
322 if (geomRefTime.text() == "") {
323 geomRefTime.setAttribute("xsi:nil", "true");
324 }
325 else {
326 QString timeValue = geomRefTime.text();
327 PvlToXmlTranslationManager::resetElementValue(geomRefTime, timeValue + "Z");
328 }
329 xmlPath.clear();
330 xmlPath << "Product_Observational"
331 << "Observation_Area"
332 << "Discipline_Area"
333 << "geom:Geometry"
334 << "geom:Image_Display_Geometry"
335 << "geom:Object_Orientation_North_East"
336 << "geom:east_azimuth";
337 QDomElement eastAzimuth = getElement(xmlPath, baseElement);
338 if (eastAzimuth.text() != "") {
339 PvlToXmlTranslationManager::resetElementValue(eastAzimuth, eastAzimuth.text(), "deg");
340 }
341 }
342
343 QDomElement investigationAreaNode = obsAreaNode.firstChildElement("Investigation_Area");
344 obsAreaNode.insertAfter(investigationAreaNode, obsAreaNode.firstChildElement("Time_Coordinates"));
345
346 QDomElement obsSystemNode = obsAreaNode.firstChildElement("Observing_System");
347 obsAreaNode.insertAfter(obsSystemNode, obsAreaNode.firstChildElement("Investigation_Area"));
348
349 QDomElement targetIdNode = obsAreaNode.firstChildElement("Target_Identification");
350 obsAreaNode.insertAfter(targetIdNode, obsAreaNode.firstChildElement("Observing_System"));
351
352 QDomElement missionAreaNode = obsAreaNode.firstChildElement("Mission_Area");
353 obsAreaNode.insertAfter(missionAreaNode, obsAreaNode.firstChildElement("Target_Identification"));
354
355 QDomElement disciplineAreaNode = obsAreaNode.firstChildElement("Discipline_Area");
356 obsAreaNode.insertAfter(disciplineAreaNode, obsAreaNode.firstChildElement("Mission_Area"));
357 }
358
359 QDomElement identificationAreaNode = m_domDoc->documentElement().firstChildElement("Identification_Area");
360 if ( !identificationAreaNode.isNull() ) {
361 QDomElement aliasListNode = identificationAreaNode.firstChildElement("Alias_List");
362 identificationAreaNode.insertAfter(aliasListNode, identificationAreaNode.firstChildElement("product_class"));
363 }
364
365 // Put Reference list in correct place:
366 QDomElement referenceListNode = m_domDoc->documentElement().firstChildElement("Reference_List");
367 if ( !referenceListNode.isNull() && !identificationAreaNode.isNull() ) {
368 m_domDoc->documentElement().insertAfter(referenceListNode, obsAreaNode);
369 }
370
371 QDomElement fileAreaObservationalNode = m_domDoc->documentElement().firstChildElement("File_Area_Observational");
372 QDomElement array2DImageNode = fileAreaObservationalNode.firstChildElement("Array_2D_Image");
373 if ( !array2DImageNode.isNull() ) {
374 QDomElement descriptionNode = array2DImageNode.firstChildElement("description");
375 array2DImageNode.insertAfter(descriptionNode, array2DImageNode.firstChildElement("axis_index_order"));
376 }
377 }
378
408 m_lid = lid.toLower();
409 }
410
411
425 void ProcessExportPds4::setVersionId(QString versionId) {
426 m_versionId = versionId;
427 }
428
429
440 void ProcessExportPds4::setTitle(QString title) {
441 m_title = title;
442 }
443
444
454 m_schemaLocation = schema;
455 }
456
457
463 Pvl *inputLabel = InputCubes[0]->label();
464 FileName translationFileName;
465 translationFileName = "$ISISROOT/appdata/translations/pds4ExportIdentificationArea.trn";
466 PvlToXmlTranslationManager xlator(*inputLabel, translationFileName.expanded());
467 xlator.Auto(*m_domDoc);
468
469 if (m_lid.isEmpty()) {
470 m_lid = "urn:nasa:pds:TBD:TBD:TBD";
471 }
472
473 QDomElement identificationElement;
474 QStringList identificationPath;
475 identificationPath.append("Product_Observational");
476 identificationPath.append("Identification_Area");
477 try {
478 identificationElement = getElement(identificationPath);
479 if( identificationElement.isNull() ) {
480 throw IException(IException::Unknown, "", _FILEINFO_);
481 }
482 }
483 catch(IException &e) {
484 QString msg = "Could not find Identification_Area element "
485 "to add modification history under.";
486 throw IException(IException::Programmer, msg, _FILEINFO_);
487 }
488
489 QDomElement lidElement = identificationElement.firstChildElement("logical_identifier");
491
492 if (m_versionId != "") {
493 QDomElement versionElement = identificationElement.firstChildElement("version_id");
495 }
496
497 if (m_title != "") {
498 QDomElement titleElement = identificationElement.firstChildElement("title");
500 }
501
502 // Get export history and add <Modification_History> element.
503 // These regular expressions match the pipe followed by the date from
504 // the Application::Version() return value.
505 QRegularExpression versionRegex(" \\| \\d{4}\\-\\d{2}\\-\\d{2}");
506 QString historyDescription = "Created PDS4 output product from ISIS cube with the "
508 + " application from ISIS version "
509 + Application::Version().remove(versionRegex) + ".";
510 // This regular expression matches the time from the Application::DateTime return value.
511 QRegularExpression dateRegex("T\\d{2}:\\d{2}:\\d{2}");
512 QString historyDate = Application::DateTime().remove(dateRegex);
513 addHistory(historyDescription, historyDate);
514 }
515
516
522 // Add header info
523 addSchema("PDS4_DISP_1B00.sch",
524 "PDS4_DISP_1B00.xsd",
525 "xmlns:disp",
526 "http://pds.nasa.gov/pds4/disp/v1");
527
528 Pvl *inputLabel = InputCubes[0]->label();
529 FileName translationFileName;
530 translationFileName = "$ISISROOT/appdata/translations/pds4ExportDisplaySettings.trn";
531 PvlToXmlTranslationManager xlator(*inputLabel, translationFileName.expanded());
532 xlator.Auto(*m_domDoc);
533 }
534
535
541 Pvl *inputLabel = InputCubes[0]->label();
542 if ( !inputLabel->findObject("IsisCube").hasGroup("BandBin") ) return;
543 // Add header info
544 addSchema("PDS4_IMG_1A10_1510.sch",
545 "PDS4_IMG_1A10_1510.xsd",
546 "xmlns:img",
547 "http://pds.nasa.gov/pds4/img/v1");
548
549 // Get the input Isis cube label and find the BandBin group if it has one
550 if (m_imageType == StandardImage) {
551 translateBandBinImage(*inputLabel);
552 }
553 else {
554 // Add header info
555 addSchema("PDS4_SP_1100.sch",
556 "PDS4_SP_1100.xsd",
557 "xmlns:sp",
558 "http://pds.nasa.gov/pds4/sp/v1");
559 if (m_imageType == UniformlySampledSpectrum) {
561 }
562 else if (m_imageType == BinSetSpectrum) {
564 }
565 }
566 }
567
568
573 QString translationFile = "$ISISROOT/appdata/translations/";
574 translationFile += "pds4ExportBandBinImage.trn";
575 FileName translationFileName(translationFile);
576 PvlToXmlTranslationManager xlator(inputLabel, translationFileName.expanded());
577 xlator.Auto(*m_domDoc);
578 }
579
580
585 QString translationFile = "$ISISROOT/appdata/translations/";
586 translationFile += "pds4ExportBandBinSpectrumUniform.trn";
587 FileName translationFileName(translationFile);
588 PvlToXmlTranslationManager xlator(inputLabel, translationFileName.expanded());
589 xlator.Auto(*m_domDoc);
590
591 PvlGroup bandBinGroup = inputLabel.findObject("IsisCube").findGroup("BandBin");
592 // fix multi-valued bandbin info
593 QStringList xmlPath;
594 xmlPath << "Product_Observational"
595 << "Observation_Area"
596 << "Discipline_Area"
597 << "sp:Spectral_Characteristics";
598 QDomElement baseElement = m_domDoc->documentElement();
599 QDomElement spectralCharElement = getElement(xmlPath, baseElement);
600
601 // Axis_Bin_Set for variable bin widths
602 // required - bin_sequence_number, center_value, bin_width
603 // optional - detector_number, grating_position, original_bin_number, scaling_factor, value_offset, Filter
604 // ... see schema for more...
605 PvlKeyword center;
606 if (bandBinGroup.hasKeyword("Center")) {
607 center = bandBinGroup["Center"];
608 }
609 else if (bandBinGroup.hasKeyword("FilterCenter")) {
610 center = bandBinGroup["FilterCenter"];
611 }
612 else {
613 QString msg = "Unable to translate BandBin info for BinSetSpectrum. "
614 "Translation for PDS4 required value [center_value] not found.";
615 throw IException(IException::Programmer, msg, _FILEINFO_);
616 }
617 PvlKeyword width;
618 if (bandBinGroup.hasKeyword("Width")) {
619 width = bandBinGroup["Width"];
620 }
621 else if (bandBinGroup.hasKeyword("FilterWidth")) {
622 width = bandBinGroup["FilterWidth"];
623 }
624 else {
625 QString msg = "Unable to translate BandBin info for BinSetSpectrum. "
626 "Translation for PDS4 required value [bin_width] not found.";
627 throw IException(IException::Programmer, msg, _FILEINFO_);
628 }
629
630 QString units = center.unit();
631
632 if (!width.unit().isEmpty() ) {
633 if (units.isEmpty()) {
634 units = width.unit();
635 }
636 if (units.compare(width.unit(), Qt::CaseInsensitive) != 0) {
637 QString msg = "Unable to translate BandBin info for BinSetSpectrum. "
638 "Unknown or unmatching units for [center_value] and [bin_width].";
639 throw IException(IException::Programmer, msg, _FILEINFO_);
640 }
641 }
642
643 PvlKeyword originalBand;
644 if (bandBinGroup.hasKeyword("OriginalBand")) {
645 originalBand = bandBinGroup["OriginalBand"];
646 }
647 PvlKeyword name;
648 if (bandBinGroup.hasKeyword("Name")) {
649 name = bandBinGroup["Name"];
650 }
651 else if (bandBinGroup.hasKeyword("FilterName")) {
652 name = bandBinGroup["FilterName"];
653 }
654 else if (bandBinGroup.hasKeyword("FilterId")) {
655 name = bandBinGroup["FilterId"];
656 }
657 PvlKeyword number;
658 if (bandBinGroup.hasKeyword("Number")) {
659 number = bandBinGroup["Number"];
660 }
661 else if (bandBinGroup.hasKeyword("FilterNumber")) {
662 number = bandBinGroup["FilterNumber"];
663 }
664
665 QDomElement axisBinSetElement = spectralCharElement.firstChildElement("sp:Axis_Bin_Set");
666 if (axisBinSetElement.isNull()) {
667 axisBinSetElement = m_domDoc->createElement("sp:Axis_Bin_Set");
668 spectralCharElement.appendChild(axisBinSetElement);
669 }
670 int bands = (int)inputLabel.findObject("IsisCube")
671 .findObject("Core")
672 .findGroup("Dimensions")
673 .findKeyword("Bands");
674
675 for (int i = 0; i < bands; i++) {
676
677 QDomElement bin = m_domDoc->createElement("sp:Bin");
678 axisBinSetElement.appendChild(bin);
679
680 QDomElement binSequenceNumber = m_domDoc->createElement("sp:bin_sequence_number");
682 bin.appendChild(binSequenceNumber);
683
684
685 QDomElement centerValue = m_domDoc->createElement("sp:center_value");
686 PvlToXmlTranslationManager::setElementValue(centerValue, center[i], units);
687 bin.appendChild(centerValue);
688
689 QDomElement binWidth = m_domDoc->createElement("sp:bin_width");
690 if (width.size() == bands) {
691 PvlToXmlTranslationManager::setElementValue(binWidth, width[i] , units);
692 }
693 else {
694 PvlToXmlTranslationManager::setElementValue(binWidth, width[0] , units);
695 }
696 bin.appendChild(binWidth);
697
698 QDomElement originalBinNumber = m_domDoc->createElement("sp:original_bin_number");
699 if (originalBand.size() > 0) {
700 PvlToXmlTranslationManager::setElementValue(originalBinNumber, originalBand[i]);
701 bin.appendChild(originalBinNumber);
702 }
703
704 if (name.size() > 0 || number.size() > 0) {
705 QDomElement filter = m_domDoc->createElement("sp:Filter");
706 bin.appendChild(filter);
707 if (name.size() > 0) {
708 QDomElement filterName = m_domDoc->createElement("sp:filter_name");
710 filter.appendChild(filterName);
711 }
712 if (number.size() > 0) {
713 QDomElement filterNumber= m_domDoc->createElement("sp:filter_number");
714 PvlToXmlTranslationManager::setElementValue(filterNumber, number[i]);
715 filter.appendChild(filterNumber);
716 }
717 }
718 }
719
720 }
721
722
727 QString translationFile = "$ISISROOT/appdata/translations/";
728 translationFile += "pds4ExportBandBinSpectrumBinSet.trn";
729 FileName translationFileName(translationFile);
730 PvlToXmlTranslationManager xlator(inputLabel, translationFileName.expanded());
731 xlator.Auto(*m_domDoc);
732
733 PvlGroup bandBinGroup = inputLabel.findObject("IsisCube").findGroup("BandBin");
734 // fix multi-valued bandbin info
735 QStringList xmlPath;
736 xmlPath << "Product_Observational"
737 << "Observation_Area"
738 << "Discipline_Area"
739 << "sp:Spectral_Characteristics";
740 QDomElement baseElement = m_domDoc->documentElement();
741 QDomElement spectralCharElement = getElement(xmlPath, baseElement);
742
743 // Axis_Uniformly_Sampled
744 // required - sampling_parameter_type (frequency, wavelength, wavenumber)
745 // sampling_interval (units Hz, Angstrom, cm**-1, respectively)
746 // bin_width (units Hz, Angstrom, cm**-1, respectively)
747 // first_center_value (units Hz, Angstrom, cm**-1, respectively)
748 // last_center_value (units Hz, Angstrom, cm**-1, respectively)
749 // Local_Internal_Reference
750 // Local_Internal_Reference:local_reference_type = spectral_characteristics_to_array_axis
751 // Local_Internal_Reference:local_identifier_reference,
752 // 1. At least one Axis_Array:axis_name must match the
753 // value of the local_identifier_reference in the
754 // Axis_Uniformly_Sampled.
755 // Set Axis_Uniformly_Sampled:local_identifier_reference = Axis_Array:axis_name = Band
756 // 2. At least one Array_3D_Spectrum:local_identifier must match
757 // the value of the local_identifier_reference in the
758 // Spectral_Characteristics.
759 // Set Spectral_Characteristics:local_identifier_reference = Array_3D_Spectrum:local_identifier = Spectral_Array_Object
760 // Local_Internal_Reference:local_reference_type = spectral_characteristics_to_array_axis
761 PvlKeyword center("Center");
762 if (bandBinGroup.hasKeyword("FilterCenter")) {
763 center = bandBinGroup["FilterCenter"];
764 }
765 else if (bandBinGroup.hasKeyword("Center")) {
766 center = bandBinGroup["Center"];
767 }
768 else {
769 QString msg = "Unable to translate BandBin info for UniformlySpacedSpectrum. "
770 "Translation for PDS4 required value [last_center_value] not found.";
771 throw IException(IException::Programmer, msg, _FILEINFO_);
772 }
773 QString lastCenter = center[center.size() - 1];
774
775 QDomElement axisBinSetElement = spectralCharElement.firstChildElement("sp:Axis_Uniformly_Sampled");
776 if (axisBinSetElement.isNull()) {
777 axisBinSetElement = m_domDoc->createElement("sp:Axis_Uniformly_Sampled");
778 spectralCharElement.appendChild(axisBinSetElement);
779 }
780
781 QDomElement lastCenterElement = m_domDoc->createElement("sp:last_center_value");
782 PvlToXmlTranslationManager::setElementValue(lastCenterElement, lastCenter);
783 spectralCharElement.appendChild(lastCenterElement);
784
785 }
786
793 void ProcessExportPds4::setPixelDescription(QString description) {
794 m_pixelDescription = description;
795 }
796
803 Pvl *inputLabel = InputCubes[0]->label();
804 QString imageObject = "";
805
806 QString translationFile = "$ISISROOT/appdata/translations/pds4Export";
807 if (m_imageType == StandardImage) {
808 int bands = (int)inputLabel->findObject("IsisCube")
809 .findObject("Core")
810 .findGroup("Dimensions")
811 .findKeyword("Bands");
812 if (bands > 1) {
813 imageObject = "Array_3D_Image";
814 }
815 else {
816 imageObject = "Array_2D_Image";
817 }
818 translationFile += QString(imageObject).remove('_');
819 }
820 else {
821 imageObject = "Array_3D_Spectrum";
822 translationFile += QString(imageObject).remove('_');
823 if (m_imageType == UniformlySampledSpectrum) {
824 translationFile += "Uniform";
825 }
826 else if (m_imageType == BinSetSpectrum) {
827 translationFile += "BinSet";
828 }
829 }
830 translationFile += ".trn";
831 FileName translationFileName(translationFile);
832
833 PvlToXmlTranslationManager xlator(*inputLabel, translationFileName.expanded());
834 xlator.Auto(*m_domDoc);
835
836 QDomElement rootElement = m_domDoc->documentElement();
837 QDomElement fileAreaObservationalElement =
838 rootElement.firstChildElement("File_Area_Observational");
839
840 // Calculate the core base/mult for the output cube
841 double base = 0.0;
842 double multiplier = 1.0;
843 double outputMin, outputMax;
844
845 double inputMin = (p_inputMinimum.size()) ? p_inputMinimum[0] : 0.0;
846 double inputMax = (p_inputMaximum.size()) ? p_inputMaximum[0] : 0.0;
847
848 for(unsigned int i = 0; i < p_inputMinimum.size(); i ++) {
849 inputMin = std::min(inputMin, p_inputMinimum[i]);
850 inputMax = std::max(inputMax, p_inputMaximum[i]);
851 }
852
853 outputMin = p_outputMinimum;
854 outputMax = p_outputMaximum;
855
856 if(p_inputMinimum.size() && ( p_pixelType == Isis::UnsignedByte ||
857 p_pixelType == Isis::SignedWord ||
858 p_pixelType == Isis::UnsignedWord ) ) {
859 multiplier = (inputMax - inputMin) / (outputMax - outputMin);
860 base = inputMin - multiplier * outputMin;
861 }
862
863 if (!fileAreaObservationalElement.isNull()) {
864 QDomElement arrayImageElement =
865 fileAreaObservationalElement.firstChildElement(imageObject);
866 if (!arrayImageElement.isNull()) {
867
868 // reorder axis elements.
869 // Translation order: elements, axis_name, sequence_number
870 // Correct order: axis_name, elements, sequence_number
871 QDomElement axisArrayElement = arrayImageElement.firstChildElement("Axis_Array");
872 while( !axisArrayElement.isNull() ) {
873 QDomElement axisNameElement = axisArrayElement.firstChildElement("axis_name");
874 axisArrayElement.insertBefore(axisNameElement,
875 axisArrayElement.firstChildElement("elements"));
876 axisArrayElement = axisArrayElement.nextSiblingElement("Axis_Array");
877 }
878
879 QDomElement elementArrayElement = m_domDoc->createElement("Element_Array");
880 arrayImageElement.insertBefore(elementArrayElement,
881 arrayImageElement.firstChildElement("Axis_Array"));
882
883 QDomElement dataTypeElement = m_domDoc->createElement("data_type");
886 elementArrayElement.appendChild(dataTypeElement);
887
888 QDomElement scalingFactorElement = m_domDoc->createElement("scaling_factor");
890 toString(multiplier));
891 elementArrayElement.appendChild(scalingFactorElement);
892
893 QDomElement offsetElement = m_domDoc->createElement("value_offset");
895 toString(base));
896 elementArrayElement.appendChild(offsetElement);
897 }
898
899 // Add the Special_Constants class to define ISIS special pixel values if pixel type is
900 QDomElement specialConstantElement = m_domDoc->createElement("Special_Constants");
901 arrayImageElement.insertAfter(specialConstantElement,
902 arrayImageElement.lastChildElement("Axis_Array"));
903
904 switch (p_pixelType) {
905 case Real:
906 { QDomElement nullElement = m_domDoc->createElement("missing_constant");
907 PvlToXmlTranslationManager::setElementValue(nullElement, QString::number(NULL4, 'g', 18));
908 specialConstantElement.appendChild(nullElement);
909
910 QDomElement highInstrumentSatElement = m_domDoc->createElement("high_instrument_saturation");
911 PvlToXmlTranslationManager::setElementValue(highInstrumentSatElement, QString::number(HIGH_INSTR_SAT4, 'g', 18));
912 specialConstantElement.appendChild(highInstrumentSatElement);
913
914 QDomElement highRepresentationSatElement = m_domDoc->createElement("high_representation_saturation");
915 PvlToXmlTranslationManager::setElementValue(highRepresentationSatElement, QString::number(HIGH_REPR_SAT4, 'g', 18));
916 specialConstantElement.appendChild(highRepresentationSatElement);
917
918 QDomElement lowInstrumentSatElement = m_domDoc->createElement("low_instrument_saturation");
919 PvlToXmlTranslationManager::setElementValue(lowInstrumentSatElement, QString::number(LOW_INSTR_SAT4, 'g', 18));
920 specialConstantElement.appendChild(lowInstrumentSatElement);
921
922 QDomElement lowRepresentationSatElement = m_domDoc->createElement("low_representation_saturation");
923 PvlToXmlTranslationManager::setElementValue(lowRepresentationSatElement, QString::number(LOW_REPR_SAT4, 'g', 18));
924 specialConstantElement.appendChild(lowRepresentationSatElement);
925 break;}
926
927 case UnsignedByte:
928 { QDomElement nullElement = m_domDoc->createElement("missing_constant");
929 PvlToXmlTranslationManager::setElementValue(nullElement, QString::number(NULL1, 'g', 18));
930 specialConstantElement.appendChild(nullElement);
931
932 QDomElement highInstrumentSatElement = m_domDoc->createElement("high_instrument_saturation");
933 PvlToXmlTranslationManager::setElementValue(highInstrumentSatElement, QString::number(HIGH_INSTR_SAT1, 'g', 18));
934 specialConstantElement.appendChild(highInstrumentSatElement);
935
936 QDomElement highRepresentationSatElement = m_domDoc->createElement("high_representation_saturation");
937 PvlToXmlTranslationManager::setElementValue(highRepresentationSatElement, QString::number(HIGH_REPR_SAT1, 'g', 18));
938 specialConstantElement.appendChild(highRepresentationSatElement);
939
940 QDomElement lowInstrumentSatElement = m_domDoc->createElement("low_instrument_saturation");
941 PvlToXmlTranslationManager::setElementValue(lowInstrumentSatElement, QString::number(LOW_INSTR_SAT1, 'g', 18));
942 specialConstantElement.appendChild(lowInstrumentSatElement);
943
944 QDomElement lowRepresentationSatElement = m_domDoc->createElement("low_representation_saturation");
945 PvlToXmlTranslationManager::setElementValue(lowRepresentationSatElement, QString::number(LOW_REPR_SAT1, 'g', 18));
946 specialConstantElement.appendChild(lowRepresentationSatElement);
947 break; }
948
949 case SignedWord:
950 { QDomElement nullElement = m_domDoc->createElement("missing_constant");
951 PvlToXmlTranslationManager::setElementValue(nullElement, QString::number(NULL2, 'g', 18));
952 specialConstantElement.appendChild(nullElement);
953
954 QDomElement highInstrumentSatElement = m_domDoc->createElement("high_instrument_saturation");
955 PvlToXmlTranslationManager::setElementValue(highInstrumentSatElement, QString::number(HIGH_INSTR_SAT2, 'g', 18));
956 specialConstantElement.appendChild(highInstrumentSatElement);
957
958 QDomElement highRepresentationSatElement = m_domDoc->createElement("high_representation_saturation");
959 PvlToXmlTranslationManager::setElementValue(highRepresentationSatElement, QString::number(HIGH_REPR_SAT2, 'g', 18));
960 specialConstantElement.appendChild(highRepresentationSatElement);
961
962 QDomElement lowInstrumentSatElement = m_domDoc->createElement("low_instrument_saturation");
963 PvlToXmlTranslationManager::setElementValue(lowInstrumentSatElement, QString::number(LOW_INSTR_SAT2, 'g', 18));
964 specialConstantElement.appendChild(lowInstrumentSatElement);
965
966 QDomElement lowRepresentationSatElement = m_domDoc->createElement("low_representation_saturation");
967 PvlToXmlTranslationManager::setElementValue(lowRepresentationSatElement, QString::number(LOW_REPR_SAT2, 'g', 18));
968 specialConstantElement.appendChild(lowRepresentationSatElement);
969 break; }
970
971 case UnsignedWord:
972 { QDomElement nullElement = m_domDoc->createElement("missing_constant");
973 PvlToXmlTranslationManager::setElementValue(nullElement, QString::number(NULLU2, 'g', 18));
974 specialConstantElement.appendChild(nullElement);
975
976 QDomElement highInstrumentSatElement = m_domDoc->createElement("high_instrument_saturation");
977 PvlToXmlTranslationManager::setElementValue(highInstrumentSatElement, QString::number(HIGH_INSTR_SATU2, 'g', 18));
978 specialConstantElement.appendChild(highInstrumentSatElement);
979
980 QDomElement highRepresentationSatElement = m_domDoc->createElement("high_representation_saturation");
981 PvlToXmlTranslationManager::setElementValue(highRepresentationSatElement, QString::number(HIGH_REPR_SATU2, 'g', 18));
982 specialConstantElement.appendChild(highRepresentationSatElement);
983
984 QDomElement lowInstrumentSatElement = m_domDoc->createElement("low_instrument_saturation");
985 PvlToXmlTranslationManager::setElementValue(lowInstrumentSatElement, QString::number(LOW_INSTR_SATU2, 'g', 18));
986 specialConstantElement.appendChild(lowInstrumentSatElement);
987
988 QDomElement lowRepresentationSatElement = m_domDoc->createElement("low_representation_saturation");
989 PvlToXmlTranslationManager::setElementValue(lowRepresentationSatElement, QString::number(LOW_REPR_SATU2, 'g', 18));
990 specialConstantElement.appendChild(lowRepresentationSatElement);
991 break; }
992
993 case None:
994 break;
995
996 default:
997 break;
998 }
999
1000
1001
1002 if (!m_pixelDescription.isEmpty()) {
1003 QDomElement descriptionElement = m_domDoc->createElement("description");
1006 arrayImageElement.insertAfter(descriptionElement, arrayImageElement.lastChildElement());
1007 }
1008 }
1009 }
1010
1011
1020 void ProcessExportPds4::addSchema(QString xsd, QString xmlns, QString xmlnsURI) {
1021 // Add xmlns
1022 QDomElement root = m_domDoc->documentElement();
1023 root.setAttribute(xmlns, xmlnsURI);
1024
1025 // Add to xsi:schemaLocation
1026 m_schemaLocation += " ";
1027 m_schemaLocation += xmlnsURI;
1028 m_schemaLocation += " ";
1029 m_schemaLocation += xmlnsURI;
1030 m_schemaLocation += "/";
1031 m_schemaLocation += xsd;
1032 root.setAttribute("xsi:schemaLocation", m_schemaLocation);
1033 }
1034
1035
1044 void ProcessExportPds4::addSchema(QString sch, QString xsd, QString xmlns, QString xmlnsURI) {
1045 // Add xml-model
1046 QString xmlModel;
1047 xmlModel += "href=\"";
1048 xmlModel += xmlnsURI;
1049 xmlModel += "/";
1050 xmlModel += sch;
1051 xmlModel += "\" schematypens=\"http://purl.oclc.org/dsdl/schematron\"";
1052 QDomProcessingInstruction header =
1053 m_domDoc->createProcessingInstruction("xml-model", xmlModel);
1054 m_domDoc->insertAfter(header, m_domDoc->firstChild());
1055
1056 // Add xmlns
1057 addSchema(xsd, xmlns, xmlnsURI);
1058 }
1059
1060
1066 void ProcessExportPds4::OutputLabel(std::ofstream &os) {
1067 os << m_domDoc->toString() << endl;
1068 }
1069
1070
1078 void ProcessExportPds4::StartProcess(std::ofstream &fout) {
1080 }
1081
1082
1090 if (m_domDoc->documentElement().isNull()) {
1091 QDomElement root = m_domDoc->createElement("Product_Observational");
1092 root.setAttribute("xmlns", "http://pds.nasa.gov/pds4/pds/v1");
1093 root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
1094 root.setAttribute("xsi:schemaLocation",
1095 "http://pds.nasa.gov/pds4/pds/v1 http://pds.nasa.gov/pds4/pds/v1");
1096 m_domDoc->appendChild(root);
1097 }
1098 return *m_domDoc;
1099 }
1100
1101
1110 void ProcessExportPds4::WritePds4(QString outFile) {
1111
1112 FileName outputFile(outFile);
1113
1114 // Name for output label
1115 QString path(outputFile.originalPath());
1116 QString name(outputFile.baseName());
1117 QString labelName = path + "/" + name + ".xml";
1118
1119 // Name for output image
1120 QString imageName = outputFile.expanded();
1121
1122 // If input file ends in .xml, the user entered a label name for the output file, not an
1123 // image name with a unique file extension.
1124 if (QString::compare(outputFile.extension(), "xml", Qt::CaseInsensitive) == 0) {
1125 imageName = path + "/" + name + ".img";
1126 }
1127
1128 QDomElement rootElement = m_domDoc->documentElement();
1129 QDomElement fileAreaObservationalElement =
1130 rootElement.firstChildElement("File_Area_Observational");
1131
1132 QDomElement fileElement = m_domDoc->createElement("File");
1133 fileAreaObservationalElement.insertBefore(fileElement,
1134 fileAreaObservationalElement.firstChildElement());
1135
1136 QDomElement fileNameElement = m_domDoc->createElement("file_name");
1137 PvlToXmlTranslationManager::setElementValue(fileNameElement, outputFile.name());
1138 fileElement.appendChild(fileNameElement);
1139
1140// QDomElement creationElement = m_domDoc->createElement("creation_date_time");
1141// PvlToXmlTranslationManager::setElementValue(creationElement, );
1142// fileElement.appendChild(creationElement);
1143
1144 ofstream outputLabel(labelName.toLatin1().data());
1145 OutputLabel(outputLabel);
1146 outputLabel.close();
1147
1148 ofstream outputImageFile(imageName.toLatin1().data());
1149 StartProcess(outputImageFile);
1150 outputImageFile.close();
1151
1152 EndProcess();
1153 }
1154
1155
1165 // Cartography
1166 // Get the input Isis cube label and find the Mapping group if it has one
1167 Pvl *inputLabel = InputCubes[0]->label();
1168 if(inputLabel->hasObject("IsisCube") &&
1169 !(inputLabel->findObject("IsisCube").hasGroup("Mapping"))) return;
1170 PvlGroup &inputMapping = inputLabel->findGroup("Mapping", Pvl::Traverse);
1171
1172 addSchema("PDS4_CART_1900.sch",
1173 "PDS4_CART_1900.xsd",
1174 "xmlns:cart",
1175 "http://pds.nasa.gov/pds4/cart/v1");
1176
1177 // Translate the projection specific keywords for a PDS IMAGE_MAP_PROJECTION
1178 Projection *proj = ProjectionFactory::Create(*inputLabel);
1179 QString projName = proj->Name();
1180 try {
1181 PvlToXmlTranslationManager xlatorSpecProj(*inputLabel,
1182 "$ISISROOT/appdata/translations/pds4Export" + projName + ".trn");
1183 xlatorSpecProj.Auto(*m_domDoc);
1184 }
1185 catch (IException &e) {
1186 QString msg = "Unable to export projection [" + projName + "] to PDS4 product. " +
1187 "This projection is not supported in ISIS3.";
1188 throw IException(e, IException::User, msg, _FILEINFO_);
1189 }
1190
1191 // convert units.
1192 QStringList xmlPath;
1193 xmlPath << "Product_Observational"
1194 << "Observation_Area"
1195 << "Discipline_Area"
1196 << "cart:Cartography"
1197 << "cart:Map_Projection"
1198 << "cart:Spatial_Reference_Information"
1199 << "cart:Horizontal_Coordinate_System_Definition"
1200 << "cart:Geodetic_Model";
1201
1202 QDomElement baseElement = m_domDoc->documentElement();
1203 QDomElement geodeticModelElement = getElement(xmlPath, baseElement);
1204 QDomElement semiMajorRadElement = geodeticModelElement.firstChildElement("cart:semi_major_radius");
1205 if (!semiMajorRadElement.isNull()) {
1206
1207 QString units = semiMajorRadElement.attribute("unit");
1208 if( units.compare("km", Qt::CaseInsensitive) != 0 && units.compare("kilometers", Qt::CaseInsensitive) != 0) {
1209
1210 //if no units, assume in meters
1211 double dValue = toDouble(semiMajorRadElement.text());
1212 dValue /= 1000.0;
1213 PvlToXmlTranslationManager::resetElementValue(semiMajorRadElement, toString(dValue), "km");
1214 }
1215 }
1216
1217 QDomElement semiMinorRadElement = geodeticModelElement.firstChildElement("cart:semi_minor_radius");
1218 if (!semiMinorRadElement.isNull()) {
1219
1220 QString units = semiMinorRadElement.attribute("unit");
1221 if( units.compare("km", Qt::CaseInsensitive) != 0 && units.compare("kilometers", Qt::CaseInsensitive) != 0) {
1222 // If no units, assume in meters
1223 double dValue = toDouble(semiMinorRadElement.text());
1224 dValue /= 1000.0;
1225 PvlToXmlTranslationManager::resetElementValue(semiMinorRadElement, toString(dValue), "km");
1226 }
1227 }
1228
1229 QDomElement polarRadElement = geodeticModelElement.firstChildElement("cart:polar_radius");
1230 if (!polarRadElement.isNull()) {
1231 QString units = polarRadElement.attribute("unit");
1232 if( units.compare("km", Qt::CaseInsensitive) != 0 && units.compare("kilometers", Qt::CaseInsensitive) != 0) {
1233 // If no units, assume in meters
1234 double dValue = toDouble(polarRadElement.text());
1235 dValue /= 1000.0;
1236 PvlToXmlTranslationManager::resetElementValue(polarRadElement, toString(dValue), "km");
1237 }
1238 }
1239
1240 PvlKeyword &isisLonDir = inputMapping.findKeyword("LongitudeDirection");
1241 QString lonDir = isisLonDir[0];
1242 lonDir = lonDir.toUpper();
1243
1244 // Add Lat/Lon range
1245 double maxLon, minLon, maxLat, minLat;
1246 InputCubes[0]->latLonRange(minLat, maxLat, minLon, maxLon);
1247
1248 xmlPath.clear();
1249 xmlPath << "Product_Observational"
1250 << "Observation_Area"
1251 << "Discipline_Area"
1252 << "cart:Cartography"
1253 << "cart:Spatial_Domain"
1254 << "cart:Bounding_Coordinates";
1255 QDomElement boundingCoordElement = getElement(xmlPath, baseElement);
1256 QDomElement eastElement = boundingCoordElement.firstChildElement("cart:east_bounding_coordinate");
1257 QDomElement westElement = boundingCoordElement.firstChildElement("cart:west_bounding_coordinate");
1258 QDomElement northElement = boundingCoordElement.firstChildElement("cart:north_bounding_coordinate");
1259 QDomElement southElement = boundingCoordElement.firstChildElement("cart:south_bounding_coordinate");
1260
1261 // Translation files currently handles Positive West case where east = min, west = max
1262 // so if positive east, swap min/max
1263 if(QString::compare(lonDir, "PositiveEast", Qt::CaseInsensitive) == 0) {
1264 // west min, east max
1265 PvlToXmlTranslationManager::resetElementValue(eastElement, toString(maxLon), "deg");
1266 PvlToXmlTranslationManager::resetElementValue(westElement, toString(minLon), "deg");
1267 }
1268 else {
1269 PvlToXmlTranslationManager::resetElementValue(eastElement, toString(minLon), "deg");
1270 PvlToXmlTranslationManager::resetElementValue(westElement, toString(maxLon), "deg");
1271 }
1272
1273 PvlToXmlTranslationManager::resetElementValue(northElement, toString(maxLat), "deg");
1274 PvlToXmlTranslationManager::resetElementValue(southElement, toString(minLat), "deg");
1275
1276 // longitude_of_central_meridian and latitude_of_projection_origin need to be converted to floats.
1277 xmlPath.clear();
1278 xmlPath << "Product_Observational"
1279 << "Observation_Area"
1280 << "Discipline_Area"
1281 << "cart:Cartography"
1282 << "cart:Spatial_Reference_Information"
1283 << "cart:Horizontal_Coordinate_System_Definition"
1284 << "cart:Planar"
1285 << "cart:Map_Projection";
1286
1287 // The following is necessary because the full xmlPath differs depending on the projection used.
1288 QDomElement projectionElement = getElement(xmlPath, baseElement);
1289 QDomElement tempElement = projectionElement.firstChildElement();
1290 QDomElement nameElement = tempElement.nextSiblingElement();
1291
1292 QDomElement longitudeElement = nameElement.firstChildElement("cart:longitude_of_central_meridian");
1293 QDomElement originElement = nameElement.firstChildElement("cart:latitude_of_projection_origin");
1294
1295 double longitudeElementValue = longitudeElement.text().toDouble();
1296 double originElementValue = originElement.text().toDouble();
1297
1298 // Only update the ouput formatting if there are no digits after the decimal point.
1299 if (!longitudeElement.text().contains('.')) {
1300 QString toset1 = QString::number(longitudeElementValue, 'f', 1);
1301 PvlToXmlTranslationManager::resetElementValue(longitudeElement, toset1, "deg");
1302 }
1303
1304 if (!originElement.text().contains('.')) {
1305 QString toset2 = QString::number(originElementValue, 'f', 1);
1306 PvlToXmlTranslationManager::resetElementValue(originElement, toset2, "deg");
1307 }
1308 }
1309
1310
1327 QDomElement ProcessExportPds4::getElement(QStringList xmlPath, QDomElement parent) {
1328 QDomElement baseElement = parent;
1329 if (baseElement.isNull()) {
1330 baseElement = m_domDoc->documentElement();
1331 }
1332 if (baseElement.isNull()) {
1333 QString msg = "Unable to get element from empty XML document.";
1334 throw IException(IException::Programmer, msg, _FILEINFO_);
1335 }
1336 QString parentName = xmlPath[0];
1337 if (parentName != baseElement.tagName()) {
1338 QString msg = "The tag name of the parent element passed in "
1339 "must be the first value in the given XML path.";
1340 throw IException(IException::Programmer, msg, _FILEINFO_);
1341 }
1342 for (int i = 1; i < xmlPath.size(); i++) {
1343 QString elementName = xmlPath[i];
1344 QDomElement nextElement = baseElement.firstChildElement(elementName);
1345 baseElement = nextElement;
1346 }
1347 return baseElement;
1348 }
1349
1350
1360 QString pds4Type("UNK");
1361 if(p_pixelType == Isis::UnsignedByte) {
1362 pds4Type = "UnsignedByte";
1363 }
1364 else if((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Msb)) {
1365 pds4Type = "UnsignedMSB2";
1366 }
1367 else if((p_pixelType == Isis::UnsignedWord) && (p_endianType == Isis::Lsb)) {
1368 pds4Type = "UnsignedLSB2";
1369 }
1370 else if((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Msb)) {
1371 pds4Type = "SignedMSB2";
1372 }
1373 else if((p_pixelType == Isis::SignedWord) && (p_endianType == Isis::Lsb)) {
1374 pds4Type = "SignedLSB2";
1375 }
1376 else if((p_pixelType == Isis::Real) && (p_endianType == Isis::Msb)) {
1377 pds4Type = "IEEE754MSBSingle";
1378 }
1379 else if((p_pixelType == Isis::Real) && (p_endianType == Isis::Lsb)) {
1380 pds4Type = "IEEE754LSBSingle";
1381 }
1382 else {
1383 QString msg = "Unsupported PDS pixel type or sample size";
1384 throw IException(IException::User, msg, _FILEINFO_);
1385 }
1386 return pds4Type;
1387 }
1388
1389
1399 void ProcessExportPds4::addHistory(QString description, QString date, QString version) {
1400 // Check that at least the "Identification_Area" element exists.
1401 QDomElement identificationElement;
1402 QStringList identificationPath;
1403 identificationPath.append("Product_Observational");
1404 identificationPath.append("Identification_Area");
1405 try {
1406 identificationElement = getElement(identificationPath);
1407 if( identificationElement.isNull() ) {
1408 throw IException(IException::Unknown, "", _FILEINFO_);
1409 }
1410 }
1411 catch(IException &e) {
1412 QString msg = "Could not find Identification_Area element "
1413 "to add modification history under.";
1414 throw IException(IException::Programmer, msg, _FILEINFO_);
1415 }
1416
1417 // Check if the "Modification_History" element exists yet.
1418 // If not, create one.
1419 QDomElement historyElement = identificationElement.firstChildElement("Modification_History");
1420 if ( historyElement.isNull() ) {
1421 historyElement = m_domDoc->createElement("Modification_History");
1422 identificationElement.insertAfter( historyElement,
1423 identificationElement.lastChildElement() );
1424 }
1425
1426 // Create the "Modification_Detail" element and add it to the end of the
1427 // "Modification_History" element.
1428 QDomElement detailElement = m_domDoc->createElement("Modification_Detail");
1429
1430 QDomElement modDateElement = m_domDoc->createElement("modification_date");
1431 PvlToXmlTranslationManager::setElementValue(modDateElement, date);
1432 detailElement.appendChild(modDateElement);
1433
1434 QDomElement versionIdElement = m_domDoc->createElement("version_id");
1435 PvlToXmlTranslationManager::setElementValue(versionIdElement, version);
1436 detailElement.appendChild(versionIdElement);
1437
1438 QDomElement descriptionElement = m_domDoc->createElement("description");
1439 PvlToXmlTranslationManager::setElementValue(descriptionElement, description);
1440 detailElement.appendChild(descriptionElement);
1441
1442 historyElement.insertAfter( detailElement,
1443 historyElement.lastChildElement() );
1444 }
1445
1446
1464 void ProcessExportPds4::translateUnits(QDomDocument &label, QString transMapFile) {
1465 Pvl configPvl;
1466 try {
1467 configPvl.read(transMapFile);
1468 }
1469 catch(IException &e) {
1470 QString msg = "Failed to read unit translation config file [" + transMapFile + "].";
1471 throw IException(e, IException::Io, msg, _FILEINFO_);
1472 }
1473
1474 QMap<QString, QString> transMap;
1475 try {
1476 transMap = createUnitMap(configPvl);
1477 }
1478 catch(IException &e) {
1479 QString msg = "Failed to load unit translation config file [" + transMapFile + "].";
1480 throw IException(e, IException::Unknown, msg, _FILEINFO_);
1481 }
1482
1483 // Now that the map is filled, recursively search through the XML document
1484 // for units and translate them.
1485 try {
1486 translateChildUnits( label.documentElement(), transMap );
1487 }
1488 catch(IException &e) {
1489 QString msg = "Failed to translate units with config file [" + transMapFile + "].";
1490 throw IException(e, IException::Unknown, msg, _FILEINFO_);
1491 }
1492 }
1493
1494
1505 QMap<QString, QString> ProcessExportPds4::createUnitMap(Pvl configPvl) {
1506 QMap<QString, QString> transMap;
1507 for (int i = 0; i < configPvl.objects(); i++) {
1508 PvlObject unitObject = configPvl.object(i);
1509 for (int j = 0; j < unitObject.groups(); j++) {
1510 PvlGroup unitGroup = unitObject.group(j);
1511 if (!unitGroup.hasKeyword("PDS4_Unit")) {
1512 QString msg = "No PDS4 standard specified for for [" + unitGroup.name() + "]";
1513 throw IException(IException::Programmer, msg, _FILEINFO_);
1514 }
1515 PvlKeyword pds4Key = unitGroup["PDS4_Unit"];
1516 // Add the PDS4 format for when the format is already correct.
1517 // This also handles case issues such as KM instead of km.
1518 transMap.insert(pds4Key[0].toLower(), pds4Key[0]);
1519
1520 // If there are ISIS versions with different formats then add those.
1521 if (unitGroup.hasKeyword("ISIS_Units")) {
1522 PvlKeyword isisKey = unitGroup["ISIS_Units"];
1523 for (int k = 0; k < isisKey.size() ; k++) {
1524 transMap.insert(isisKey[k].toLower(), pds4Key[0]);
1525 }
1526 }
1527 }
1528 }
1529 return transMap;
1530 }
1531
1532
1545 void ProcessExportPds4::translateChildUnits(QDomElement parent, QMap<QString, QString> transMap) {
1546 QDomElement childElement = parent.firstChildElement();
1547
1548 while( !childElement.isNull() ) {
1549 if ( childElement.hasAttribute("unit") ) {
1550 QString originalUnit = childElement.attribute("unit");
1551 if ( transMap.contains( originalUnit.toLower() ) ) {
1552 childElement.setAttribute("unit", transMap.value( originalUnit.toLower() ) );
1553 }
1554 else {
1555 QString msg = "Could not translate unit [" + originalUnit + "] to PDS4 format.";
1556 throw IException(IException::Unknown, msg, _FILEINFO_);
1557 }
1558 }
1559 translateChildUnits(childElement, transMap);
1560 childElement = childElement.nextSiblingElement();
1561 }
1562
1563 // Base case: If there are no more children end return
1564 return;
1565 }
1566
1567
1568} // End of Isis namespace
static QString DateTime(time_t *curtime=0)
Returns the date and time as a QString.
static QString Version()
The Isis Version for this application.
static QString Name()
Returns the name of the application.
File name manipulation and expansion.
Definition FileName.h:100
QString baseName() const
Returns the name of the file without the path and without extensions.
Definition FileName.cpp:145
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition IException.h:155
double p_outputMinimum
Desired minimum pixel value in the Buffer.
double p_outputMaximum
Desired maximum pixel value in the Buffer.
std::vector< double > p_inputMaximum
Maximum pixel value in the input cube to be mapped to the maximum value in the Buffer.
virtual void StartProcess(void funct(Isis::Buffer &in))
This method invokes the process operation over a single input cube.
PixelType p_pixelType
The bits per pixel of the output image.
ByteOrder p_endianType
The byte order of the output file.
std::vector< double > p_inputMinimum
Minimum pixel value in the input cube to be mapped to the minimum value in the Buffer.
void StartProcess(std::ofstream &fout)
This method fills the image data of the PDS4 file using the parent class ProcessExport::StartProcess.
void setVersionId(QString versionId)
Allows mission specific programs to set version_id required for PDS4 labels.
void setImageType(ImageType imageType)
Create a standard PDS4 image label from the input cube.
void setLogicalId(QString lid)
Allows mission specific programs to set logical_identifier required for PDS4 labels.
QDomDocument * m_domDoc
XML label.
QString m_versionId
QString with specified version id.
void identificationArea()
This method writes the identification information to the PDS4 labels.
void translateBandBinSpectrumUniform(Pvl &inputLabel)
Export BandBin group for uniformly spaced 3D Spectral data format.
ProcessExportPds4()
Default Constructor - Set to default the data members.
QDomDocument & GetLabel()
Return the internalized PDS4 label.
void translateBandBinSpectrumBinSet(Pvl &inputLabel)
Export BandBin group for non-uniformly spaced 3D Spectral data format.
static void translateChildUnits(QDomElement parent, QMap< QString, QString > transMap)
Recursive method that will translate the "unit" attribute of any child elements of a given element.
void addHistory(QString description, QString date="tbd", QString version="1.0")
Add a modification history instance by adding a Modification_Detail entry to the Modification_History...
QDomElement getElement(QStringList xmlPath, QDomElement parent=QDomElement())
Convenience method to get an element given a path and its parent.
QString m_schemaLocation
QString with all schema locations required.
void setTitle(QString title)
Allows mission specific programs to set the title required for PDS4 labels.
void reorder()
This method reorders the existing m_domDoc to follow PDS4 standards and fixes time formatting if need...
void setSchemaLocation(QString schema)
Allows mission specific programs to use specified versions of dictionaries.
QString m_lid
QString with specified logical identifier.
static void translateUnits(QDomDocument &label, QString transMapFile="$ISISROOT/appdata/translations/pds4ExportUnits.pvl")
This function will go through an XML document and attempt to convert all "units" attributes to the ap...
ImageType m_imageType
Type of image data to be written.
void standardBandBin()
Export bandbin group to sp:Spectral Characteristics.
void addSchema(QString sch, QString xsd, QString xmlns, QString xmlnsURI)
Adds necessary information to the xml header for a pds4 class.
void translateBandBinImage(Pvl &inputLabel)
Export BandBin group for 2D or 3D Image format.
void fileAreaObservational()
Create and internalize an image output label from the input image.
QString m_title
QString with specified title.
void StandardAllMapping()
Create the standard keywords for the IMAGE_MAP_PROJECTION group in a PDS label.
void standardInstrument()
This method translates the information from the ISIS Instrument group to the PDS4 labels.
void setPixelDescription(QString description)
Sets the description string which describes the pixel vales in File_Area_Observational.
QString PDS4PixelType(PixelType pixelType, ByteOrder endianType)
Helper function for converting ISIS pixel type and byte order to a PDS4 data_type value.
QDomDocument & StandardPds4Label()
Create a standard PDS4 image label from the input cube.
QString m_pixelDescription
Description of pixel values.
void CreateImageLabel()
Creates a PDS4 label.
void displaySettings()
This method writes the display direction information to the PDS4 labels.
static QMap< QString, QString > createUnitMap(Pvl configPvl)
Helper function for creating the unit translation map from a PVL object.
void OutputLabel(std::ofstream &os)
Write the XML label to the supplied stream.
void WritePds4(QString outFile)
This method write out the labels and image data to the specified output file.
virtual void EndProcess()
End the processing sequence and cleans up by closing cubes, freeing memory, etc.
Definition Process.cpp:462
std::vector< Isis::Cube * > InputCubes
A vector of pointers to opened Cube objects.
Definition Process.h:185
static Isis::Projection * Create(Isis::Pvl &label, bool allowDefaults=false)
This method returns a pointer to a Projection object.
Base class for Map Projections.
Definition Projection.h:155
QString name() const
Returns the container name.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
void read(const QString &file)
Loads PVL information from a stream.
Definition Pvl.cpp:90
A single keyword-value pair.
Definition PvlKeyword.h:87
int size() const
Returns the number of values stored in this keyword.
Definition PvlKeyword.h:133
QString unit(const int index=0) const
Returns the units of measurement of the element of the array of values for the object at the specifie...
void clear()
Clears all values and units for this PvlKeyword object.
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition PvlObject.h:276
PvlObject & object(const int index)
Return the object at the specified index.
@ Traverse
Search child objects.
Definition PvlObject.h:158
Allows applications to translate simple text files.
static void resetElementValue(QDomElement &element, QString value, QString units="")
Reset the QDomElement's value, and units, if units != "".
static void setElementValue(QDomElement &element, QString value, QString units="")
Set the QDomElement's value, and units, if units != "".
ByteOrder
Tests the current architecture for byte order.
Definition Endian.h:42
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition IString.cpp:149
PixelType
Enumerations for Isis Pixel Types.
Definition PixelType.h:27
Namespace for the standard library.