24#include "Displacement.h"
27#include "IException.h"
32#include "LinearAlgebra.h"
33#include "NaifStatus.h"
34#include "SpecialPixel.h"
35#include "SurfacePoint.h"
37#include "SensorUtilities.h"
39#include "csm/Warning.h"
41#include "csm/Plugin.h"
42#include "csm/Ellipsoid.h"
43#include "csm/SettableEllipsoid.h"
45#include <nlohmann/json.hpp>
46using json = nlohmann::json;
52json stateAsJson(std::string modelState);
53void sanitize(std::string &input);
63 Blob state(
"CSMState",
"String");
67 QString pluginName = blobLabel.
findKeyword(
"PluginName")[0];
68 QString modelName = blobLabel.findKeyword(
"ModelName")[0];
69 QString stateString = QString::fromUtf8(state.
getBuffer(), state.
Size());
70 init(cube, pluginName, modelName, stateString);
83 const csm::Plugin *plugin = csm::Plugin::findPlugin(pluginName.toStdString());
86 for (
const csm::Plugin *plugin: csm::Plugin::getList()) {
87 availablePlugins.append(QString::fromStdString(plugin->getPluginName()));
89 QString msg =
"Failed to find plugin [" + pluginName +
"] for image [" + cube.
fileName() +
90 "]. Check that the corresponding CSM plugin library is in the directory "
91 "specified by your IsisPreferences. Loaded plugins [" +
92 availablePlugins.join(
", ") +
"].";
95 if (!plugin->canModelBeConstructedFromState(modelName.toStdString(), stateString.toStdString())) {
96 QString msg =
"CSM state string attached to image [" + cube.
fileName() +
"] cannot "
97 "be converted to a [" + modelName +
"] using [" + pluginName +
"].";
100 m_model =
dynamic_cast<csm::RasterGM*
>(plugin->constructModelFromState(stateString.toStdString()));
103 QString msg =
"Failed to convert CSM Model to RasterGM.";
112 QString timeString = QString::fromStdString(m_model->getReferenceDateAndTime());
114 timeString.remove(
"Z");
135 csm::ImageCoord imagePt;
137 double achievedPrecision = 0;
138 csm::WarningList warnings;
139 csm::EcefLocus imageLocus;
141 imageLocus = m_model->imageToRemoteImagingLocus(imagePt,
146 catch (csm::Error &e) {
151 if (achievedPrecision > 0.001) {
154 if (!warnings.empty()) {
155 for (csm::Warning warning : warnings) {
156 if (warning.getWarning() == csm::Warning::IMAGE_COORD_OUT_OF_BOUNDS){
163 std::vector<double> obsPosition = {imageLocus.point.x / 1000.0,
164 imageLocus.point.y / 1000.0,
165 imageLocus.point.z / 1000.0};
166 std::vector<double> locusVec = {imageLocus.direction.x,
167 imageLocus.direction.y,
168 imageLocus.direction.z};
177 target()->shape()->setHasIntersection(
false);
182 if(!
target()->shape()->intersectSurface(obsPosition, locusVec)) {
240 if (shape->
name() !=
"Plane") {
249 target()->shape()->clearSurfacePoint();
270 SensorUtilities::GroundPt3D sphericalPt = {decRad, raRad, 1};
271 SensorUtilities::Vec rectPt = SensorUtilities::sphericalToRect(sphericalPt);
273 csm::EcefCoord lookPt = {rectPt.x, rectPt.y, rectPt.z};
274 double achievedPrecision = 0;
275 csm::WarningList warnings;
276 bool validBackProject;
277 csm::ImageCoord imagePt;
280 imagePt = m_model->groundToImage(lookPt, 0.01, &achievedPrecision, &warnings);
284 validBackProject =
SetImage(sample, line);
286 catch (csm::Error &e) {
287 validBackProject =
false;
290 return validBackProject;
313 memcpy(
m_lookB, &lookB[0],
sizeof(
double) * 3);
318 target()->shape()->setHasIntersection(
false);
337 double orgLine =
Line();
338 double orgSample =
Sample();
343 double y =
Line() - orgLine;
344 double x =
Sample() - orgSample;
345 double celestialNorthClockAngle = atan2(-y, x) * 180.0 /
Isis::PI;
346 celestialNorthClockAngle = 90.0 - celestialNorthClockAngle;
348 if (celestialNorthClockAngle < 0.0) {
349 celestialNorthClockAngle += 360.0;
353 return celestialNorthClockAngle;
367 if (!surfacePt.Valid()) {
372 bool validBackProject =
true;
375 csm::ImageCoord imagePt;
376 double achievedPrecision = 0;
377 csm::WarningList warnings;
380 imagePt = m_model->groundToImage(groundPt, 0.01, &achievedPrecision, &warnings);
382 catch (csm::Error &e) {
383 validBackProject =
false;
385 if (achievedPrecision > 0.01) {
386 validBackProject =
false;
388 if (!warnings.empty()) {
389 for (csm::Warning warning : warnings) {
390 if (warning.getWarning() == csm::Warning::IMAGE_COORD_OUT_OF_BOUNDS){
391 validBackProject =
false;
399 csm::EcefLocus imageLocus = m_model->imageToRemoteImagingLocus(imagePt);
400 std::vector<double> sensorPosition = {imageLocus.point.x, imageLocus.point.y, imageLocus.point.z};
402 shape->intersectSurface(surfacePt,
406 validBackProject =
false;
410 if (validBackProject) {
411 m_lookB[0] = imageLocus.direction.x;
412 m_lookB[1] = imageLocus.direction.y;
413 m_lookB[2] = imageLocus.direction.z;
448 return sqrt(imagePartials[0]*imagePartials[0] +
449 imagePartials[2]*imagePartials[2] +
450 imagePartials[4]*imagePartials[4]);
469 return sqrt(imagePartials[1] * imagePartials[1] +
470 imagePartials[3] * imagePartials[3] +
471 imagePartials[5] * imagePartials[5]);
492 double lineRes = sqrt(imagePartials[0]*imagePartials[0] +
493 imagePartials[2]*imagePartials[2] +
494 imagePartials[4]*imagePartials[4]);
495 double sampRes = sqrt(imagePartials[1]*imagePartials[1] +
496 imagePartials[3]*imagePartials[3] +
497 imagePartials[5]*imagePartials[5]);
498 return (sampRes + lineRes) / 2.0;
610 csm::ImageCoord imagePt;
612 csm::EcefCoord sensorPosition = m_model->getSensorPosition(imagePt);
614 std::vector<double> result {
615 sensorPosition.x / 1000.0,
616 sensorPosition.y / 1000.0,
617 sensorPosition.z / 1000.0};
701 vector<double> groundPartials = m_model->computeGroundPartials(groundCoord);
707 groundMatrix(0,0) = groundPartials[0];
708 groundMatrix(0,1) = groundPartials[1];
709 groundMatrix(0,2) = groundPartials[2];
710 groundMatrix(1,0) = groundPartials[3];
711 groundMatrix(1,1) = groundPartials[4];
712 groundMatrix(1,2) = groundPartials[5];
716 vector<double> imagePartials = {imageMatrix(0,0),
722 return imagePartials;
767 vector<double> groundPartials = m_model->computeGroundPartials(groundCoord);
768 return groundPartials;
781 csm::Ellipsoid targetEllipsoid = csm::SettableEllipsoid::getEllipsoid(m_model);
810 csmPixel.line = line - 0.5;
811 csmPixel.samp = sample - 0.5;
825 line = csmPixel.line + 0.5;
826 sample = csmPixel.samp + 0.5;
841 return csm::EcefCoord(groundPt.GetX().meters(),
842 groundPt.GetY().meters(),
843 groundPt.GetZ().meters());
871 csm::EcefVector sunEcefVec = m_model->getIlluminationDirection(groundPt);
875 std::vector<double> sunVec = {
876 (groundPt.x - sunEcefVec.x) / 1000.0,
877 (groundPt.y - sunEcefVec.y) / 1000.0,
878 (groundPt.z - sunEcefVec.z) / 1000.0};
900 csm::EcefVector sunEcefVec = m_model->getIlluminationDirection(groundPt);
904 std::vector<double> sunVec = {
905 (groundPt.x - sunEcefVec.x) / 1000.0,
906 (groundPt.y - sunEcefVec.y) / 1000.0,
907 (groundPt.z - sunEcefVec.z) / 1000.0};
908 return target()->shape()->incidenceAngle(sunVec);
922 std::vector<double> sensorToGround = {
923 groundPoint.GetX().kilometers() - (sensorPosition[0]),
924 groundPoint.GetY().kilometers() - (sensorPosition[1]),
925 groundPoint.GetZ().kilometers() - (sensorPosition[2])};
928 sensorToGround[0] * sensorToGround[0] +
929 sensorToGround[1] * sensorToGround[1] +
930 sensorToGround[2] * sensorToGround[2]);
943 sensorPosition[0] * sensorPosition[0] +
944 sensorPosition[1] * sensorPosition[1] +
945 sensorPosition[2] * sensorPosition[2]);
957 return m_model->getParameterSetIndices(paramSet);
969 std::vector<int> parameterIndices;
970 for (
int i = 0; i < m_model->getNumParameters(); i++) {
971 if (m_model->getParameterType(i) == paramType) {
972 parameterIndices.push_back(i);
975 return parameterIndices;
987 std::vector<int> parameterIndices;
989 for (
int i = 0; i < paramList.size(); i++) {
991 for (
int j = 0; j < m_model->getNumParameters(); j++) {
992 if (QString::compare(QString::fromStdString(m_model->getParameterName(j)).trimmed(),
993 paramList[i].trimmed(),
994 Qt::CaseInsensitive) == 0) {
995 parameterIndices.push_back(j);
1002 failedParams.push_back(paramList[i]);
1006 if (!failedParams.empty()) {
1007 QString msg =
"Failed to find indices for the following parameters [" +
1008 failedParams.join(
",") +
"].";
1011 return parameterIndices;
1022 double currentValue = m_model->getParameterValue(index);
1023 m_model->setParameterValue(index, currentValue + correction);
1034 return m_model->getParameterCovariance(index1, index2);
1038 vector<double> CSMCamera::getSensorPartials(
int index,
SurfacePoint groundPoint) {
1041 std::pair<double, double> partials = m_model->computeSensorPartials(index, groundCoord);
1042 vector<double> partialsVector = {partials.first, partials.second};
1044 return partialsVector;
1056 return QString::fromStdString(m_model->getParameterName(index));
1068 return m_model->getParameterValue(index);
1080 return QString::fromStdString(m_model->getParameterUnits(index));
1090 return QString::fromStdString(m_model->getModelState());
1103 QString msg =
"Setting the image time is not supported for CSM camera models";
1119 QString msg =
"Sub solar point is not supported for CSM camera models";
1132 QString msg =
"Pixel Field of View is not supported for CSM camera models";
1146 QString msg =
"Sun position is not supported for CSM camera models";
1160 QString msg =
"Sun position is not supported for CSM camera models";
1175 QString msg =
"Instrument position is not supported for CSM camera models";
1189 QString msg =
"Body orientation is not supported for CSM camera models";
1204 QString msg =
"Instrument orientation is not supported for CSM camera models";
1218 QString msg =
"Solar longitude is not supported for CSM camera models";
1231 QString msg =
"Solar distance is not supported for CSM camera models";
1243 csm::EcefLocus locus = m_model->imageToRemoteImagingLocus(csm::ImageCoord(
p_childLine,
p_childSample), 0.00001, &precision);
1244 csm::EcefVector v = locus.direction;
1245 SensorUtilities::GroundPt3D sphere_v = SensorUtilities::rectToSpherical({v.x, v.y, v.z});
1246 double lon = sphere_v.lon;
1261 csm::EcefLocus locus = m_model->imageToRemoteImagingLocus(csm::ImageCoord(
p_childLine,
p_childSample), 0.00001, &precision);
1262 csm::EcefVector v = locus.direction;
1263 SensorUtilities::GroundPt3D sphere_v = SensorUtilities::rectToSpherical({v.x, v.y, v.z});
1264 return sphere_v.lat *
RAD2DEG;
1267 json stateAsJson(std::string modelState) {
1269 sanitize(modelState);
1271 std::size_t foundFirst = modelState.find_first_of(
"{");
1272 std::size_t foundLast = modelState.find_last_of(
"}");
1274 if (foundFirst == std::string::npos) {
1277 return json::parse(modelState.begin() + foundFirst, modelState.begin() + foundLast + 1);
1280 void sanitize(std::string &input){
1282 std::replace_if(input.begin(), input.end(), [](
int c){return !::isprint(c);},
'\n');
double AlphaSample(double betaSample)
Returns an alpha sample given a beta sample.
double BetaLine(double alphaLine)
Returns a beta line given an alpha line.
double AlphaLine(double betaLine)
Returns an alpha line given a beta line.
double BetaSample(double alphaSample)
Returns a beta sample given an alpha sample.
double degrees() const
Get the angle in units of Degrees.
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
int Size() const
Accessor method that returns the number of bytes in the blob data.
char * getBuffer()
Get the internal data buff of the Blob.
PvlObject & Label()
Accessor method that returns a PvlObject containing the Blob label.
QString getModelState() const
Get the CSM Model state string to re-create the CSM Model.
virtual void computeSolarLongitude(iTime et)
Computes the solar longitude for the given ephemeris time.
virtual double DetectorResolution()
Compute the detector resolution in meters per pixel for the current set point.
std::vector< int > getParameterIndices(csm::param::Set paramSet) const
Get the indices of the parameters that belong to a set.
CSMCamera(Cube &cube)
Constructor for an ISIS Camera model that uses a Community Sensor Model (CSM) for the principal trans...
void setTarget(Pvl label)
Set the Target object for the camera model.
QString getParameterUnits(int index)
Get the units of the parameter at a particular index.
void init(Cube &cube, QString pluginName, QString modelName, QString stateString)
Init method which performs most of the setup for the CSM Camera Model inside ISIS.
double getParameterCovariance(int index1, int index2)
Get the covariance between two parameters.
virtual bool SetImage(const double sample, const double line)
Set the image sample and line for the Camera Model and then compute the corresponding image time,...
virtual QList< QPointF > PixelIfovOffsets()
Returns the pixel ifov offsets from center of pixel.
virtual void setTime(const iTime &time)
Set the time and update the sensor position and orientation.
virtual double parentLine() const
Returns the currently set parent line for the camera model.
virtual SpicePosition * sunPosition() const
Get the SpicePosition object that contains the state information for the sun in J2000.
double getParameterValue(int index)
Get the value of a parameter.
virtual double SampleResolution()
Compute the sample resolution in meters per pixel for the current set point.
virtual void subSpacecraftPoint(double &lat, double &lon)
Get the latitude and longitude of the sub-spacecraft point at the currently set time.
virtual bool SetUniversalGround(const double latitude, const double longitude)
Set the latitude and longitude for the Camera Model and then compute the corresponding image time,...
virtual double LineResolution()
Compute the line resolution in meters per pixel for the current set point.
virtual double ObliqueLineResolution(bool useLocal=true)
Compute the oblique line resolution in meters per pixel for the current set point.
void csmToIsisPixel(csm::ImageCoord csmPixel, double &line, double &sample) const
Convert a CSM pixel coordinate to an ISIS pixel coordinate.
virtual double IncidenceAngle() const
Compute the incidence angle at the currently set ground point.
virtual double RightAscension()
Computes the Right Ascension of the currently set image coordinate.
csm::EcefCoord isisToCsmGround(const SurfacePoint &groundPt) const
Convert an ISIS ground point into a CSM ground point.
virtual std::vector< double > ImagePartials()
Compute the partial derivatives of the ground point with respect to the line and sample at the curren...
QString getParameterName(int index)
Get the name of the parameter.
virtual double CelestialNorthClockAngle()
Computes the celestial north clock angle at the current line/sample or ra/dec.
SurfacePoint csmToIsisGround(const csm::EcefCoord &groundPt) const
Convert a CSM ground point into an ISIS ground point.
virtual double Declination()
Computes the Declination of the currently set image coordinate.
void applyParameterCorrection(int index, double correction)
Adjust the value of a parameter.
virtual void subSolarPoint(double &lat, double &lon)
Returns the sub-solar latitude/longitude in universal coordinates (0-360 positive east,...
virtual std::vector< double > GroundPartials()
Compute the partial derivatives of the sample, line with respect to the x, y, z coordinates of the gr...
virtual bool SetRightAscensionDeclination(const double ra, const double dec)
Given the ra/dec compute the look direction.
virtual SpicePosition * instrumentPosition() const
Get the SpicePosition object the contains the state information for the sensor in J2000.
virtual double PhaseAngle() const
Compute the phase angle at the currently set ground point.
virtual double ObliqueSampleResolution(bool useLocal=true)
Compute the oblique sample resolution in meters per pixel for the current set point.
std::vector< double > sensorPositionBodyFixed() const
Get the position of the sensor in the body fixed coordinate system at the currently set time.
void isisToCsmPixel(double line, double sample, csm::ImageCoord &csmPixel) const
The reference time that all model image times are relative to.
virtual double EmissionAngle() const
Compute the emission angle at the currently set ground point.
virtual void instrumentBodyFixedPosition(double p[3]) const
Get the position of the sensor in the body fixed coordinate system at the currently set time.
virtual SpiceRotation * instrumentRotation() const
Get the SpiceRotation object the contains the orientation of the sensor relative to J2000.
virtual double parentSample() const
Returns the currently set parent sample for the camera model.
virtual double ObliqueDetectorResolution(bool useLocal=true)
Compute the oblique detector resolution in meters per pixel for the current set point.
virtual SpiceRotation * bodyRotation() const
Get the SpiceRotation object the contains the orientation of the target body relative to J2000.
virtual double SolarDistance() const
Computes the distance to the sun from the currently set ground point.
iTime m_refTime
CSM sensor model.
virtual double SlantDistance() const
Compute the slant distance from the sensor to the ground point at the currently set time.
virtual bool SetGround(Latitude latitude, Longitude longitude)
Set the latitude and longitude for the Camera Model and then compute the corresponding image time,...
virtual bool SetLookDirection(const std::vector< double > lookB)
Sets the look direction of the spacecraft.
virtual double targetCenterDistance() const
Calculates and returns the distance from the spacecraft to the target center at the currently set tim...
QString m_spacecraftNameLong
Full spacecraft name.
AlphaCube * p_alphaCube
A pointer to the AlphaCube.
virtual double Line() const
Returns the current line number.
double RaDecResolution()
Returns the RaDec resolution.
virtual double Sample() const
Returns the current sample number.
double p_childSample
Sample value for child.
bool p_pointComputed
Flag showing if Sample/Line has been computed.
QString m_instrumentNameShort
Shortened instrument name.
QString m_spacecraftNameShort
Shortened spacecraft name.
double p_childLine
Line value for child.
QString m_instrumentNameLong
Full instrument name.
IO Handler for Isis Cubes.
void read(Blob &blob, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >()) const
This method will read data from the specified Blob object.
virtual QString fileName() const
Returns the opened cube's filename.
Pvl * label() const
Returns a pointer to the IsisLabel object associated with the cube.
Displacement is a signed length, usually in meters.
@ Kilometers
The distance is being specified in kilometers.
@ Meters
The distance is being specified in meters.
Distance measurement, usually in meters.
bool isValid() const
Test if this distance has been initialized or not.
@ Kilometers
The distance is being specified in kilometers.
@ Meters
The distance is being specified in meters.
@ 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.
This class is designed to encapsulate the concept of a Latitude.
static Matrix pseudoinverse(const Matrix &matrix)
Returns the pseudoinverse of a matrix.
boost::numeric::ublas::matrix< double > Matrix
Definition for an Isis::LinearAlgebra::Matrix of doubles.
This class is designed to encapsulate the concept of a Longitude.
Container for cube-like labels.
Contains Pvl Groups and Pvl Objects.
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
virtual SurfacePoint GetSurfacePoint() const
Returns the surface point (most efficient accessor).
SpiceDouble m_lookB[3]
Look direction in body fixed.
bool HasSurfaceIntersection() const
Returns if the last call to either SetLookDirection or SetUniversalGround had a valid intersection wi...
bool m_newLookB
flag to indicate we need to recompute ra/dec
Distance LocalRadius() const
Returns the local radius at the intersection point.
Define shapes and provide utilities for Isis targets.
virtual void clearSurfacePoint()
Clears or resets the current surface point.
bool hasIntersection()
Returns intersection status.
void setHasIntersection(bool b)
Sets the flag to indicate whether this ShapeModel has an intersection.
QString name() const
Gets the shape name.
Target * m_target
Target of the observation.
void radii(Distance r[3]) const
Returns the radii of the body in km.
virtual Target * target() const
Returns a pointer to the target object.
iTime * m_et
Ephemeris time (read NAIF documentation for a detailed description)
Obtain SPICE position information for a body.
Obtain SPICE rotation information for a body.
This class defines a body-fixed surface point.
Latitude GetLatitude() const
Return the body-fixed latitude for the surface point.
Longitude GetLongitude() const
Return the body-fixed longitude for the surface point.
This class is used to create and store valid Isis targets.
Parse and return pieces of a time string.
This is free and unencumbered software released into the public domain.
const double DEG2RAD
Multiplier for converting from degrees to radians.
const double Null
Value for an Isis Null pixel.
const double RAD2DEG
Multiplier for converting from radians to degrees.
const double PI
The mathematical constant PI.
Namespace for the standard library.