Official websites use .gov
A .gov website belongs to an official government organization in the United States.

Secure .gov websites use HTTPS
A lock ( ) or https:// means you’ve safely connected to the .gov website. Share sensitive information only on official, secure websites.

Isis 3 Programmer Reference
Image.cpp
1#include "Image.h"
2
3#include <QBuffer>
4#include <QDataStream>
5#include <QDebug>
6#include <QDir>
7#include <QFileInfo>
8#include <QMutexLocker>
9#include <QRegularExpression>
10#include <QScopedPointer>
11#include <QString>
12#include <QUuid>
13#include <QXmlStreamWriter>
14
15#include <geos/geom/MultiPolygon.h>
16#include <geos/io/WKTReader.h>
17#include <geos/io/WKTWriter.h>
18
19#include "Angle.h"
20#include "Cube.h"
21#include "CubeAttribute.h"
22#include "DisplayProperties.h"
23#include "Distance.h"
24#include "FileName.h"
26#include "ImagePolygon.h"
27#include "IString.h"
28#include "ObservationNumber.h"
29#include "PolygonTools.h"
30#include "Project.h"
31#include "SerialNumber.h"
32#include "Target.h"
33
34namespace Isis {
35
41 Image::Image(QString imageFileName, QObject *parent) : QObject(parent) {
42 m_bodyCode = NULL;
43 m_cube = NULL;
45 m_footprint = NULL;
46 m_id = NULL;
47
48 m_aspectRatio = Null;
49 m_resolution = Null;
50 m_lineResolution = Null;
51 m_sampleResolution = Null;
52
53 m_fileName = imageFileName;
54
55 cube();
56
58
59 try {
61 }
62 catch (IException &) {
63 }
64
65 m_displayProperties = new ImageDisplayProperties(FileName(m_fileName).name(), this);
66
67 m_id = new QUuid(QUuid::createUuid());
68 }
69
70
76 Image::Image(Cube *imageCube, QObject *parent) : QObject(parent) {
77 m_fileName = imageCube->fileName();
78
79 m_bodyCode = NULL;
80 m_cube = imageCube;
82 m_footprint = NULL;
83 m_id = NULL;
84
85 m_aspectRatio = Null;
86 m_resolution = Null;
87 m_lineResolution = Null;
88 m_sampleResolution = Null;
89
91
92 try {
94 }
95 catch (IException &e) {
96 }
97
98 m_displayProperties = new ImageDisplayProperties(FileName(m_fileName).name(), this);
99
100 m_id = new QUuid(QUuid::createUuid());
101 }
102
103
110 Image::Image(Cube *imageCube, geos::geom::MultiPolygon *footprint, QString id, QObject *parent) :
111 QObject(parent) {
112 m_fileName = imageCube->fileName();
113
114 m_bodyCode = NULL;
115 m_cube = imageCube;
116 m_displayProperties = NULL;
117 m_id = NULL;
118
119 m_aspectRatio = Null;
120 m_resolution = Null;
121 m_lineResolution = Null;
122 m_sampleResolution = Null;
123
124 initCamStats();
125
127
128 m_displayProperties = new ImageDisplayProperties(FileName(m_fileName).name(), this);
129
130 setId(id);
131 }
132
133
138 delete m_bodyCode;
139 m_bodyCode = NULL;
140
141 delete m_cube;
142 m_cube = NULL;
143
144 delete m_footprint;
145 m_footprint = NULL;
146
147 delete m_id;
148 m_id = NULL;
149
150 // Image is a "Qt" parent of display properties, so the Image QObject
151 // destructor will take care of deleting the display props. See call to
152 // DisplayProperties' constructor.
153 m_displayProperties = NULL;
154 }
155
156
170 void Image::fromPvl(const PvlObject &pvl) {
171 QString pvlFileName = ((IString)pvl["FileName"][0]).ToQt();
172 if (m_fileName != pvlFileName) {
173 throw IException(IException::Unknown,
174 tr("Tried to load Image [%1] with properties/information from [%2].")
175 .arg(m_fileName).arg(pvlFileName),
176 _FILEINFO_);
177 }
178
179 displayProperties()->fromPvl(pvl.findObject("DisplayProperties"));
180
181 if (pvl.hasKeyword("ID")) {
182 QByteArray hexValues(pvl["ID"][0].toLatin1());
183 QDataStream valuesStream(QByteArray::fromHex(hexValues));
184 valuesStream >> *m_id;
185 }
186 }
187
188
202 PvlObject Image::toPvl() const {
203 PvlObject output("Image");
204
205 output += PvlKeyword("FileName", m_fileName);
206
207 // Do m_id
208 QBuffer dataBuffer;
209 dataBuffer.open(QIODevice::ReadWrite);
210
211 QDataStream idStream(&dataBuffer);
212 idStream << *m_id;
213
214 dataBuffer.seek(0);
215
216 output += PvlKeyword("ID", QString(dataBuffer.data().toHex()));
217
218 output += displayProperties()->toPvl();
219
220 return output;
221 }
222
223
230 bool result = false;
231
232 if (m_footprint) {
233 result = true;
234 }
235
236 if (!result && m_cube) {
237 Blob example = ImagePolygon().toBlob();
238
239 QString blobType = example.Type();
240 QString blobName = example.Name();
241
242 Pvl &labels = *m_cube->label();
243
244 for (int i = 0; i < labels.objects(); i++) {
245 PvlObject &obj = labels.object(i);
246
247 if (obj.isNamed(blobType) && obj.hasKeyword("Name") && obj["Name"][0] == blobName)
248 result = true;
249 }
250 }
251
252 return result;
253 }
254
255
264 if (!m_cube) {
265 try {
266 m_cube = new Cube(m_fileName);
267 }
268 catch (IException &e) {
269 throw IException(e, IException::Programmer, "Cube cannot be created", _FILEINFO_);
270 }
271 }
272
273 return m_cube;
274 }
275
276
284 if (m_cube) {
285 delete m_cube;
286 m_cube = NULL;
287 }
288 }
289
290
299
300
310
311
316 QString Image::fileName() const {
317 return m_fileName;
318 }
319
320
326 if (m_observationNumber.isEmpty()) {
328 }
329 return m_observationNumber;
330 }
331
332
338 if (m_serialNumber.isEmpty()) {
340 }
341 return m_serialNumber;
342 }
343
344
350 geos::geom::MultiPolygon *Image::footprint() {
351 return m_footprint;
352 }
353
354
359 void Image::setId(QString id) {
360 m_id = new QUuid(id);
361 }
362
363
369 const geos::geom::MultiPolygon *Image::footprint() const {
370 return m_footprint;
371 }
372
373
385 bool Image::initFootprint(QMutex *cameraMutex) {
386 if (!m_footprint) {
387 try {
389 }
390 catch (IException &e) {
391 try {
392 m_footprint = createFootprint(cameraMutex);
393 }
394 catch (IException &e) {
395 IString msg = "Could not read the footprint from cube [" +
396 displayProperties()->displayName() + "]. Please make "
397 "sure footprintinit has been run";
398 throw IException(e, IException::Io, msg, _FILEINFO_);
399 }
400 }
401 }
402
403 // I'm not sure how this could ever be NULL. -SL
404 return (m_footprint != NULL);
405 }
406
407
412 double Image::aspectRatio() const {
413 return m_aspectRatio;
414 }
415
416
421 QString Image::id() const {
422 return m_id->toString().remove(QRegularExpression("[{}]"));
423 }
424
425
431 double Image::resolution() const {
432 return m_resolution;
433 }
434
435
442 return m_emissionAngle;
443 }
444
445
452 return m_incidenceAngle;
453 }
454
455
461 double Image::lineResolution() const {
462 return m_lineResolution;
463 }
464
465
472 return m_localRadius;
473 }
474
475
482 return m_northAzimuth;
483 }
484
485
492 return m_phaseAngle;
493 }
494
495
501 double Image::sampleResolution() const {
502 return m_sampleResolution;
503 }
504
505
510 void Image::copyToNewProjectRoot(const Project *project, FileName newProjectRoot) {
511 if (FileName(newProjectRoot) != FileName(project->projectRoot())) {
512 Cube origImage(m_fileName);
513
514 // The imageDataRoot will either be PROJECTROOT/images or PROJECTROOT/results/bundle/timestamp/images,
515 // depending on how the newProjectRoot points to.
516 FileName newExternalLabelFileName(Project::imageDataRoot(newProjectRoot.toString()) + "/" +
517 FileName(m_fileName).dir().dirName() + "/" + FileName(m_fileName).name());
518
519 if (m_fileName != newExternalLabelFileName.toString()) {
520 // This cube copy creates a filename w/ecub extension in the new project root, but looks to
521 // be a cube(internal vs external). It changes the DnFile pointer to the old ecub,
522 // /tmp/tsucharski_ipce/tmpProject/images/import1/AS15-.ecub, but doing a less on file
523 // immediately after the following call indicates it is a binary file.
524 QScopedPointer<Cube> newExternalLabel(
525 origImage.copy(newExternalLabelFileName, CubeAttributeOutput("+External")));
526
527 // If this is an ecub (it should be) and is pointing to a relative file name,
528 // then we want to copy the DN cube also.
529 if ( origImage.labelsAttached() == Cube::ExternalLabel) {
530 if (origImage.externalCubeFileName().path() == ".") {
531 Cube dnFile(
532 FileName(m_fileName).path() + "/" + origImage.externalCubeFileName().name());
533 FileName newDnFileName = newExternalLabelFileName.setExtension("cub");
534 QScopedPointer<Cube> newDnFile(dnFile.copy(newDnFileName, CubeAttributeOutput()));
535 newDnFile->close();
536 // Changes the ecube's DnFile pointer in the labels.
537 newExternalLabel->relocateDnData(newDnFileName.name());
538 }
539 else {
540 // If the the ecub's external cube is pointing to the old project root, update to new
541 // project root.
542 if (origImage.externalCubeFileName().toString().contains(project->projectRoot())) {
543 QString newExternalCubeFileName = origImage.externalCubeFileName().toString();
544 newExternalCubeFileName.replace(project->projectRoot(), project->newProjectRoot());
545 newExternalLabel->relocateDnData(newExternalCubeFileName);
546 }
547 else {
548 newExternalLabel->relocateDnData(origImage.externalCubeFileName());
549 }
550 }
551 }
552 }
553 }
554 }
555
556
563 bool deleteCubAlso = (cube()->externalCubeFileName().path() == ".");
564 closeCube();
565
566 if (!QFile::remove(m_fileName)) {
567 throw IException(IException::Io,
568 tr("Could not remove file [%1]").arg(m_fileName),
569 _FILEINFO_);
570 }
571
572 if (deleteCubAlso) {
573 FileName cubFile = FileName(m_fileName).setExtension("cub");
574 if (!QFile::remove(cubFile.expanded() ) ) {
575 throw IException(IException::Io,
576 tr("Could not remove file [%1]").arg(m_fileName),
577 _FILEINFO_);
578 }
579 }
580
581 // If we're the last thing in the folder, remove the folder too.
582 QDir dir;
583 dir.rmdir(FileName(m_fileName).path());
584 }
585
586
602 void Image::save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot)
603 const {
604 stream.writeStartElement("image");
605
606 stream.writeAttribute("id", m_id->toString());
607 stream.writeAttribute("fileName", FileName(m_fileName).name());
608 stream.writeAttribute("instrumentId", m_instrumentId);
609 stream.writeAttribute("spacecraftName", m_spacecraftName);
610
611 if (!IsSpecial(m_aspectRatio) ) {
612 stream.writeAttribute("aspectRatio", IString(m_aspectRatio).ToQt());
613 }
614
615 if (!IsSpecial(m_resolution) ) {
616 stream.writeAttribute("resolution", IString(m_resolution).ToQt());
617 }
618
619 if (m_emissionAngle.isValid() ) {
620 stream.writeAttribute("emissionAngle", IString(m_emissionAngle.radians()).ToQt());
621 }
622
623 if (m_incidenceAngle.isValid() ) {
624 stream.writeAttribute("incidenceAngle", IString(m_incidenceAngle.radians()).ToQt());
625 }
626
627 if (!IsSpecial(m_lineResolution) ) {
628 stream.writeAttribute("lineResolution", IString(m_lineResolution).ToQt());
629 }
630
631 if (m_localRadius.isValid() ) {
632 stream.writeAttribute("localRadius", IString(m_localRadius.meters()).ToQt());
633 }
634
635 if (m_northAzimuth.isValid() ) {
636 stream.writeAttribute("northAzimuth", IString(m_northAzimuth.radians()).ToQt());
637 }
638
639 if (m_phaseAngle.isValid() ) {
640 stream.writeAttribute("phaseAngle", IString(m_phaseAngle.radians()).ToQt());
641 }
642
643 if (!IsSpecial(m_sampleResolution) ) {
644 stream.writeAttribute("sampleResolution", IString(m_sampleResolution).ToQt());
645 }
646
647 if (m_footprint) {
648 stream.writeStartElement("footprint");
649
650 geos::io::WKTWriter wktWriter;
651 stream.writeCharacters(QString::fromStdString(wktWriter.write(m_footprint)));
652
653 stream.writeEndElement();
654 }
655
656 m_displayProperties->save(stream, project, newProjectRoot);
657
658 stream.writeEndElement();
659 }
660
661
668 closeCube();
669
670 FileName original(m_fileName);
671 FileName newName(project->imageDataRoot() + "/" +
672 original.dir().dirName() + "/" + original.name());
673 m_fileName = newName.expanded();
674 }
675
676
682 geos::geom::MultiPolygon *Image::createFootprint(QMutex *cameraMutex) {
683 QMutexLocker lock(cameraMutex);
684
685 // We need to walk the image to create the polygon...
686 ImagePolygon imgPoly;
687
688 int sampleStepSize = cube()->sampleCount() / 10;
689 if (sampleStepSize <= 0) sampleStepSize = 1;
690
691 int lineStepSize = cube()->lineCount() / 10;
692 if (lineStepSize <= 0) lineStepSize = 1;
693
694 imgPoly.Create(*cube(), sampleStepSize, lineStepSize);
695
696 IException e = IException(IException::User,
697 tr("Warning: Polygon re-calculated for [%1] which can be very slow")
698 .arg(displayProperties()->displayName()),
699 _FILEINFO_);
700 e.print();
701
702 return PolygonTools::MakeMultiPolygon(imgPoly.Polys()->clone().release());
703 }
704
705
711 bool hasCamStats = false;
712
713 Pvl &label = *cube()->label();
714 for (int i = 0; !hasCamStats && i < label.objects(); i++) {
715 PvlObject &obj = label.object(i);
716
717 try {
718 if (obj.name() == "Table") {
719 if (obj["Name"][0] == "CameraStatistics") {
720 hasCamStats = true;
721 }
722 }
723 }
724 catch (IException &) {
725 }
726 }
727
728 if (hasCamStats) {
729 Table camStatsTable("CameraStatistics", m_fileName, label);
730
731 int numRecords = camStatsTable.Records();
732 for (int recordIndex = 0; recordIndex < numRecords; recordIndex++) {
733 TableRecord &record = camStatsTable[recordIndex];
734
735 // The TableField class gives us a std::string with NULL (\0) characters... be careful not
736 // to keep them when going to QString.
737 QString recordName((QString)record["Name"]);
738 double avgValue = (double)record["Average"];
739
740 if (recordName == "AspectRatio") {
741 m_aspectRatio = avgValue;
742 }
743 else if (recordName == "Resolution") {
744 m_resolution = avgValue;
745 }
746 else if (recordName == "EmissionAngle") {
748 }
749 else if (recordName == "IncidenceAngle") {
751 }
752 else if (recordName == "LineResolution") {
753 m_lineResolution = avgValue;
754 }
755 else if (recordName == "LocalRadius") {
757 }
758 else if (recordName == "NorthAzimuth") {
760 }
761 else if (recordName == "PhaseAngle") {
762 m_phaseAngle = Angle(avgValue, Angle::Degrees);
763 }
764 else if (recordName == "SampleResolution") {
765 m_sampleResolution = avgValue;
766 }
767 }
768 }
769
770 for (int i = 0; i < label.objects(); i++) {
771 PvlObject &obj = label.object(i);
772 try {
773 if (obj.hasGroup("Instrument")) {
774 PvlGroup instGroup = obj.findGroup("Instrument");
775
776 if (instGroup.hasKeyword("SpacecraftName"))
777 m_spacecraftName = obj.findGroup("Instrument")["SpacecraftName"][0];
778
779 if (instGroup.hasKeyword("InstrumentId"))
780 m_instrumentId = obj.findGroup("Instrument")["InstrumentId"][0];
781 }
782 }
783 catch (IException &) {
784 }
785 }
786 }
787
788
794 ImagePolygon poly = cube()->readFootprint();
795 m_footprint = PolygonTools::MakeMultiPolygon(poly.Polys()->clone().release());
796 }
797}
Defines an angle and provides unit conversions.
Definition Angle.h:45
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
Manipulate and parse attributes of output cube filenames.
IO Handler for Isis Cubes.
Definition Cube.h:168
ImagePolygon readFootprint() const
Read the footprint polygon for the Cube.
Definition Cube.cpp:1114
int lineCount() const
Definition Cube.cpp:2008
FileName externalCubeFileName() const
If this is an external cube label file, this will give you the cube dn file that this label reference...
Definition Cube.cpp:1810
@ ExternalLabel
The label is pointing to an external DN file - the label is also external to the data.
Definition Cube.h:254
int sampleCount() const
Definition Cube.cpp:2081
Cube * copy(FileName newFile, const CubeAttributeOutput &newFileAttributes)
Copies the cube to the new fileName.
Definition Cube.cpp:288
LabelAttachment labelsAttached() const
Test if labels are attached.
Definition Cube.cpp:260
virtual QString fileName() const
Returns the opened cube's filename.
Definition Cube.cpp:1837
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition Cube.cpp:1975
QString displayName() const
Returns the display name.
PvlObject toPvl() const
Convert to Pvl for project files.
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
This is the GUI communication mechanism for cubes.
Cube * cube()
Get the Cube pointer associated with this display property.
Definition Image.cpp:263
Angle incidenceAngle() const
Get the incidence angle of this image, as calculated and attached by camstats.
Definition Image.cpp:451
double m_sampleResolution
Sample resolution of the image.
Definition Image.h:215
void copyToNewProjectRoot(const Project *project, FileName newProjectRoot)
Copy the cub/ecub files associated with this image into the new project.
Definition Image.cpp:510
void setId(QString id)
Override the automatically generated ID with the given ID.
Definition Image.cpp:359
Distance m_localRadius
Local radius of the image.
Definition Image.h:216
Angle phaseAngle() const
Get the phase angle of this image, as calculated and attached by camstats.
Definition Image.cpp:491
QString m_instrumentId
Instrument id associated with this Image.
Definition Image.h:184
void closeCube()
Cleans up the Cube pointer.
Definition Image.cpp:283
Distance localRadius() const
Get the local radius of this image, as calculated and attached by camstats.
Definition Image.cpp:471
geos::geom::MultiPolygon * footprint()
Get the footprint of this image (if available).
Definition Image.cpp:350
SpiceInt * m_bodyCode
The NaifBodyCode value, if it exists in the labels.
Definition Image.h:158
double m_lineResolution
Line resolution of the image.
Definition Image.h:214
QString serialNumber()
Returns the serial number of the Cube.
Definition Image.cpp:337
QUuid * m_id
A unique ID for this Image (useful for others to reference this Image when saving to disk).
Definition Image.h:208
~Image()
Clean up this image.
Definition Image.cpp:137
double m_aspectRatio
Aspect ratio of the image.
Definition Image.h:210
QString m_serialNumber
The serial number for this image.
Definition Image.h:194
Angle m_incidenceAngle
Incidence angle of the image.
Definition Image.h:213
Angle emissionAngle() const
Get the emission angle of this image, as calculated and attached by camstats.
Definition Image.cpp:441
void updateFileName(Project *)
Change the on-disk file name for this cube to be where the image ought to be in the given project.
Definition Image.cpp:667
double lineResolution() const
Get the line resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:461
bool isFootprintable() const
Test to see if it's possible to create a footprint from this image.
Definition Image.cpp:229
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Write the Image properties out to an XML file.
Definition Image.cpp:602
Angle m_emissionAngle
Emmission angle of the image.
Definition Image.h:212
double aspectRatio() const
Get the aspect ratio of this image, as calculated and attached by camstats.
Definition Image.cpp:412
QString m_fileName
The on-disk file name of the cube associated with this Image.
Definition Image.h:179
PvlObject toPvl() const
Convert this Image to PVL.
Definition Image.cpp:202
Image(QString imageFileName, QObject *parent=0)
Create an image from a cube file on disk.
Definition Image.cpp:41
Angle m_phaseAngle
Phase angle for the image.
Definition Image.h:218
QString m_spacecraftName
Spacecraft name associated with this Image.
Definition Image.h:199
double m_resolution
Resolution of the image.
Definition Image.h:211
QString m_observationNumber
The observation number for this image.
Definition Image.h:189
Cube * m_cube
The cube associated with this Image.
Definition Image.h:169
ImageDisplayProperties * displayProperties()
Get the display (GUI) properties (information) associated with this image.
Definition Image.cpp:296
Angle northAzimuth() const
Get the north azimuth of this image, as calculated and attached by camstats.
Definition Image.cpp:481
QString observationNumber()
Returns the observation number of the Cube.
Definition Image.cpp:325
Angle m_northAzimuth
North Azimuth for the image.
Definition Image.h:217
QString fileName() const
Get the file name of the cube that this image represents.
Definition Image.cpp:316
void initCamStats()
Checks to see if the Cube label contains Camera Statistics.
Definition Image.cpp:710
QString id() const
Get a unique, identifying string associated with this image.
Definition Image.cpp:421
double resolution() const
Get the resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:431
void fromPvl(const PvlObject &pvl)
Read the image settings from a Pvl.
Definition Image.cpp:170
bool initFootprint(QMutex *cameraMutex)
Calculate a footprint for this image.
Definition Image.cpp:385
void deleteFromDisk()
Delete the image data from disk.
Definition Image.cpp:562
geos::geom::MultiPolygon * createFootprint(QMutex *cameraMutex)
Calculates a footprint for an Image using the camera or projection information.
Definition Image.cpp:682
ImageDisplayProperties * m_displayProperties
The GUI information for how this Image ought to be displayed.
Definition Image.h:174
geos::geom::MultiPolygon * m_footprint
A 0-360 ocentric lon,lat degrees footprint of this Image.
Definition Image.h:204
void initQuickFootprint()
Creates a default ImagePolygon option which is read into the Cube.
Definition Image.cpp:793
double sampleResolution() const
Get the sample resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:501
Create cube polygons, read/write polygons to blobs.
void Create(Cube &cube, int sinc=1, int linc=1, int ss=1, int sl=1, int ns=0, int nl=0, int band=1, bool increasePrecision=false)
Create a Polygon from given cube.
geos::geom::MultiPolygon * Polys()
Return a geos Multipolygon.
Blob toBlob() const
Serialize the ImagePolygon to a Blob.
static QString Compose(Pvl &label, bool def2filename=false)
Compose a ObservationNumber from a PVL.
static geos::geom::MultiPolygon * MakeMultiPolygon(const geos::geom::Geometry *geom)
Make a geos::geom::MultiPolygon out of the components of the argument.
The main project for ipce.
Definition Project.h:287
QString newProjectRoot() const
Get the top-level folder of the new project.
Definition Project.cpp:1737
QString projectRoot() const
Get the top-level folder of the project.
Definition Project.cpp:1728
static QString imageDataRoot(QString projectRoot)
Appends the root directory name 'images' to the project .
Definition Project.cpp:2129
static QString Compose(Pvl &label, bool def2filename=false)
Compose a SerialNumber from a PVL.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16