From 5ae463d145d2d3b93002d4c09745b0adc871bcb7 Mon Sep 17 00:00:00 2001 From: jay Date: Wed, 26 Apr 2017 13:44:48 -0700 Subject: [PATCH] Fixes #1, #2, #4 and improves test coverage --- include/mdis/MdisNacSensorModel.h | 41 ++- include/mdis/MdisPlugin.h | 11 + src/MdisPlugin.cpp | 261 ++++++++++++++++--- src/MdisSensorModel.cpp | 409 ++++++++++++++++++++---------- tests/CW1071364100B_IU_5.json | 9 +- tests/EN1007907102M.json | 5 +- tests/test_mdis_csm.py | 74 +++++- usgscam/mdis.pxd | 20 +- usgscam/mdis.pyx | 41 ++- 9 files changed, 677 insertions(+), 194 deletions(-) diff --git a/include/mdis/MdisNacSensorModel.h b/include/mdis/MdisNacSensorModel.h index 6f72991..e16b86e 100644 --- a/include/mdis/MdisNacSensorModel.h +++ b/include/mdis/MdisNacSensorModel.h @@ -1,3 +1,4 @@ + #ifndef MdisNacSensorModel_h #define MdisNacSensorModel_h @@ -26,6 +27,12 @@ class MdisNacSensorModel : public csm::RasterGM { double *achievedPrecision=NULL, csm::WarningList *warnings=NULL) const; + virtual csm::ImageCoord groundToImage(const csm::EcefCoord& ground_pt, + const std::vector& adjustments, + double desired_precision=0.001, + double* achieved_precision=NULL, + csm::WarningList* warnings=NULL) const; + /** * This function determines if a sample, line intersects the target body and if so, where * this intersection occurs in body-fixed coordinates. @@ -279,9 +286,6 @@ class MdisNacSensorModel : public csm::RasterGM { static const std::string _SENSOR_MODEL_NAME; - - - protected: virtual bool setFocalPlane(double dx,double dy,double &undistortedX,double &undistortedY) const; @@ -289,17 +293,26 @@ class MdisNacSensorModel : public csm::RasterGM { virtual void distortionJacobian(double x, double y, double &Jxx, double &Jxy, double &Jyx, double &Jyy) const; + private: + // Input parameters + static const int m_numParameters; + static const std::string m_parameterName[]; + std::vector m_currentParameterValue; + std::vector m_currentParameterCovariance; + std::vector m_noAdjustments; + std::vector m_odtX; + std::vector m_odtY; + + static const int _NUM_STATE_KEYWORDS; + static const std::string _STATE_KEYWORD[]; + double m_transX[3]; double m_transY[3]; double m_majorAxis; double m_minorAxis; - double m_omega; - double m_phi; - double m_kappa; double m_focalLength; - double m_spacecraftPosition[3]; double m_spacecraftVelocity[3]; double m_sunPosition[3]; double m_ccdCenter[2]; @@ -311,8 +324,6 @@ class MdisNacSensorModel : public csm::RasterGM { double m_ifov; std::string m_instrumentID; double m_focalLengthEpsilon; - double m_odtX[10]; - double m_odtY[10]; double m_originalHalfLines; std::string m_spacecraftName; double m_pixelPitch; @@ -323,12 +334,16 @@ class MdisNacSensorModel : public csm::RasterGM { double m_boresight[3]; int m_nLines; int m_nSamples; + int m_nParameters; + double getValue(int index,const std::vector &adjustments) const; void calcRotationMatrix(double m[3][3]) const; - void losEllipsoidIntersect (double& height, double& xc, - double& yc, double& zc, - double& xl, double& yl, - double& zl, + void calcRotationMatrix(double m[3][3], const std::vector &adjustments) const; + + void losEllipsoidIntersect (const double& height,const double& xc, + const double& yc, const double& zc, + const double& xl, const double& yl, + const double& zl, double& x,double& y, double& z) const; }; diff --git a/include/mdis/MdisPlugin.h b/include/mdis/MdisPlugin.h index ce098a8..a483faa 100644 --- a/include/mdis/MdisPlugin.h +++ b/include/mdis/MdisPlugin.h @@ -52,6 +52,17 @@ class MDIS_EXPORT_API MdisPlugin : public csm::Plugin { csm::WarningList *warnings = NULL) const; // TODO when implementing, add any other necessary members. + +private: + static const MdisPlugin m_registeredPlugin; + static const std::string _PLUGIN_NAME; + static const std::string _MANUFACTURER_NAME; + static const std::string _RELEASE_DATE; + static const int _N_SENSOR_MODELS; + static const int _NUM_ISD_KEYWORDS; + static const std::string _ISD_KEYWORD[]; + static const int _NUM_STATE_KEYWORDS; + static const std::string _STATE_KEYWORD[]; }; #endif diff --git a/src/MdisPlugin.cpp b/src/MdisPlugin.cpp index 27a220b..554d5d5 100644 --- a/src/MdisPlugin.cpp +++ b/src/MdisPlugin.cpp @@ -1,4 +1,5 @@ #include "MdisPlugin.h" +#include "MdisNacSensorModel.h" #include #include @@ -8,10 +9,96 @@ #include #include -#include "MdisNacSensorModel.h" - -// Create static instance of self for plugin registration to work with csm::Plugin -//const MdisPlugin MdisPlugin::m_registeredPlugin; +#include + + +using json = nlohmann::json; + +// Declaration of static variables +const std::string MdisPlugin::_PLUGIN_NAME = "UsgsAstroFrameMdisPluginCSM"; +const std::string MdisPlugin::_MANUFACTURER_NAME = "UsgsAstrogeology"; +const std::string MdisPlugin::_RELEASE_DATE = "20170425"; +const int MdisPlugin::_N_SENSOR_MODELS = 1; + +const int MdisPlugin::_NUM_ISD_KEYWORDS = 36; +const std::string MdisPlugin::_ISD_KEYWORD[] = +{ + "model_name", + "starting_detector_sample", + "starting_detector_line", + "target_name", + "ifov", + "instrument_id", + "focal_length", + "focal_length_epsilon", + "x_sensor_origin", + "y_sensor_origin", + "z_sensor_origin", + "x_sensor_velocity", + "y_sensor_velocity", + "z_sensor_velocity", + "x_sun_position", + "y_sun_position", + "z_sun_position", + "omega", + "phi", + "kappa", + "odt_x", + "odt_y", + "ccd_center", + "original_half_lines", + "original_half_samples", + "spacecraft_name", + "pixel_pitch", + "itrans_line", + "itrans_sample", + "ephemeris_time", + "boresight", + "nlines", + "nsamples", + "transx", + "transy", + "semi_major_axis", + "semi_minor_axis" +}; +const int MdisPlugin::_NUM_STATE_KEYWORDS = 30; +const std::string MdisPlugin::_STATE_KEYWORD[] = +{ + "m_focalLength", + "m_iTransS", + "m_iTransL", + "m_boresight", + "m_transX", + "m_transY", + "m_majorAxis", + "m_minorAxis", + "m_spacecraftVelocity", + "m_sunPosition", + "m_startingDetectorSample", + "m_startingDetectorLine", + "m_targetName", + "m_ifov", + "m_instrumentID", + "m_focalLengthEpsilon", + "m_ccdCenter", + "m_line_pp", + "m_sample_pp", + "m_odtX", + "m_odtY", + "m_originalHalfLines", + "m_originalHalfSamples", + "m_spacecraftName", + "m_pixelPitch", + "m_ephemerisTime", + "m_nLines", + "m_nSamples", + "m_currentParameterValue", + "m_currentParameterCovariance" +}; + + +// Static Instance of itself +const MdisPlugin MdisPlugin::m_registeredPlugin; MdisPlugin::MdisPlugin() { } @@ -22,27 +109,27 @@ MdisPlugin::~MdisPlugin() { std::string MdisPlugin::getPluginName() const { - return "UsgsAstroFrameMdisPluginCSM"; + return _PLUGIN_NAME; } std::string MdisPlugin::getManufacturer() const { - return "UsgsAstrogeology"; + return _MANUFACTURER_NAME; } std::string MdisPlugin::getReleaseDate() const { - return "TBA"; + return _RELEASE_DATE; } csm::Version MdisPlugin::getCsmVersion() const { - return csm::Version(3, 1, 0); + return CURRENT_CSM_VERSION; } size_t MdisPlugin::getNumModels() const { - return 1; + return _N_SENSOR_MODELS; } @@ -53,12 +140,11 @@ std::string MdisPlugin::getModelName(size_t modelIndex) const { std::string MdisPlugin::getModelFamily(size_t modelIndex) const { - return "Raster"; + return CSM_RASTER_FAMILY; } csm::Version MdisPlugin::getModelVersion(const std::string &modelName) const { - return csm::Version(1, 0, 0); } @@ -66,25 +152,99 @@ csm::Version MdisPlugin::getModelVersion(const std::string &modelName) const { bool MdisPlugin::canModelBeConstructedFromState(const std::string &modelName, const std::string &modelState, csm::WarningList *warnings) const { - return false; + bool constructible = true; + + // Get the model name from the model state + std::string model_name_from_state; + model_name_from_state = getModelNameFromModelState(modelState, warnings); + + // Check that the plugin supports the model + if (modelName != model_name_from_state || + modelName != MdisNacSensorModel::_SENSOR_MODEL_NAME){ + constructible = false; + } + + // Check that the necessary keys are there (this does not chek values at all.) + auto state = json::parse(modelState); + for(auto &key : _STATE_KEYWORD){ + if (state.find(key) == state.end()){ + constructible = false; + } + } + return constructible; } bool MdisPlugin::canModelBeConstructedFromISD(const csm::Isd &imageSupportData, const std::string &modelName, csm::WarningList *warnings) const { - - if (modelName != MdisNacSensorModel::_SENSOR_MODEL_NAME) { - return false; - } - - return true; + return canISDBeConvertedToModelState(imageSupportData, modelName, warnings); } -csm::Model *MdisPlugin::constructModelFromState(const std::string&modelState, +csm::Model *MdisPlugin::constructModelFromState(const std::string& modelState, csm::WarningList *warnings) const { - return NULL; + csm::Model *sensor_model = 0; + + // Get the sensor model name from the sensor model state + std::string model_name_from_state = getModelNameFromModelState(modelState); + + if (model_name_from_state != MdisNacSensorModel::_SENSOR_MODEL_NAME){ + csm::Error::ErrorType aErrorType = csm::Error::INVALID_SENSOR_MODEL_STATE; + std::string aMessage = "Model name from state is not recognized."; + std::string aFunction = "MdisPlugin::constructModelFromState()"; + throw csm::Error(aErrorType, aMessage, aFunction); + } + + // Check that all of the necessary keys are included + canModelBeConstructedFromState(model_name_from_state, modelState); + + // Create the model from the state + MdisNacSensorModel* mdsensor_model = new MdisNacSensorModel(); + + auto state = json::parse(modelState); + + mdsensor_model->m_focalLength = state["m_focalLength"]; + mdsensor_model->m_majorAxis = state["m_majorAxis"]; + mdsensor_model->m_minorAxis = state["m_minorAxis"]; + mdsensor_model->m_startingDetectorLine = state["m_startingDetectorLine"]; + mdsensor_model->m_startingDetectorSample = state["m_startingDetectorSample"]; + mdsensor_model->m_ifov = state["m_ifov"]; + mdsensor_model->m_instrumentID = state["m_instrumentID"]; + mdsensor_model->m_focalLengthEpsilon = state["m_focalLengthEpsilon"]; + mdsensor_model->m_line_pp = state["m_line_pp"]; + mdsensor_model->m_sample_pp = state["m_sample_pp"]; + mdsensor_model->m_originalHalfLines = state["m_originalHalfLines"]; + mdsensor_model->m_originalHalfSamples = state["m_originalHalfSamples"]; + mdsensor_model->m_spacecraftName = state["m_spacecraftName"]; + mdsensor_model->m_pixelPitch = state["m_pixelPitch"]; + mdsensor_model->m_ephemerisTime = state["m_ephemerisTime"]; + mdsensor_model->m_nLines = state["m_nLines"]; + mdsensor_model->m_nSamples = state["m_nSamples"]; + + mdsensor_model->m_ccdCenter[0] = state["m_ccdCenter"][0]; + mdsensor_model->m_ccdCenter[1] = state["m_ccdCenter"][1]; + + for (int i=0;i<3;i++){ + mdsensor_model->m_boresight[i] = state["m_boresight"][i]; + mdsensor_model->m_iTransS[i] = state["m_iTransS"][i]; + mdsensor_model->m_iTransL[i] = state["m_iTransL"][i]; + mdsensor_model->m_transX[i] = state["m_transX"][i]; + mdsensor_model->m_transY[i] = state["m_transY"][i]; + mdsensor_model->m_spacecraftVelocity[i] = state["m_spacecraftVelocity"][i]; + mdsensor_model->m_sunPosition[i] = state["m_sunPosition"][i]; + } + + // Having types as vectors, instead of arrays makes interoperability with + // the JSON library very easy. + mdsensor_model->m_currentParameterValue = state["m_currentParameterValue"].get>(); + mdsensor_model->m_odtX = state["m_odtX"].get>(); + mdsensor_model->m_odtY = state["m_odtY"].get>(); + + mdsensor_model->m_currentParameterCovariance = state["m_currentParameterCovariance"].get>(); + +sensor_model = mdsensor_model; +return sensor_model; } @@ -124,11 +284,11 @@ csm::Model *MdisPlugin::constructModelFromISD(const csm::Isd &imageSupportData, sensorModel->m_focalLengthEpsilon = atof(imageSupportData.param("focal_length_epsilon").c_str()); - sensorModel->m_spacecraftPosition[0] = + sensorModel->m_currentParameterValue[0] = atof(imageSupportData.param("x_sensor_origin").c_str()); - sensorModel->m_spacecraftPosition[1] = + sensorModel->m_currentParameterValue[1] = atof(imageSupportData.param("y_sensor_origin").c_str()); - sensorModel->m_spacecraftPosition[2] = + sensorModel->m_currentParameterValue[2] = atof(imageSupportData.param("z_sensor_origin").c_str()); if (imageSupportData.param("x_sensor_origin") == "") { missingKeywords.push_back("x_sensor_origin"); @@ -156,9 +316,9 @@ csm::Model *MdisPlugin::constructModelFromISD(const csm::Isd &imageSupportData, atof(imageSupportData.param("z_sun_position").c_str()); // sun position is not strictly necessary, but is required for getIlluminationDirection. - sensorModel->m_omega = atof(imageSupportData.param("omega").c_str()); - sensorModel->m_phi = atof(imageSupportData.param("phi").c_str()); - sensorModel->m_kappa = atof(imageSupportData.param("kappa").c_str()); + sensorModel->m_currentParameterValue[3] = atof(imageSupportData.param("omega").c_str()); + sensorModel->m_currentParameterValue[4] = atof(imageSupportData.param("phi").c_str()); + sensorModel->m_currentParameterValue[5] = atof(imageSupportData.param("kappa").c_str()); if (imageSupportData.param("omega") == "") { missingKeywords.push_back("omega"); } @@ -311,19 +471,62 @@ csm::Model *MdisPlugin::constructModelFromISD(const csm::Isd &imageSupportData, std::string MdisPlugin::getModelNameFromModelState(const std::string &modelState, csm::WarningList *warnings) const { - return "state"; + std::string name; + auto state = json::parse(modelState); + if(state.find("model_name") != state.end()){ + name = state["model_name"]; + } + else{ + csm::Error::ErrorType aErrorType = csm::Error::INVALID_SENSOR_MODEL_STATE; + std::string aMessage = "No 'model_name' key in the model state object."; + std::string aFunction = "MdisPlugin::getModelNameFromModelState"; + csm::Error csmErr(aErrorType, aMessage, aFunction); + throw(csmErr); + } + + if (name != MdisNacSensorModel::_SENSOR_MODEL_NAME){ + csm::Error::ErrorType aErrorType = csm::Error::SENSOR_MODEL_NOT_SUPPORTED; + std::string aMessage = "Sensor model not supported."; + std::string aFunction = "MdisPlugin::getModelNameFromModelState()"; + csm::Error csmErr(aErrorType, aMessage, aFunction); + throw(csmErr); + } + + + return MdisNacSensorModel::_SENSOR_MODEL_NAME; } bool MdisPlugin::canISDBeConvertedToModelState(const csm::Isd &imageSupportData, const std::string &modelName, csm::WarningList *warnings) const { - return false; + bool convertible = true; + if (modelName !=MdisNacSensorModel::_SENSOR_MODEL_NAME){ + convertible = false; + } + + std::string value; + for(auto &key : _ISD_KEYWORD){ + value = imageSupportData.param(key); + if (value.empty()){ + convertible = false; + } + } + return convertible; } std::string MdisPlugin::convertISDToModelState(const csm::Isd &imageSupportData, const std::string &modelName, csm::WarningList *warnings) const { - return "state"; + csm::Model* sensor_model = constructModelFromISD( + imageSupportData, modelName); + + if (sensor_model == 0){ + csm::Error::ErrorType aErrorType = csm::Error::ISD_NOT_SUPPORTED; + std::string aMessage = "ISD not supported: "; + std::string aFunction = "MdisPlugin::convertISDToModelState()"; + throw csm::Error(aErrorType, aMessage, aFunction); + } + return sensor_model->getModelState(); } diff --git a/src/MdisSensorModel.cpp b/src/MdisSensorModel.cpp index 07057df..cf2a2b3 100644 --- a/src/MdisSensorModel.cpp +++ b/src/MdisSensorModel.cpp @@ -4,16 +4,60 @@ #include #include -#include #include -using json = nlohmann::json; +#include + +using json = nlohmann::json; using namespace std; +// Declaration of static variables const std::string MdisNacSensorModel::_SENSOR_MODEL_NAME = "ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so"; - - +const int MdisNacSensorModel::m_numParameters = 6; +const std::string MdisNacSensorModel::m_parameterName[] = { + "X Sensor Position (m)", // 0 + "Y Sensor Position (m)", // 1 + "Z Sensor Position (m)", // 2 + "Omega (radians)", // 3 + "Phi (radians)", // 4 + "Kappa (radians)" // 5 +}; + +const int MdisNacSensorModel::_NUM_STATE_KEYWORDS = 30; +const std::string MdisNacSensorModel::_STATE_KEYWORD[] = +{ + "m_focalLength", + "m_iTransS", + "m_iTransL", + "m_boresight", + "m_transX", + "m_transY", + "m_majorAxis", + "m_minorAxis", + "m_spacecraftVelocity", + "m_sunPosition", + "m_startingDetectorSample", + "m_startingDetectorLine", + "m_targetName", + "m_ifov", + "m_instrumentID", + "m_focalLengthEpsilon", + "m_ccdCenter", + "m_line_pp", + "m_sample_pp", + "m_odtX", + "m_odtY", + "m_originalHalfLines", + "m_originalHalfSamples", + "m_spacecraftName", + "m_pixelPitch", + "m_ephemerisTime", + "m_nLines", + "m_nSamples", + "m_currentParameterValue", + "m_currentParameterCovariance" +}; MdisNacSensorModel::MdisNacSensorModel() { @@ -35,15 +79,8 @@ MdisNacSensorModel::MdisNacSensorModel() { m_majorAxis = 0.0; m_minorAxis = 0.0; - m_omega = 0.0; - m_phi = 0.0; - m_kappa = 0.0; m_focalLength = 0.0; - m_spacecraftPosition[0] = 0.0; - m_spacecraftPosition[1] = 0.0; - m_spacecraftPosition[2] = 0.0; - m_spacecraftVelocity[0] = 0.0; m_spacecraftVelocity[1] = 0.0; m_spacecraftVelocity[2] = 0.0; @@ -65,27 +102,8 @@ MdisNacSensorModel::MdisNacSensorModel() { m_line_pp = 0.0; m_sample_pp = 0.0; - m_odtX[0] = 0.0; - m_odtX[1] = 0.0; - m_odtX[2] = 0.0; - m_odtX[3] = 0.0; - m_odtX[4] = 0.0; - m_odtX[5] = 0.0; - m_odtX[6] = 0.0; - m_odtX[7] = 0.0; - m_odtX[8] = 0.0; - m_odtX[9] = 0.0; - - m_odtY[0] = 0.0; - m_odtY[1] = 0.0; - m_odtY[2] = 0.0; - m_odtY[3] = 0.0; - m_odtY[4] = 0.0; - m_odtY[5] = 0.0; - m_odtY[6] = 0.0; - m_odtY[7] = 0.0; - m_odtY[8] = 0.0; - m_odtY[9] = 0.0; + m_odtX.assign(10, 0.0); + m_odtY.assign(10, 0.0); m_originalHalfLines = 0.0; m_spacecraftName = ""; @@ -107,54 +125,84 @@ MdisNacSensorModel::MdisNacSensorModel() { m_nLines = 0; m_nSamples = 0; + + m_currentParameterValue.assign(m_numParameters, 0.0); + m_currentParameterCovariance.assign(m_numParameters*m_numParameters,0.0); + m_noAdjustments.assign(m_numParameters,0.0); } MdisNacSensorModel::~MdisNacSensorModel() {} + +/** + * @brief MdisNacSensorModel::groundToImage + * @param groundPt + * @param desiredPrecision + * @param achievedPrecision + * @param warnings + * @return Returns coordinate in the image corresponding to the ground point + * without bundle adjustment correction. + */ csm::ImageCoord MdisNacSensorModel::groundToImage(const csm::EcefCoord &groundPt, double desiredPrecision, double *achievedPrecision, csm::WarningList *warnings) const { -double xl, yl, zl; -xl = m_spacecraftPosition[0]; -yl = m_spacecraftPosition[1]; -zl = m_spacecraftPosition[2]; + return groundToImage(groundPt,m_noAdjustments,desiredPrecision,achievedPrecision,warnings); +} -double x, y, z; -x = groundPt.x; -y = groundPt.y; -z = groundPt.z; -double xo, yo, zo; -xo = xl - x; -yo = yl - y; -zo = zl - z; +/** + * @brief MdisNacSensorModel::groundToImage + * @param groundPt + * @param adjustments + * @param desired_precision + * @param achieved_precision + * @param warnings + * @return Returns coordinate in the image corresponding to the ground point. + * This function applies bundle adjustments to the final value. + */ +csm::ImageCoord MdisNacSensorModel::groundToImage( + const csm::EcefCoord& groundPt, + const std::vector& adjustments, + double desired_precision, + double* achieved_precision, + csm::WarningList* warnings ) const { -double f; -f = m_focalLength; + double x, y, z; + x = groundPt.x; + y = groundPt.y; + z = groundPt.z; -// Camera rotation matrix -double m[3][3]; -calcRotationMatrix(m); + double xo, yo, zo; + xo = x - getValue(0,adjustments); + yo = y - getValue(1,adjustments); + zo = z - getValue(2,adjustments); + + double f; + f = m_focalLength; + + // Camera rotation matrix + double m[3][3]; + calcRotationMatrix(m,adjustments); -// Sensor position -double undistortedx, undistortedy, denom; -denom = m[0][2] * xo + m[1][2] * yo + m[2][2] * zo; -undistortedx = (f * (m[0][0] * xo + m[1][0] * yo + m[2][0] * zo)/denom) + m_sample_pp; //m_sample_pp like this assumes mm -undistortedy = (f * (m[0][1] * xo + m[1][1] * yo + m[2][1] * zo)/denom) + m_line_pp; + // Sensor position + double undistortedx, undistortedy, denom; + denom = m[0][2] * xo + m[1][2] * yo + m[2][2] * zo; + undistortedx = (f * (m[0][0] * xo + m[1][0] * yo + m[2][0] * zo)/denom) + m_sample_pp; //m_sample_pp like this assumes mm + undistortedy = (f * (m[0][1] * xo + m[1][1] * yo + m[2][1] * zo)/denom) + m_line_pp; -// Apply the distortion to the line/sample location and then convert back to line/sample -double distortedx, distortedy; -distortionFunction(undistortedx, undistortedy, distortedx, distortedy); + // Apply the distortion to the line/sample location and then convert back to line/sample + double distortedx, distortedy; + distortionFunction(undistortedx, undistortedy, distortedx, distortedy); -//Convert distorted mm into line/sample -double sample, line; -sample = m_iTransS[0] + m_iTransS[1] * distortedx + m_iTransS[2] * distortedx + m_ccdCenter[0] - 0.5; -line = m_iTransL[0] + m_iTransL[1] * distortedy + m_iTransL[2] * distortedy + m_ccdCenter[0] - 0.5; + //Convert distorted mm into line/sample + double sample, line; + sample = m_iTransS[0] + m_iTransS[1] * distortedx + m_iTransS[2] * distortedx + m_ccdCenter[0] - 0.5; + line = m_iTransL[0] + m_iTransL[1] * distortedy + m_iTransL[2] * distortedy + m_ccdCenter[0] - 0.5; -return csm::ImageCoord(line, sample); + return csm::ImageCoord(line, sample); } @@ -178,8 +226,6 @@ csm::EcefCoord MdisNacSensorModel::imageToGround(const csm::ImageCoord &imagePt, double sample = imagePt.samp; double line = imagePt.line; - std::cout << "Sample: " << sample << " Line: "<< line << std::endl; - //Here is where we should be able to apply an adjustment to opk double m[3][3]; calcRotationMatrix(m); @@ -211,9 +257,9 @@ csm::EcefCoord MdisNacSensorModel::imageToGround(const csm::ImageCoord &imagePt, double x, y, z; double xc, yc, zc; - xc = m_spacecraftPosition[0]; - yc = m_spacecraftPosition[1]; - zc = m_spacecraftPosition[2]; + xc = m_currentParameterValue[0]; + yc = m_currentParameterValue[1]; + zc = m_currentParameterValue[2]; // Intersect with some height about the ellipsoid. losEllipsoidIntersect(height, xc, yc, zc, xl, yl, zl, x, y, z); @@ -221,6 +267,7 @@ csm::EcefCoord MdisNacSensorModel::imageToGround(const csm::ImageCoord &imagePt, return csm::EcefCoord(x, y, z); } + csm::EcefCoordCovar MdisNacSensorModel::imageToGround(const csm::ImageCoordCovar &imagePt, double height, double heightVariance, double desiredPrecision, double *achievedPrecision, @@ -230,6 +277,7 @@ csm::EcefCoordCovar MdisNacSensorModel::imageToGround(const csm::ImageCoordCovar "MdisNacSensorModel::imageToGround"); } + csm::EcefLocus MdisNacSensorModel::imageToProximateImagingLocus(const csm::ImageCoord &imagePt, const csm::EcefCoord &groundPt, double desiredPrecision, @@ -275,7 +323,7 @@ csm::EcefLocus MdisNacSensorModel::imageToRemoteImagingLocus(const csm::ImageCoo lookB[2] / mag }; - return csm::EcefLocus(m_spacecraftPosition[0], m_spacecraftPosition[1], m_spacecraftPosition[2], + return csm::EcefLocus(m_currentParameterValue[0], m_currentParameterValue[1], m_currentParameterValue[2], lookBUnit[0], lookBUnit[1], lookBUnit[2]); } @@ -288,6 +336,7 @@ csm::ImageCoord MdisNacSensorModel::getImageStart() const { return start; } + csm::ImageVector MdisNacSensorModel::getImageSize() const { csm::ImageVector size; @@ -296,6 +345,7 @@ csm::ImageVector MdisNacSensorModel::getImageSize() const { return size; } + std::pair MdisNacSensorModel::getValidImageRange() const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -303,6 +353,7 @@ std::pair MdisNacSensorModel::getValidImageRan "MdisNacSensorModel::getValidImageRange"); } + std::pair MdisNacSensorModel::getValidHeightRange() const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -310,6 +361,7 @@ std::pair MdisNacSensorModel::getValidHeightRange() const { "MdisNacSensorModel::getValidHeightRange"); } + csm::EcefVector MdisNacSensorModel::getIlluminationDirection(const csm::EcefCoord &groundPt) const { // ground (body-fixed) - sun (body-fixed) gives us the illumination direction. return csm::EcefVector { @@ -319,6 +371,7 @@ csm::EcefVector MdisNacSensorModel::getIlluminationDirection(const csm::EcefCoor }; } + double MdisNacSensorModel::getImageTime(const csm::ImageCoord &imagePt) const { // check if the image point is in range @@ -335,16 +388,18 @@ double MdisNacSensorModel::getImageTime(const csm::ImageCoord &imagePt) const { } } + csm::EcefCoord MdisNacSensorModel::getSensorPosition(const csm::ImageCoord &imagePt) const { + // check if the image point is in range if (imagePt.samp >= m_startingDetectorSample && imagePt.samp <= (m_startingDetectorSample + m_nSamples) && imagePt.line >= m_startingDetectorSample && imagePt.line <= (m_startingDetectorLine + m_nLines)) { csm::EcefCoord sensorPosition; - sensorPosition.x = m_spacecraftPosition[0]; - sensorPosition.y = m_spacecraftPosition[1]; - sensorPosition.z = m_spacecraftPosition[2]; + sensorPosition.x = m_currentParameterValue[0]; + sensorPosition.y = m_currentParameterValue[1]; + sensorPosition.z = m_currentParameterValue[2]; return sensorPosition; } @@ -355,6 +410,7 @@ csm::EcefCoord MdisNacSensorModel::getSensorPosition(const csm::ImageCoord &imag } } + csm::EcefCoord MdisNacSensorModel::getSensorPosition(double time) const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -362,13 +418,13 @@ csm::EcefCoord MdisNacSensorModel::getSensorPosition(double time) const { "MdisNacSensorModel::getSensorPosition"); } + csm::EcefVector MdisNacSensorModel::getSensorVelocity(const csm::ImageCoord &imagePt) const { // Make sure the passed coordinate is with the image dimensions. if (imagePt.samp < 0.0 || imagePt.samp > m_nSamples || imagePt.line < 0.0 || imagePt.line > m_nLines) { - std::stringstream ss; - ss << "Image coordinate (" << imagePt.line << ", " << imagePt.samp << ") out of bounds."; - throw csm::Error(csm::Error::BOUNDS, ss.str(), "MdisNacSensorModel::getSensorVelocity"); + throw csm::Error(csm::Error::BOUNDS, "Image coordinate out of bounds.", + "MdisNacSensorModel::getSensorVelocity"); } // Since this is a frame, just return the sensor velocity the ISD gave us. @@ -379,6 +435,7 @@ csm::EcefVector MdisNacSensorModel::getSensorVelocity(const csm::ImageCoord &ima }; } + csm::EcefVector MdisNacSensorModel::getSensorVelocity(double time) const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -386,6 +443,7 @@ csm::EcefVector MdisNacSensorModel::getSensorVelocity(double time) const { "MdisNacSensorModel::getSensorVelocity"); } + csm::RasterGM::SensorPartials MdisNacSensorModel::computeSensorPartials(int index, const csm::EcefCoord &groundPt, double desiredPrecision, double *achievedPrecision, @@ -396,17 +454,45 @@ csm::RasterGM::SensorPartials MdisNacSensorModel::computeSensorPartials(int inde "MdisNacSensorModel::computeSensorPartials"); } -csm::RasterGM::SensorPartials MdisNacSensorModel::computeSensorPartials(int index, const csm::ImageCoord &imagePt, + +/** + * @brief MdisNacSensorModel::computeSensorPartials + * @param index + * @param imagePt + * @param groundPt + * @param desiredPrecision + * @param achievedPrecision + * @param warnings + * @return The partial derivatives in the line,sample directions. + * + * Research: We should investigate using a central difference scheme to approximate + * the partials. It is more accurate, but it might be costlier calculation-wise. + * + */ +csm::RasterGM::SensorPartials MdisNacSensorModel::computeSensorPartials(int index, + const csm::ImageCoord &imagePt, const csm::EcefCoord &groundPt, double desiredPrecision, double *achievedPrecision, csm::WarningList *warnings) const { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::computeSensorPartials"); + const double delta = 1.0; + std::vector adjustments(m_numParameters, 0.0); + adjustments[index] = delta; + + csm::ImageCoord imagePt1 = groundToImage(groundPt,adjustments,desiredPrecision,achievedPrecision); + + cout << "Img1 line: " << imagePt1.line << " ,Img1 sample: " << imagePt1.samp << endl; + csm::RasterGM::SensorPartials partials; + + partials.first = (imagePt1.line - imagePt.line)/delta; + partials.second = (imagePt1.samp - imagePt.samp)/delta; + + return partials; + } + std::vector MdisNacSensorModel::computeGroundPartials(const csm::EcefCoord &groundPt) const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -414,6 +500,7 @@ std::vector MdisNacSensorModel::computeGroundPartials(const csm::EcefCoo "MdisNacSensorModel::computeGroundPartials"); } + const csm::CorrelationModel& MdisNacSensorModel::getCorrelationModel() const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, @@ -421,6 +508,7 @@ const csm::CorrelationModel& MdisNacSensorModel::getCorrelationModel() const { "MdisNacSensorModel::getCorrelationModel"); } + std::vector MdisNacSensorModel::getUnmodeledCrossCovariance(const csm::ImageCoord &pt1, const csm::ImageCoord &pt2) const { @@ -430,8 +518,6 @@ std::vector MdisNacSensorModel::getUnmodeledCrossCovariance(const csm::I } - - csm::Version MdisNacSensorModel::getVersion() const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, "Unsupported function", @@ -440,7 +526,9 @@ csm::Version MdisNacSensorModel::getVersion() const { std::string MdisNacSensorModel::getModelName() const { - return "UsgsAstroFrameMdisPluginCSM"; + throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, + "Unsupported function", + "MdisNacSensorModel::getModelName"); } @@ -516,28 +604,46 @@ std::string MdisNacSensorModel::getReferenceDateAndTime() const { std::string MdisNacSensorModel::getModelState() const { - // TEMPORARY - /* commented out for testing the gtest framework - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::getModelState"); - */ - json state = { - {"m_focalLength" , m_focalLength}, - {"m_spacecraftPosition"}, {m_spacecraftPosition[0], - m_spacecraftPosition[1], - m_spacecraftPosition[2]}, - {"m_iTransS"}, {m_iTransS[0], - m_iTransS[1], - m_iTransS[2]}, - {"m_iTransL"}, {m_iTransL[0], - m_iTransL[1], - m_iTransL[2]}, - {"m_boresight"}, {m_boresight[0], - m_boresight[1], - m_boresight[2]} - }; - return state.dump(); + json state = { + {"model_name", _SENSOR_MODEL_NAME}, + {"m_focalLength" , m_focalLength}, + {"m_iTransS", {m_iTransS[0], m_iTransS[1], m_iTransS[2]}}, + {"m_iTransL", {m_iTransL[0], m_iTransL[1], m_iTransL[2]}}, + {"m_boresight", {m_boresight[0], m_boresight[1], m_boresight[2]}}, + {"m_transX", {m_transX[0], m_transX[1], m_transX[2]}}, + {"m_transY", {m_transY[0], m_transY[1], m_transY[2]}}, + {"m_iTransS", {m_iTransS[0], m_iTransS[1], m_iTransS[2]}}, + {"m_iTransL", {m_iTransL[0], m_iTransL[1], m_iTransL[2]}}, + {"m_majorAxis", m_majorAxis}, + {"m_minorAxis", m_minorAxis}, + {"m_spacecraftVelocity", {m_spacecraftVelocity[0], m_spacecraftVelocity[1], m_spacecraftVelocity[2]}}, + {"m_sunPosition", {m_sunPosition[0], m_sunPosition[1], m_sunPosition[2]}}, + {"m_startingDetectorSample", m_startingDetectorSample}, + {"m_startingDetectorLine", m_startingDetectorLine}, + {"m_targetName", m_targetName}, + {"m_ifov", m_ifov}, + {"m_instrumentID", m_instrumentID}, + {"m_focalLengthEpsilon", m_focalLengthEpsilon}, + {"m_ccdCenter", {m_ccdCenter[0], m_ccdCenter[1]}}, + {"m_line_pp", m_line_pp}, + {"m_sample_pp", m_sample_pp}, + {"m_odtX", {m_odtX[0], m_odtX[1], m_odtX[2], m_odtX[3], m_odtX[4], + m_odtX[5], m_odtX[6], m_odtX[7], m_odtX[8], m_odtX[9]}}, + {"m_odtY", {m_odtY[0], m_odtY[1], m_odtY[2], m_odtY[3], m_odtY[4], + m_odtY[5], m_odtY[6], m_odtY[7], m_odtY[8], m_odtY[9]}}, + {"m_originalHalfLines", m_originalHalfLines}, + {"m_originalHalfSamples", m_originalHalfSamples}, + {"m_spacecraftName", m_spacecraftName}, + {"m_pixelPitch", m_pixelPitch}, + {"m_ephemerisTime", m_ephemerisTime}, + {"m_nLines", m_nLines}, + {"m_nSamples", m_nSamples}, + {"m_currentParameterValue", {m_currentParameterValue[0], m_currentParameterValue[1], + m_currentParameterValue[2], m_currentParameterValue[3], + m_currentParameterValue[4], m_currentParameterValue[5]}}, + {"m_currentParameterCovariance", m_currentParameterCovariance} + }; + return state.dump(); } @@ -548,8 +654,6 @@ void MdisNacSensorModel::replaceModelState(const std::string& argState) { } - - csm::EcefCoord MdisNacSensorModel::getReferencePoint() const { throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, "Unsupported function", @@ -565,23 +669,25 @@ void MdisNacSensorModel::setReferencePoint(const csm::EcefCoord &groundPt) { int MdisNacSensorModel::getNumParameters() const { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::getNumParameters"); + + return m_numParameters; } std::string MdisNacSensorModel::getParameterName(int index) const { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::getParameterName"); + + return m_parameterName[index]; } std::string MdisNacSensorModel::getParameterUnits(int index) const { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::getParameterUnits"); + + if (index < 3) { + return "m"; + } + else { + return "radians"; + } } @@ -607,16 +713,15 @@ csm::SharingCriteria MdisNacSensorModel::getParameterSharingCriteria(int index) double MdisNacSensorModel::getParameterValue(int index) const { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::getParameterValue"); + + return m_currentParameterValue[index]; + } void MdisNacSensorModel::setParameterValue(int index, double value) { - throw csm::Error(csm::Error::UNSUPPORTED_FUNCTION, - "Unsupported function", - "MdisNacSensorModel::setParameterValue"); + + m_currentParameterValue[index] = value; } @@ -687,19 +792,42 @@ std::vector MdisNacSensorModel::getCrossCovarianceMatrix( "MdisNacSensorModel::getCrossCovarianceMatrix"); } + void MdisNacSensorModel::calcRotationMatrix( - double m[3][3]) const { + double m[3][3]) const { // Trigonometric functions for rotation matrix - double sinw = std::sin(m_omega); - double cosw = std::cos(m_omega); - double sinp = std::sin(m_phi); - double cosp = std::cos(m_phi); - double sink = std::sin(m_kappa); - double cosk = std::cos(m_kappa); + double sinw = std::sin(m_currentParameterValue[3]); + double cosw = std::cos(m_currentParameterValue[3]); + double sinp = std::sin(m_currentParameterValue[4]); + double cosp = std::cos(m_currentParameterValue[4]); + double sink = std::sin(m_currentParameterValue[5]); + double cosk = std::cos(m_currentParameterValue[5]); // Rotation matrix taken from Introduction to Mordern Photogrammetry by // Edward M. Mikhail, et al., p. 373 + m[0][0] = cosp * cosk; + m[0][1] = cosw * sink + sinw * sinp * cosk; + m[0][2] = sinw * sink - cosw * sinp * cosk; + m[1][0] = -1 * cosp * sink; + m[1][1] = cosw * cosk - sinw * sinp * sink; + m[1][2] = sinw * cosk + cosw * sinp * sink; + m[2][0] = sinp; + m[2][1] = -1 * sinw * cosp; + m[2][2] = cosw * cosp; +} + + +void MdisNacSensorModel::calcRotationMatrix( + double m[3][3], const std::vector &adjustments) const { + + // Trigonometric functions for rotation matrix + double sinw = std::sin(getValue(3,adjustments)); + double cosw = std::cos(getValue(3,adjustments)); + double sinp = std::sin(getValue(4,adjustments)); + double cosp = std::cos(getValue(4,adjustments)); + double sink = std::sin(getValue(5,adjustments)); + double cosk = std::cos(getValue(5,adjustments)); m[0][0] = cosp * cosk; m[0][1] = cosw * sink + sinw * sinp * cosk; @@ -712,14 +840,15 @@ void MdisNacSensorModel::calcRotationMatrix( m[2][2] = cosw * cosp; } + void MdisNacSensorModel::losEllipsoidIntersect( - double& height, - double& xc, - double& yc, - double& zc, - double& xl, - double& yl, - double& zl, + const double& height, + const double& xc, + const double& yc, + const double& zc, + const double& xl, + const double& yl, + const double& zl, double& x, double& y, double& z ) const @@ -759,6 +888,8 @@ void MdisNacSensorModel::losEllipsoidIntersect( y = yc + scale * yl; z = zc + scale * zl; } + + /** * @brief Compute undistorted focal plane x/y. * @@ -899,6 +1030,7 @@ void MdisNacSensorModel::distortionJacobian(double x, double y, double &Jxx, dou } + /** * @description Compute distorted focal plane (dx,dy) coordinate given an undistorted focal * plane (ux,uy) coordinate. This describes the third order Taylor approximation to the @@ -931,3 +1063,12 @@ void MdisNacSensorModel::distortionFunction(double ux, double uy, double &dx, do dy = dy + f[i] * m_odtY[i]; } } + +/***** Helper Functions *****/ + +double MdisNacSensorModel::getValue( + int index, + const std::vector &adjustments) const +{ + return m_currentParameterValue[index] + adjustments[index]; +} diff --git a/tests/CW1071364100B_IU_5.json b/tests/CW1071364100B_IU_5.json index b496171..cbdcf1e 100644 --- a/tests/CW1071364100B_IU_5.json +++ b/tests/CW1071364100B_IU_5.json @@ -24,6 +24,7 @@ 0.0 ], "kappa": -3.072868243248164, + "model_name": "ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so", "nlines": 1024, "nsamples": 1024, "odt_x": [ @@ -72,6 +73,12 @@ 0.013997772676294 ], "x_sensor_origin": 28892.88978623381, + "x_sensor_velocity": 0, + "x_sun_position": 0, "y_sensor_origin": 633940.116378508, - "z_sensor_origin": 2683552.1331144567 + "y_sensor_velocity": 0, + "y_sun_position": 0, + "z_sensor_origin": 2683552.1331144567, + "z_sensor_velocity": 0, + "z_sun_position": 0 } diff --git a/tests/EN1007907102M.json b/tests/EN1007907102M.json index 1a235a4..d4ccb6b 100644 --- a/tests/EN1007907102M.json +++ b/tests/EN1007907102M.json @@ -24,6 +24,7 @@ 0.0 ], "kappa": -0.963008015000929, + "model_name": "ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so", "nlines": 1024, "nsamples": 1024, "odt_x": [ @@ -73,9 +74,11 @@ ], "x_sensor_origin": 1728181.0340792781, "x_sun_position": -31648725087.588726, + "x_sensor_velocity": 0, "y_sensor_origin": -2088202.591297346, "y_sun_position": -60633907522.72863, + "y_sensor_velocity": 0, "z_sensor_origin": 2082707.608992824, + "z_sensor_velocity" :0, "z_sun_position": -38729485.77334732 } - diff --git a/tests/test_mdis_csm.py b/tests/test_mdis_csm.py index b1f4f8b..8224b3d 100644 --- a/tests/test_mdis_csm.py +++ b/tests/test_mdis_csm.py @@ -23,14 +23,82 @@ class TestPlugin: csm_isd.addparam(k, v) return csm_isd - def test_mdis_plugin(self, plugin): - assert plugin.name == 'UsgsAstroFrameMdisPluginCSM' + def test_nmodels(self, plugin): assert plugin.nmodels == 1 - assert plugin.modelname(1) == 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' def test_check_isd_construction(self, plugin, i): assert plugin.check_isd_construction(i, plugin.modelname(1)) + def test_releasedate(self, plugin): + assert plugin.releasedate == "20170425" + + def test_csmversion(self, plugin): + assert plugin.csmversion.version.decode() == "3.0.1" + + def test_plugin_name(self, plugin): + assert plugin.name == 'UsgsAstroFrameMdisPluginCSM' + + def test_modelname(self, plugin): + assert plugin.modelname(1) == 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' + + def test_modelfamily(self, plugin): + assert plugin.modelfamily(1) == 'Raster' + + def test_modelname_from_state(self, plugin, i): + state = {'model_name': 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so'} + name = plugin.modelname_from_state(json.dumps(state)) + assert name == state['model_name'] + + def test_modelname_from_state_bad_key(self, plugin): + state = {'mname':'foo'} + with pytest.raises(RuntimeError) as err: + name = plugin.modelname_from_state(json.dumps(state)) + assert "'model_name'" in str(err.value) + + def test_modelname_from_state_bad_name(self, plugin): + state = {'model_name':'foo'} + with pytest.raises(RuntimeError) as err: + name = plugin.modelname_from_state(json.dumps(state)) + assert "Sensor model not supported." in str(err.value) + + def test_can_model_be_constructed_from_state(self, plugin): + name = 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' + with open(os.path.join(data_path,'nac_state.json'), 'r') as f: + state = json.load(f) + constructible = plugin.can_model_be_constructed_from_state(name, json.dumps(state)) + assert constructible == True + + name = 'foo' + constructible = plugin.can_model_be_constructed_from_state(name, json.dumps(state)) + assert constructible == False + + def test_can_isd_be_converted_to_model_state(self, plugin, i): + name = 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' + res = plugin.can_isd_be_converted_to_model_state(i, name) + assert res == True + + def test_convert_isd_to_model_state(self, plugin, i): + name = 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' + state = plugin.convert_isd_to_state(i, name) + with open(os.path.join(data_path,'nac_state.json'), 'r') as f: + truth = json.load(f) + assert state == truth + + def test_convert_isd_to_model_state_bad(self, plugin, i): + # Trash the isd and check error handling + i.clear_params("focal_length") + name = 'ISIS_MDISNAC_USGSAstro_1_Linux64_csm30.so' + with pytest.raises(RuntimeError) as err: + state = plugin.convert_isd_to_state(i, name) + assert "Sensor model support data" in str(err.value) + + def test_construct_model_from_state(self, plugin): + with open(os.path.join(data_path,'nac_state.json'), 'r') as f: + state = json.load(f) + camera = plugin.from_state(json.dumps(state)) + assert isinstance(camera, cam.mdis.MdisNacSensorModel) + + class TestMdisWac: @pytest.fixture def model(self): diff --git a/usgscam/mdis.pxd b/usgscam/mdis.pxd index d00bd02..9c5b705 100644 --- a/usgscam/mdis.pxd +++ b/usgscam/mdis.pxd @@ -6,12 +6,13 @@ from libcpp.pair cimport pair from cycsm.isd cimport CppIsd from cycsm.csm cimport CppEcefCoord, CppImageCoord, CppImageVector, CppEcefVector, CppEcefLocus from cycsm.model cimport CppModel +from cycsm.version cimport CppVersion cdef extern from "MdisNacSensorModel.h": cdef cppclass CppMdisNacSensorModel "MdisNacSensorModel": CppMdisNacSensorModel() except + - CppEcefCoord imageToGround(CppImageCoord imagePt, double height, double precision) - CppImageCoord groundToImage(CppEcefCoord groundPt, double desiredPrecision) + CppEcefCoord imageToGround(CppImageCoord imagePt, double height, double precision) except + + CppImageCoord groundToImage(CppEcefCoord groundPt, double desiredPrecision) except + CppImageCoord getImageStart() CppImageVector getImageSize() @@ -42,13 +43,18 @@ cdef extern from "MdisPlugin.h": string getPluginName() string getManufacturer() - #string getReleaseDate() - #string getCsmVersion + string getModelNameFromModelState(const string modelState) except + + string getReleaseDate() + CppVersion getCsmVersion() size_t getNumModels() string getModelName(size_t modelIndex) - bool canModelBeConstructedFromISD(CppIsd isd, const string modelname) - string convertISDToModelState(CppIsd isd, const string modelname) - CppModel *constructModelFromISD(CppIsd &isd, string &modelname) + string getModelFamily(size_t modelIndex) + bool canModelBeConstructedFromISD(CppIsd isd, const string modelname) except + + bool canModelBeConstructedFromState(const string modelName, const string modelState) except + + bool canISDBeConvertedToModelState(CppIsd isd, const string modelName) except + + string convertISDToModelState(CppIsd isd, const string modelname) except + + CppModel *constructModelFromISD(CppIsd &isd, string &modelname) except + + CppModel *constructModelFromState(string modelState) except + # For casting from the CSM Model into our specific camera model - I hope. cdef extern from *: diff --git a/usgscam/mdis.pyx b/usgscam/mdis.pyx index 9a1bf88..0bb5206 100644 --- a/usgscam/mdis.pyx +++ b/usgscam/mdis.pyx @@ -1,9 +1,11 @@ import numpy as np import ast +import json from cython.operator cimport dereference as deref from cycsm.csm import EcefCoord, ImageCoord from cycsm.isd cimport Isd +from cycsm.version import Version cdef class MdisNacSensorModel: cdef: @@ -261,21 +263,43 @@ cdef class MdisPlugin: def manufacturer(self): return self.thisptr.getManufacturer().decode() - #@property - #def releasedate(self): - # return self.thisptr.getReleaseDate() + @property + def releasedate(self): + return self.thisptr.getReleaseDate().decode() - #@property - #def version(self): - # return self.thisptr.getCsmVersion() + @property + def csmversion(self): + return Version(self.thisptr.getCsmVersion().version()) @property def nmodels(self): return self.thisptr.getNumModels() + + def modelfamily(self, modelindex): + return self.thisptr.getModelFamily(modelindex).decode() + + def modelname_from_state(self, state): + state = state.encode() + res = self.thisptr.getModelNameFromModelState(state).decode() + return res + def modelname(self, modelindex): return self.thisptr.getModelName(modelindex).decode() + def can_model_be_constructed_from_state(self, name, state): + name = name.encode() + state = state.encode() + return self.thisptr.canModelBeConstructedFromState(name, state) + + def can_isd_be_converted_to_model_state(self, Isd isd, modelname): + modelname = modelname.encode() + return self.thisptr.canISDBeConvertedToModelState(isd.thisptr[0], modelname) + + def convert_isd_to_state(self, Isd isd, modelname): + modelname = modelname.encode() + return json.loads(self.thisptr.convertISDToModelState(isd.thisptr[0], modelname).decode()) + def check_isd_construction(self, Isd isd, modelname): modelname = str(modelname).encode() return self.thisptr.canModelBeConstructedFromISD(isd.thisptr[0], modelname) @@ -283,3 +307,8 @@ cdef class MdisPlugin: def from_isd(self, Isd isd, modelname): modelname = str(modelname).encode() return MdisNacSensorModel.factory(dynamic_cast_model_ptr(self.thisptr.constructModelFromISD(isd.thisptr[0], modelname))) + + def from_state(self, state): + state = state.encode() + #self.thisptr.constructModelFromState(state) + return MdisNacSensorModel.factory(dynamic_cast_model_ptr(self.thisptr.constructModelFromState(state))) -- GitLab