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
Convert an ISIS pixel coordinate to a CSM pixel coordinate.
 
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.