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 <QScopedPointer>
10#include <QString>
11#include <QUuid>
12#include <QXmlStreamWriter>
13
14#include <geos/geom/MultiPolygon.h>
15#include <geos/io/WKTReader.h>
16#include <geos/io/WKTWriter.h>
17
18#include "Angle.h"
19#include "Cube.h"
20#include "CubeAttribute.h"
21#include "DisplayProperties.h"
22#include "Distance.h"
23#include "FileName.h"
25#include "ImagePolygon.h"
26#include "IString.h"
27#include "ObservationNumber.h"
28#include "PolygonTools.h"
29#include "Project.h"
30#include "SerialNumber.h"
31#include "Target.h"
32
33namespace Isis {
34
40 Image::Image(QString imageFileName, QObject *parent) : QObject(parent) {
41 m_bodyCode = NULL;
42 m_cube = NULL;
44 m_footprint = NULL;
45 m_id = NULL;
46
51
52 m_fileName = imageFileName;
53
54 cube();
55
57
58 try {
60 }
61 catch (IException &) {
62 }
63
65
66 m_id = new QUuid(QUuid::createUuid());
67 }
68
69
75 Image::Image(Cube *imageCube, QObject *parent) : QObject(parent) {
76 m_fileName = imageCube->fileName();
77
78 m_bodyCode = NULL;
79 m_cube = imageCube;
81 m_footprint = NULL;
82 m_id = NULL;
83
88
90
91 try {
93 }
94 catch (IException &e) {
95 }
96
98
99 m_id = new QUuid(QUuid::createUuid());
100 }
101
102
109 Image::Image(Cube *imageCube, geos::geom::MultiPolygon *footprint, QString id, QObject *parent) :
110 QObject(parent) {
111 m_fileName = imageCube->fileName();
112
113 m_bodyCode = NULL;
114 m_cube = imageCube;
115 m_displayProperties = NULL;
116 m_id = NULL;
117
122
123 initCamStats();
124
126
128
129 setId(id);
130 }
131
132
137 delete m_bodyCode;
138 m_bodyCode = NULL;
139
140 delete m_cube;
141 m_cube = NULL;
142
143 delete m_footprint;
144 m_footprint = NULL;
145
146 delete m_id;
147 m_id = NULL;
148
149 // Image is a "Qt" parent of display properties, so the Image QObject
150 // destructor will take care of deleting the display props. See call to
151 // DisplayProperties' constructor.
152 m_displayProperties = NULL;
153 }
154
155
169 void Image::fromPvl(const PvlObject &pvl) {
170 QString pvlFileName = ((IString)pvl["FileName"][0]).ToQt();
171 if (m_fileName != pvlFileName) {
173 tr("Tried to load Image [%1] with properties/information from [%2].")
174 .arg(m_fileName).arg(pvlFileName),
175 _FILEINFO_);
176 }
177
178 displayProperties()->fromPvl(pvl.findObject("DisplayProperties"));
179
180 if (pvl.hasKeyword("ID")) {
181 QByteArray hexValues(pvl["ID"][0].toLatin1());
182 QDataStream valuesStream(QByteArray::fromHex(hexValues));
183 valuesStream >> *m_id;
184 }
185 }
186
187
202 PvlObject output("Image");
203
204 output += PvlKeyword("FileName", m_fileName);
205
206 // Do m_id
207 QBuffer dataBuffer;
208 dataBuffer.open(QIODevice::ReadWrite);
209
210 QDataStream idStream(&dataBuffer);
211 idStream << *m_id;
212
213 dataBuffer.seek(0);
214
215 output += PvlKeyword("ID", QString(dataBuffer.data().toHex()));
216
217 output += displayProperties()->toPvl();
218
219 return output;
220 }
221
222
229 bool result = false;
230
231 if (m_footprint) {
232 result = true;
233 }
234
235 if (!result && m_cube) {
236 Blob example = ImagePolygon().toBlob();
237
238 QString blobType = example.Type();
239 QString blobName = example.Name();
240
241 Pvl &labels = *m_cube->label();
242
243 for (int i = 0; i < labels.objects(); i++) {
244 PvlObject &obj = labels.object(i);
245
246 if (obj.isNamed(blobType) && obj.hasKeyword("Name") && obj["Name"][0] == blobName)
247 result = true;
248 }
249 }
250
251 return result;
252 }
253
254
263 if (!m_cube) {
264 try {
265 m_cube = new Cube(m_fileName);
266 }
267 catch (IException &e) {
268 throw IException(e, IException::Programmer, "Cube cannot be created", _FILEINFO_);
269 }
270 }
271
272 return m_cube;
273 }
274
275
283 if (m_cube) {
284 delete m_cube;
285 m_cube = NULL;
286 }
287 }
288
289
298
299
309
310
315 QString Image::fileName() const {
316 return m_fileName;
317 }
318
319
325 if (m_observationNumber.isEmpty()) {
327 }
328 return m_observationNumber;
329 }
330
331
337 if (m_serialNumber.isEmpty()) {
339 }
340 return m_serialNumber;
341 }
342
343
349 geos::geom::MultiPolygon *Image::footprint() {
350 return m_footprint;
351 }
352
353
358 void Image::setId(QString id) {
359 m_id = new QUuid(id);
360 }
361
362
368 const geos::geom::MultiPolygon *Image::footprint() const {
369 return m_footprint;
370 }
371
372
384 bool Image::initFootprint(QMutex *cameraMutex) {
385 if (!m_footprint) {
386 try {
388 }
389 catch (IException &e) {
390 try {
391 m_footprint = createFootprint(cameraMutex);
392 }
393 catch (IException &e) {
394 IString msg = "Could not read the footprint from cube [" +
395 displayProperties()->displayName() + "]. Please make "
396 "sure footprintinit has been run";
397 throw IException(e, IException::Io, msg, _FILEINFO_);
398 }
399 }
400 }
401
402 // I'm not sure how this could ever be NULL. -SL
403 return (m_footprint != NULL);
404 }
405
406
411 double Image::aspectRatio() const {
412 return m_aspectRatio;
413 }
414
415
420 QString Image::id() const {
421 return m_id->toString().remove(QRegExp("[{}]"));
422 }
423
424
430 double Image::resolution() const {
431 return m_resolution;
432 }
433
434
441 return m_emissionAngle;
442 }
443
444
451 return m_incidenceAngle;
452 }
453
454
460 double Image::lineResolution() const {
461 return m_lineResolution;
462 }
463
464
471 return m_localRadius;
472 }
473
474
481 return m_northAzimuth;
482 }
483
484
491 return m_phaseAngle;
492 }
493
494
500 double Image::sampleResolution() const {
501 return m_sampleResolution;
502 }
503
504
509 void Image::copyToNewProjectRoot(const Project *project, FileName newProjectRoot) {
510 if (FileName(newProjectRoot) != FileName(project->projectRoot())) {
511 Cube origImage(m_fileName);
512
513 // The imageDataRoot will either be PROJECTROOT/images or PROJECTROOT/results/bundle/timestamp/images,
514 // depending on how the newProjectRoot points to.
515 FileName newExternalLabelFileName(Project::imageDataRoot(newProjectRoot.toString()) + "/" +
516 FileName(m_fileName).dir().dirName() + "/" + FileName(m_fileName).name());
517
518 if (m_fileName != newExternalLabelFileName.toString()) {
519 // This cube copy creates a filename w/ecub extension in the new project root, but looks to
520 // be a cube(internal vs external). It changes the DnFile pointer to the old ecub,
521 // /tmp/tsucharski_ipce/tmpProject/images/import1/AS15-.ecub, but doing a less on file
522 // immediately after the following call indicates it is a binary file.
523 QScopedPointer<Cube> newExternalLabel(
524 origImage.copy(newExternalLabelFileName, CubeAttributeOutput("+External")));
525
526 // If this is an ecub (it should be) and is pointing to a relative file name,
527 // then we want to copy the DN cube also.
528 if (!origImage.storesDnData() ) {
529 if (origImage.externalCubeFileName().path() == ".") {
530 Cube dnFile(
531 FileName(m_fileName).path() + "/" + origImage.externalCubeFileName().name());
532 FileName newDnFileName = newExternalLabelFileName.setExtension("cub");
533 QScopedPointer<Cube> newDnFile(dnFile.copy(newDnFileName, CubeAttributeOutput()));
534 newDnFile->close();
535 // Changes the ecube's DnFile pointer in the labels.
536 newExternalLabel->relocateDnData(newDnFileName.name());
537 }
538 else {
539 // If the the ecub's external cube is pointing to the old project root, update to new
540 // project root.
541 if (origImage.externalCubeFileName().toString().contains(project->projectRoot())) {
542 QString newExternalCubeFileName = origImage.externalCubeFileName().toString();
543 newExternalCubeFileName.replace(project->projectRoot(), project->newProjectRoot());
544 newExternalLabel->relocateDnData(newExternalCubeFileName);
545 }
546 else {
547 newExternalLabel->relocateDnData(origImage.externalCubeFileName());
548 }
549 }
550 }
551 }
552 }
553 }
554
555
562 bool deleteCubAlso = (cube()->externalCubeFileName().path() == ".");
563 closeCube();
564
565 if (!QFile::remove(m_fileName)) {
567 tr("Could not remove file [%1]").arg(m_fileName),
568 _FILEINFO_);
569 }
570
571 if (deleteCubAlso) {
572 FileName cubFile = FileName(m_fileName).setExtension("cub");
573 if (!QFile::remove(cubFile.expanded() ) ) {
575 tr("Could not remove file [%1]").arg(m_fileName),
576 _FILEINFO_);
577 }
578 }
579
580 // If we're the last thing in the folder, remove the folder too.
581 QDir dir;
582 dir.rmdir(FileName(m_fileName).path());
583 }
584
585
601 void Image::save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot)
602 const {
603 stream.writeStartElement("image");
604
605 stream.writeAttribute("id", m_id->toString());
606 stream.writeAttribute("fileName", FileName(m_fileName).name());
607 stream.writeAttribute("instrumentId", m_instrumentId);
608 stream.writeAttribute("spacecraftName", m_spacecraftName);
609
610 if (!IsSpecial(m_aspectRatio) ) {
611 stream.writeAttribute("aspectRatio", IString(m_aspectRatio).ToQt());
612 }
613
614 if (!IsSpecial(m_resolution) ) {
615 stream.writeAttribute("resolution", IString(m_resolution).ToQt());
616 }
617
618 if (m_emissionAngle.isValid() ) {
619 stream.writeAttribute("emissionAngle", IString(m_emissionAngle.radians()).ToQt());
620 }
621
622 if (m_incidenceAngle.isValid() ) {
623 stream.writeAttribute("incidenceAngle", IString(m_incidenceAngle.radians()).ToQt());
624 }
625
627 stream.writeAttribute("lineResolution", IString(m_lineResolution).ToQt());
628 }
629
630 if (m_localRadius.isValid() ) {
631 stream.writeAttribute("localRadius", IString(m_localRadius.meters()).ToQt());
632 }
633
634 if (m_northAzimuth.isValid() ) {
635 stream.writeAttribute("northAzimuth", IString(m_northAzimuth.radians()).ToQt());
636 }
637
638 if (m_phaseAngle.isValid() ) {
639 stream.writeAttribute("phaseAngle", IString(m_phaseAngle.radians()).ToQt());
640 }
641
643 stream.writeAttribute("sampleResolution", IString(m_sampleResolution).ToQt());
644 }
645
646 if (m_footprint) {
647 stream.writeStartElement("footprint");
648
649 geos::io::WKTWriter wktWriter;
650 stream.writeCharacters(QString::fromStdString(wktWriter.write(m_footprint)));
651
652 stream.writeEndElement();
653 }
654
655 m_displayProperties->save(stream, project, newProjectRoot);
656
657 stream.writeEndElement();
658 }
659
660
667 closeCube();
668
669 FileName original(m_fileName);
670 FileName newName(project->imageDataRoot() + "/" +
671 original.dir().dirName() + "/" + original.name());
672 m_fileName = newName.expanded();
673 }
674
675
681 geos::geom::MultiPolygon *Image::createFootprint(QMutex *cameraMutex) {
682 QMutexLocker lock(cameraMutex);
683
684 // We need to walk the image to create the polygon...
685 ImagePolygon imgPoly;
686
687 int sampleStepSize = cube()->sampleCount() / 10;
688 if (sampleStepSize <= 0) sampleStepSize = 1;
689
690 int lineStepSize = cube()->lineCount() / 10;
691 if (lineStepSize <= 0) lineStepSize = 1;
692
693 imgPoly.Create(*cube(), sampleStepSize, lineStepSize);
694
696 tr("Warning: Polygon re-calculated for [%1] which can be very slow")
697 .arg(displayProperties()->displayName()),
698 _FILEINFO_);
699 e.print();
700
701 return PolygonTools::MakeMultiPolygon(imgPoly.Polys()->clone().release());
702 }
703
704
710 bool hasCamStats = false;
711
712 Pvl &label = *cube()->label();
713 for (int i = 0; !hasCamStats && i < label.objects(); i++) {
714 PvlObject &obj = label.object(i);
715
716 try {
717 if (obj.name() == "Table") {
718 if (obj["Name"][0] == "CameraStatistics") {
719 hasCamStats = true;
720 }
721 }
722 }
723 catch (IException &) {
724 }
725 }
726
727 if (hasCamStats) {
728 Table camStatsTable("CameraStatistics", m_fileName, label);
729
730 int numRecords = camStatsTable.Records();
731 for (int recordIndex = 0; recordIndex < numRecords; recordIndex++) {
732 TableRecord &record = camStatsTable[recordIndex];
733
734 // The TableField class gives us a std::string with NULL (\0) characters... be careful not
735 // to keep them when going to QString.
736 QString recordName((QString)record["Name"]);
737 double avgValue = (double)record["Average"];
738
739 if (recordName == "AspectRatio") {
740 m_aspectRatio = avgValue;
741 }
742 else if (recordName == "Resolution") {
743 m_resolution = avgValue;
744 }
745 else if (recordName == "EmissionAngle") {
747 }
748 else if (recordName == "IncidenceAngle") {
750 }
751 else if (recordName == "LineResolution") {
752 m_lineResolution = avgValue;
753 }
754 else if (recordName == "LocalRadius") {
756 }
757 else if (recordName == "NorthAzimuth") {
759 }
760 else if (recordName == "PhaseAngle") {
761 m_phaseAngle = Angle(avgValue, Angle::Degrees);
762 }
763 else if (recordName == "SampleResolution") {
764 m_sampleResolution = avgValue;
765 }
766 }
767 }
768
769 for (int i = 0; i < label.objects(); i++) {
770 PvlObject &obj = label.object(i);
771 try {
772 if (obj.hasGroup("Instrument")) {
773 PvlGroup instGroup = obj.findGroup("Instrument");
774
775 if (instGroup.hasKeyword("SpacecraftName"))
776 m_spacecraftName = obj.findGroup("Instrument")["SpacecraftName"][0];
777
778 if (instGroup.hasKeyword("InstrumentId"))
779 m_instrumentId = obj.findGroup("Instrument")["InstrumentId"][0];
780 }
781 }
782 catch (IException &) {
783 }
784 }
785 }
786
787
793 ImagePolygon poly = cube()->readFootprint();
794 m_footprint = PolygonTools::MakeMultiPolygon(poly.Polys()->clone().release());
795 }
796}
Defines an angle and provides unit conversions.
Definition Angle.h:45
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
Definition Angle.cpp:95
double radians() const
Convert an angle to a double.
Definition Angle.h:226
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
QString Type() const
Accessor method that returns a string containing the Blob type.
Definition Blob.cpp:124
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:873
int lineCount() const
Definition Cube.cpp:1741
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:1542
int sampleCount() const
Definition Cube.cpp:1814
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Definition Cube.cpp:1708
QString displayName() const
Returns the display name.
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Output format:
PvlObject toPvl() const
Convert to Pvl for project files.
Distance measurement, usually in meters.
Definition Distance.h:34
bool isValid() const
Test if this distance has been initialized or not.
Definition Distance.cpp:192
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
double meters() const
Get the distance in meters.
Definition Distance.cpp:85
File name manipulation and expansion.
Definition FileName.h:100
QString path() const
Returns the path of the file name.
Definition FileName.cpp:103
QDir dir() const
Returns the path of the file's parent directory as a QDir object.
Definition FileName.cpp:465
FileName setExtension(const QString &extension) const
Sets all current file extensions to a new extension in the file name.
Definition FileName.cpp:265
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
Definition FileName.cpp:162
QString toString() const
Returns a QString of the full file name including the file path, excluding the attributes with any Is...
Definition FileName.cpp:515
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
Adds specific functionality to C++ strings.
Definition IString.h:165
QString ToQt() const
Retuns the object string as a QString.
Definition IString.cpp:869
This is the GUI communication mechanism for cubes.
Cube * cube()
Get the Cube pointer associated with this display property.
Definition Image.cpp:262
Angle incidenceAngle() const
Get the incidence angle of this image, as calculated and attached by camstats.
Definition Image.cpp:450
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:509
void setId(QString id)
Override the automatically generated ID with the given ID.
Definition Image.cpp:358
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:490
QString m_instrumentId
Instrument id associated with this Image.
Definition Image.h:184
void closeCube()
Cleans up the Cube pointer.
Definition Image.cpp:282
Distance localRadius() const
Get the local radius of this image, as calculated and attached by camstats.
Definition Image.cpp:470
geos::geom::MultiPolygon * footprint()
Get the footprint of this image (if available).
Definition Image.cpp:349
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:336
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:136
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:440
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:666
double lineResolution() const
Get the line resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:460
bool isFootprintable() const
Test to see if it's possible to create a footprint from this image.
Definition Image.cpp:228
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Write the Image properties out to an XML file.
Definition Image.cpp:601
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:411
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:201
Image(QString imageFileName, QObject *parent=0)
Create an image from a cube file on disk.
Definition Image.cpp:40
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:295
Angle northAzimuth() const
Get the north azimuth of this image, as calculated and attached by camstats.
Definition Image.cpp:480
QString observationNumber()
Returns the observation number of the Cube.
Definition Image.cpp:324
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:315
void initCamStats()
Checks to see if the Cube label contains Camera Statistics.
Definition Image.cpp:709
QString id() const
Get a unique, identifying string associated with this image.
Definition Image.cpp:420
double resolution() const
Get the resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:430
void fromPvl(const PvlObject &pvl)
Read the image settings from a Pvl.
Definition Image.cpp:169
bool initFootprint(QMutex *cameraMutex)
Calculate a footprint for this image.
Definition Image.cpp:384
void deleteFromDisk()
Delete the image data from disk.
Definition Image.cpp:561
geos::geom::MultiPolygon * createFootprint(QMutex *cameraMutex)
Calculates a footprint for an Image using the camera or projection information.
Definition Image.cpp:681
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:792
double sampleResolution() const
Get the sample resolution of this image, as calculated and attached by camstats.
Definition Image.cpp:500
Create cube polygons, read/write polygons to blobs.
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:1736
QString imageDataRoot() const
Accessor for the root directory of the image data.
Definition Project.cpp:2138
QString projectRoot() const
Get the top-level folder of the project.
Definition Project.cpp:1727
static QString imageDataRoot(QString projectRoot)
Appends the root directory name 'images' to the project .
Definition Project.cpp:2128
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
int objects() const
Returns the number of objects.
Definition PvlObject.h:221
PvlObject & object(const int index)
Return the object at the specified index.
static QString Compose(Pvl &label, bool def2filename=false)
Compose a SerialNumber from a PVL.
Class for storing Table blobs information.
Definition Table.h:61
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double Null
Value for an Isis Null pixel.
bool IsSpecial(const double d)
Returns if the input pixel is special.