10#include <QScopedPointer>
13#include <QXmlStreamWriter>
15#include <geos/geom/MultiPolygon.h>
16#include <geos/io/WKTReader.h>
17#include <geos/io/WKTWriter.h>
20#include "CameraFactory.h"
21#include "ControlPoint.h"
23#include "CubeAttribute.h"
24#include "DisplayProperties.h"
27#include "IException.h"
28#include "ImagePolygon.h"
30#include "PolygonTools.h"
32#include "ProjectionFactory.h"
33#include "SerialNumber.h"
34#include "ShapeDisplayProperties.h"
36#include "XmlStackedHandlerReader.h"
82 xmlReader->pushContentHandler(
new XmlHandler(
this, shapeFolder));
109 void Shape::initMemberData() {
117 m_aspectRatio =
Null;
119 m_lineResolution =
Null;
120 m_sampleResolution =
Null;
123 m_projectionName =
Null;
124 m_pixelResolution =
Null;
129 void Shape::initShape() {
132 m_id =
new QUuid(QUuid::createUuid());
135 m_radiusSource = ControlPoint::RadiusSource::None;
137 if (
cube()->hasTable(
"ShapeModelStatistics")) {
138 m_surfacePointSource = ControlPoint::SurfacePointSource::Basemap;
139 m_radiusSource = ControlPoint::RadiusSource::DEM;
146 m_surfacePointSource = ControlPoint::SurfacePointSource::Basemap;
147 m_radiusSource = ControlPoint::RadiusSource::Ellipsoid;
148 m_shapeType = Basemap;
150 catch (IException &) {
154 m_surfacePointSource = ControlPoint::SurfacePointSource::Reference;
156 PvlGroup kernels =
cube()->
group(
"Kernels");
157 if (kernels.hasKeyword(
"ShapeModel")) {
158 QString shapeFile = kernels[
"ShapeModel"];
159 if (shapeFile.contains(
"dem")) {
160 m_radiusSource = ControlPoint::RadiusSource::DEM;
163 m_radiusSource = ControlPoint::RadiusSource::Ellipsoid;
166 m_shapeType = Unprojected;
168 catch (IException &e) {
169 m_surfacePointSource = ControlPoint::SurfacePointSource::None;
170 m_radiusSource = ControlPoint::RadiusSource::None;
171 m_shapeType = Unknown;
172 QString message =
"Cannot create either Camera or Projections "
174 "Check the validity of the cube labels. The cube must either be projected or "
175 " run through spiceinit.";
182 if (m_shapeType == Unprojected) {
185 else if (m_shapeType == Basemap || m_shapeType == Dem) {
187 if (m_shapeType == Dem) {
192 catch (IException &e) {
193 QString message =
"Cannot initialize the camera, map or dem statistics for this shape file [" +
195 "cube must either be projected or run through spiceinit. \n";
196 message += e.toString();
197 QMessageBox::warning((
QWidget *) parent(),
"Warning", message);
201 initQuickFootprint();
203 catch (IException &e) {
209 ControlPoint::SurfacePointSource::Source Shape::surfacePointSource() {
210 return m_surfacePointSource;
214 ControlPoint::RadiusSource::Source Shape::radiusSource() {
215 return m_radiusSource;
219 Shape::ShapeType Shape::shapeType() {
237 QString pvlFileName = ((
IString)pvl[
"FileName"][0]).ToQt();
240 tr(
"Tried to load Shape [%1] with properties/information from [%2].")
247 if (pvl.hasKeyword(
"ID")) {
248 QByteArray hexValues(pvl[
"ID"][0].toLatin1());
249 QDataStream valuesStream(QByteArray::fromHex(hexValues));
250 valuesStream >> *
m_id;
275 dataBuffer.open(QIODevice::ReadWrite);
277 QDataStream idStream(&dataBuffer);
282 output +=
PvlKeyword(
"ID", QString(dataBuffer.data().toHex()));
303 QString blobType = example.
Type();
304 QString blobName = example.Name();
308 for (
int i = 0; i < labels.objects(); i++) {
311 if (obj.isNamed(blobType) && obj.hasKeyword(
"Name") && obj[
"Name"][0] == blobName)
403 *
m_id = QUuid(QString(
"{%1}").arg(
id));
424 initQuickFootprint();
431 IString msg =
"Could not read the footprint from cube [" +
433 "sure footprintinit has been run";
450 return m_aspectRatio;
460 return m_id->toString().remove(QRegExp(
"[{}]"));
482 return m_emissionAngle;
493 return m_incidenceAngle;
504 return m_lineResolution;
515 return m_localRadius;
526 return m_northAzimuth;
548 return m_sampleResolution;
562 QScopedPointer<Cube> newExternalLabel(
567 if (!origShape.storesDnData()) {
568 if (origShape.externalCubeFileName().path() ==
".") {
577 newExternalLabel->relocateDnData(newDnFileName.name());
580 newExternalLabel->relocateDnData(origShape.externalCubeFileName());
597 tr(
"Could not remove file [%1]").arg(
m_fileName),
603 if (!QFile::remove(cubFile.expanded())) {
605 tr(
"Could not remove file [%1]").arg(
m_fileName),
627 original.
dir().dirName() +
"/" + original.
name());
639 QMutexLocker lock(cameraMutex);
645 if (sampleStepSize <= 0) sampleStepSize = 1;
648 if (lineStepSize <= 0) lineStepSize = 1;
650 imgPoly.Create(*
cube(), sampleStepSize, lineStepSize);
653 tr(
"Warning: Polygon re-calculated for [%1] which can be very slow")
666 bool hasCamStats =
false;
669 for (
int i = 0; !hasCamStats && i < label.
objects(); i++) {
673 if (obj.name() ==
"Table") {
674 if (obj[
"Name"][0] ==
"CameraStatistics") {
687 int numRecords = camStatsTable.Records();
688 for (
int recordIndex = 0; recordIndex < numRecords; recordIndex++) {
693 QString recordName((QString)record[
"Name"]);
694 double avgValue = (double)record[
"Average"];
696 if (recordName ==
"AspectRatio") {
697 m_aspectRatio = avgValue;
699 else if (recordName ==
"Resolution") {
700 m_resolution = avgValue;
702 else if (recordName ==
"EmissionAngle") {
705 else if (recordName ==
"IncidenceAngle") {
708 else if (recordName ==
"LineResolution") {
709 m_lineResolution = avgValue;
711 else if (recordName ==
"LocalRadius") {
714 else if (recordName ==
"NorthAzimuth") {
717 else if (recordName ==
"PhaseAngle") {
720 else if (recordName ==
"SampleResolution") {
721 m_sampleResolution = avgValue;
726 for (
int i = 0; i < label.
objects(); i++) {
729 if (obj.hasGroup(
"Instrument")) {
730 PvlGroup instGroup = obj.findGroup(
"Instrument");
732 if (instGroup.hasKeyword(
"SpacecraftName"))
735 if (instGroup.hasKeyword(
"InstrumentId"))
746 void Shape::initMapStats() {
749 for (
int i = 0; i < label.
objects(); i++) {
752 if (obj.hasGroup(
"Instrument")) {
753 PvlGroup instGroup = obj.findGroup(
"Instrument");
755 if (instGroup.hasKeyword(
"SpacecraftName"))
758 if (instGroup.hasKeyword(
"InstrumentId"))
762 if (obj.hasGroup(
"Mapping")) {
763 PvlGroup mapGroup = obj.findGroup(
"Mapping");
765 if (mapGroup.hasKeyword(
"TargetName"))
766 m_targetName = obj.findGroup(
"Mapping")[
"TargetName"][0];
768 if (mapGroup.hasKeyword(
"ProjectionName"))
769 m_projectionName = obj.findGroup(
"Mapping")[
"ProjectionName"][0];
771 if (mapGroup.hasKeyword(
"CenterLongitude"))
772 m_centerLongitude = Longitude(
toDouble(obj.findGroup(
"Mapping")[
"CenterLongitude"][0]),
775 if (mapGroup.hasKeyword(
"CenterLatitude"))
776 m_centerLatitude = Latitude(
toDouble(obj.findGroup(
"Mapping")[
"CenterLatitude"][0]),
779 if (mapGroup.hasKeyword(
"MinimumLatitude"))
780 m_minimumLatitude = Latitude(
toDouble(obj.findGroup(
"Mapping")[
"MinimumLatitude"][0]),
783 if (mapGroup.hasKeyword(
"MaximumLatitude"))
784 m_maximumLatitude = Latitude(
toDouble(obj.findGroup(
"Mapping")[
"MaximumLatitude"][0]),
787 if (mapGroup.hasKeyword(
"MinimumLongitude"))
788 m_minimumLongitude = Longitude(
toDouble(obj.findGroup(
"Mapping")[
"MinimumLongitude"][0]),
791 if (mapGroup.hasKeyword(
"MaximumLongitude"))
792 m_maximumLongitude = Longitude(
toDouble(obj.findGroup(
"Mapping")[
"MaximumLongitude"][0]),
795 if (mapGroup.hasKeyword(
"PixelResolution"))
796 m_pixelResolution = obj.findGroup(
"Mapping")[
"PixelResolution"];
798 if (mapGroup.hasKeyword(
"Scale"))
799 m_scale = obj.findGroup(
"Mapping")[
"Scale"];
802 catch (IException &e) {
809 void Shape::initDemStats() {
815 void Shape::initQuickFootprint() {
830 m_shapeFolder = shapeFolder;
847 stream.writeStartElement(
"shape");
849 stream.writeAttribute(
"id",
m_id->toString());
854 if (m_shapeType == Unprojected) {
855 type =
"Unprojected";
857 else if (m_shapeType == Basemap) {
863 stream.writeAttribute(
"shapeType", type);
864 stream.writeAttribute(
"surfacePointSource",
866 stream.writeAttribute(
"radiusSource",
869 if (m_shapeType == Unprojected) {
874 stream.writeAttribute(
"aspectRatio",
IString(m_aspectRatio).ToQt());
878 stream.writeAttribute(
"resolution",
IString(m_resolution).ToQt());
881 if (m_emissionAngle.
isValid()) {
885 if (m_incidenceAngle.
isValid()) {
890 stream.writeAttribute(
"lineResolution",
IString(m_lineResolution).ToQt());
897 if (m_northAzimuth.
isValid()) {
906 stream.writeAttribute(
"sampleResolution",
IString(m_sampleResolution).ToQt());
909 else if (m_shapeType == Basemap) {
912 else if (m_shapeType == Dem) {
917 stream.writeStartElement(
"footprint");
919 geos::io::WKTWriter wktWriter;
920 stream.writeCharacters(QString::fromStdString(wktWriter.write(
m_footprint)));
922 stream.writeEndElement();
927 stream.writeEndElement();
937 const QString &qName,
const QXmlAttributes &atts) {
940 if (XmlStackedHandler::startElement(namespaceURI, localName, qName, atts)) {
941 if (localName ==
"shape") {
942 QString
id = atts.value(
"id");
943 QString
fileName = atts.value(
"fileName");
944 m_shape->m_serialNumber = atts.value(
"serialNumber");
947 delete m_shape->m_id;
948 m_shape->m_id = NULL;
949 m_shape->m_id =
new QUuid(
id.toLatin1());
953 m_shape->m_fileName = m_shapeFolder.expanded() +
"/" +
fileName;
956 if (m_shape->m_serialNumber.isEmpty()) {
960 m_shape->m_surfacePointSource =
962 m_shape->m_radiusSource =
964 QString shapeType = atts.value(
"shapeType");
966 if (shapeType ==
"Unprojected") {
967 m_shape->m_shapeType = Unprojected;
968 QString instrumentId = atts.value(
"instrumentId");
969 QString spacecraftName = atts.value(
"spacecraftName");
971 QString aspectRatioStr = atts.value(
"aspectRatio");
972 QString resolutionStr = atts.value(
"resolution");
973 QString emissionAngleStr = atts.value(
"emissionAngle");
974 QString incidenceAngleStr = atts.value(
"incidenceAngle");
975 QString lineResolutionStr = atts.value(
"lineResolution");
976 QString localRadiusStr = atts.value(
"localRadius");
977 QString northAzimuthStr = atts.value(
"northAzimuth");
978 QString phaseAngleStr = atts.value(
"phaseAngle");
979 QString sampleResolutionStr = atts.value(
"sampleResolution");
981 if (!instrumentId.isEmpty()) {
982 m_shape->m_instrumentId = m_shapeFolder.expanded() +
"/" + instrumentId;
985 if (!instrumentId.isEmpty()) {
986 m_shape->m_instrumentId = m_shapeFolder.expanded() +
"/" + instrumentId;
989 if (!spacecraftName.isEmpty()) {
990 m_shape->m_spacecraftName = m_shapeFolder.expanded() +
"/" + spacecraftName;
993 if (!aspectRatioStr.isEmpty()) {
994 m_shape->m_aspectRatio = aspectRatioStr.toDouble();
997 if (!resolutionStr.isEmpty()) {
998 m_shape->m_resolution = resolutionStr.toDouble();
1001 if (!emissionAngleStr.isEmpty()) {
1005 if (!incidenceAngleStr.isEmpty()) {
1009 if (!lineResolutionStr.isEmpty()) {
1010 m_shape->m_lineResolution = lineResolutionStr.toDouble();
1013 if (!localRadiusStr.isEmpty()) {
1017 if (!northAzimuthStr.isEmpty()) {
1021 if (!phaseAngleStr.isEmpty()) {
1025 if (!sampleResolutionStr.isEmpty()) {
1026 m_shape->m_sampleResolution = sampleResolutionStr.toDouble();
1029 else if (shapeType ==
"Basemap") {
1030 m_shape->m_shapeType = Basemap;
1032 else if (shapeType ==
"Dem") {
1033 m_shape->m_shapeType = Dem;
1036 m_shape->m_shapeType = Unknown;
1041 else if (localName ==
"displayProperties") {
1051 bool Shape::XmlHandler::characters(
const QString &ch) {
1054 return XmlStackedHandler::characters(ch);
1059 bool Shape::XmlHandler::endElement(
const QString &namespaceURI,
const QString &localName,
1060 const QString &qName) {
1061 if (localName ==
"footprint" && !m_characters.isEmpty()) {
1062 geos::io::WKTReader wktReader(*globalFactory);
1065 wktReader.read(m_characters.toStdString()).release());
1067 catch (IException &e) {
1071 else if (localName ==
"shape" && !m_shape->m_footprint) {
1074 m_shape->initFootprint(&mutex);
1075 m_shape->closeCube();
1077 catch (IException &e) {
1083 return XmlStackedHandler::endElement(namespaceURI, localName, qName);
Defines an angle and provides unit conversions.
bool isValid() const
This indicates whether we have a legitimate angle stored or are in an unset, or invalid,...
double radians() const
Convert an angle to a double.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
QString Type() const
Accessor method that returns a string containing the Blob type.
static Camera * Create(Cube &cube)
Creates a Camera object using Pvl Specifications.
static QString RadiusSourceToString(RadiusSource::Source source)
Obtain a string representation of a given RadiusSource.
static SurfacePointSource::Source StringToSurfacePointSource(QString str)
Obtain a SurfacePoint::Source from a string.
static RadiusSource::Source StringToRadiusSource(QString str)
Obtain a RadiusSource::Source from a string.
static QString SurfacePointSourceToString(SurfacePointSource::Source source)
Obtain a string representation of a given SurfacePointSource.
Manipulate and parse attributes of output cube filenames.
IO Handler for Isis Cubes.
ImagePolygon readFootprint() const
Read the footprint polygon for the Cube.
FileName externalCubeFileName() const
If this is an external cube label file, this will give you the cube dn file that this label reference...
PvlGroup & group(const QString &group) const
Read a group from the cube into a Label.
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
QString displayName() const
Returns the display name.
PvlObject toPvl() const
Convert to Pvl for project files.
Distance measurement, usually in meters.
bool isValid() const
Test if this distance has been initialized or not.
@ Meters
The distance is being specified in meters.
double meters() const
Get the distance in meters.
File name manipulation and expansion.
QString path() const
Returns the path of the file name.
QDir dir() const
Returns the path of the file's parent directory as a QDir object.
FileName setExtension(const QString &extension) const
Sets all current file extensions to a new extension in the file name.
QString name() const
Returns the name of the file excluding the path and the attributes in the file name.
QString toString() const
Returns a QString of the full file name including the file path, excluding the attributes with any Is...
@ Unknown
A type of error that cannot be classified as any of the other error types.
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
@ Programmer
This error is for when a programmer made an API call that was illegal.
@ Io
A type of error that occurred when performing an actual I/O operation.
Adds specific functionality to C++ strings.
QString ToQt() const
Retuns the object string as a QString.
Create cube polygons, read/write polygons to blobs.
Blob toBlob() const
Serialize the ImagePolygon to a Blob.
The main project for ipce.
static QString shapeDataRoot(QString projectRoot)
Appends the root directory name 'shapes' to the project .
QString projectRoot() const
Get the top-level folder of the project.
QString shapeDataRoot() const
Accessor for the root directory of the shape model data.
static Isis::Projection * CreateFromCube(Isis::Cube &cube)
This method is a helper method.
Contains multiple PvlContainers.
Container for cube-like labels.
A single keyword-value pair.
Contains Pvl Groups and Pvl Objects.
int objects() const
Returns the number of objects.
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.
XmlHandler(Shape *shape, FileName shapeFolder)
Create an XML Handler (reader) that can populate the Shape class data.
virtual bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts)
Handle an XML start element.
This is the GUI communication mechanism for shape objects.
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Saves this object to an XML file.
This represents a shape in a project-based GUI interface.
~Shape()
Clean up this shape.
geos::geom::MultiPolygon * createFootprint(QMutex *cameraMutex)
Calculate a footprint for an Shape using the camera or projection information.
Shape(QString shapeFileName, QObject *parent=0)
Create an Shape from a cube file on disk.
void closeCube()
Cleans up the Cube *.
PvlObject toPvl() const
Convert this Shape to PVL.
bool isFootprintable() const
Test to see if it's possible to create a footprint from this shape.
SpiceInt * m_bodyCode
The NaifBodyCode value, if it exists in the labels.
Distance localRadius() const
Get the local radius of this shape, as calculated and attached by camstats.
Angle phaseAngle() const
Get the phase angle of this shape, as calculated and attached by camstats.
void updateFileName(Project *)
Change the on-disk file name for this cube to be where the shape ought to be in the given project.
double resolution() const
Get the resolution of this shape, as calculated and attached by camstats.
QString serialNumber()
Get the serial number.
QString m_spacecraftName
Spacecraft name associated with this Shape.
double sampleResolution() const
Get the sample resolution of this shape, as calculated and attached by camstats.
ShapeDisplayProperties * displayProperties()
Get the display (GUI) properties (information) associated with this shape.
double lineResolution() const
Get the line resolution of this shape, as calculated and attached by camstats.
void deleteFromDisk()
Delete the shape data from disk.
Angle emissionAngle() const
Get the emission angle of this shape, as calculated and attached by camstats.
QString id() const
Get a unique, identifying string associated with this shape.
void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const
Output format:
double aspectRatio() const
Get the aspect ratio of this shape, as calculated and attached by camstats.
QString fileName() const
Get the file name of the cube that this shape represents.
Cube * m_cube
The cube associated with this Shape.
geos::geom::MultiPolygon * m_footprint
A 0-360 ocentric lon,lat degrees footprint of this Shape.
Cube * cube()
Get the Cube * associated with this display property.
Angle incidenceAngle() const
Get the incidence angle of this shape, as calculated and attached by camstats.
void copyToNewProjectRoot(const Project *project, FileName newProjectRoot)
Copy the cub/ecub files associated with this shape into the new project.
QUuid * m_id
A unique ID for this Shape (useful for others to reference this Shape when saving to disk).
QString m_serialNumber
This will always be simply the filename and is created on construction.
QString m_instrumentId
Instrument id associated with this Shape.
bool initFootprint(QMutex *cameraMutex)
Calculate a footprint for this shape.
void fromPvl(const PvlObject &pvl)
Read the shape settings from a Pvl.
void setId(QString id)
Override the automatically generated ID with the given ID.
Angle northAzimuth() const
Get the north azimuth of this shape, as calculated and attached by camstats.
geos::geom::MultiPolygon * footprint()
Get the footprint of this shape (if available).
QString m_fileName
The on-disk file name of the cube associated with this Shape.
ShapeDisplayProperties * m_displayProperties
The GUI information for how this Shape ought to be displayed.
Class for storing Table blobs information.
Manage a stack of content handlers for reading XML files.
This is free and unencumbered software released into the public domain.
const double Null
Value for an Isis Null pixel.
bool IsSpecial(const double d)
Returns if the input pixel is special.
double toDouble(const QString &string)
Global function to convert from a string to a double.