//---------------------------------------------------------------------------- // // UNCLASSIFIED // // Copyright © 1989-2017 BAE Systems Information and Electronic Systems Integration Inc. // ALL RIGHTS RESERVED // Use of this software product is governed by the terms of a license // agreement. The license agreement is found in the installation directory. // // For support, please visit http://www.baesystems.com/gxp // // Revision History: // Date Name Description // ----------- ------------ ----------------------------------------------- // 13-Nov-2015 BAE Systems Initial Implementation // 24-Apr-2017 BAE Systems Update for CSM 3.0.2 // 24-OCT-2017 BAE Systems Update for CSM 3.0.3 //----------------------------------------------------------------------------- #include "UsgsAstroLsSensorModel.h" #include "Utilities.h" #include "Distortion.h" #include #include #include #include #include #include #include #define MESSAGE_LOG(logger, ...) if (logger) { logger->info(__VA_ARGS__); } using json = nlohmann::json; using namespace std; const std::string UsgsAstroLsSensorModel::_SENSOR_MODEL_NAME = "USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL"; const int UsgsAstroLsSensorModel::NUM_PARAMETERS = 16; const std::string UsgsAstroLsSensorModel::PARAMETER_NAME[] = { "IT Pos. Bias ", // 0 "CT Pos. Bias ", // 1 "Rad Pos. Bias ", // 2 "IT Vel. Bias ", // 3 "CT Vel. Bias ", // 4 "Rad Vel. Bias ", // 5 "Omega Bias ", // 6 "Phi Bias ", // 7 "Kappa Bias ", // 8 "Omega Rate ", // 9 "Phi Rate ", // 10 "Kappa Rate ", // 11 "Omega Accl ", // 12 "Phi Accl ", // 13 "Kappa Accl ", // 14 "Focal Bias " // 15 }; const std::string UsgsAstroLsSensorModel::_STATE_KEYWORD[] = { "m_modelName", "m_imageIdentifier", "m_sensorName", "m_nLines", "m_nSamples", "m_platformFlag", "m_intTimeLines", "m_intTimeStartTimes", "m_intTimes", "m_startingEphemerisTime", "m_centerEphemerisTime", "m_detectorSampleSumming", "m_startingDetectorSample", "m_startingDetectorLine", "m_ikCode", "m_focalLength", "m_zDirection", "m_distortionType", "m_opticalDistCoeffs", "m_iTransS", "m_iTransL", "m_detectorSampleOrigin", "m_detectorLineOrigin", "m_majorAxis", "m_minorAxis", "m_platformIdentifier", "m_sensorIdentifier", "m_minElevation", "m_maxElevation", "m_dtEphem", "m_t0Ephem", "m_dtQuat", "m_t0Quat", "m_numPositions", "m_numQuaternions", "m_positions", "m_velocities", "m_quaternions", "m_currentParameterValue", "m_parameterType", "m_referencePointXyz", "m_gsd", "m_flyingHeight", "m_halfSwath", "m_halfTime", "m_covariance", }; const int UsgsAstroLsSensorModel::NUM_PARAM_TYPES = 4; const std::string UsgsAstroLsSensorModel::PARAM_STRING_ALL[] = { "NONE", "FICTITIOUS", "REAL", "FIXED" }; const csm::param::Type UsgsAstroLsSensorModel::PARAM_CHAR_ALL[] = { csm::param::NONE, csm::param::FICTITIOUS, csm::param::REAL, csm::param::FIXED }; //*************************************************************************** // UsgsAstroLineScannerSensorModel::replaceModelState //*************************************************************************** void UsgsAstroLsSensorModel::replaceModelState(const std::string &stateString ) { MESSAGE_LOG(m_logger, "Replacing model state") reset(); auto j = json::parse(stateString); int num_params = NUM_PARAMETERS; int num_paramsSq = num_params * num_params; m_imageIdentifier = j["m_imageIdentifier"].get(); m_sensorName = j["m_sensorName"]; m_nLines = j["m_nLines"]; m_nSamples = j["m_nSamples"]; m_platformFlag = j["m_platformFlag"]; MESSAGE_LOG(m_logger, "m_imageIdentifier: {} " "m_sensorName: {} " "m_nLines: {} " "m_nSamples: {} " "m_platformFlag: {} ", j["m_imageIdentifier"].dump(), j["m_sensorName"].dump(), j["m_nLines"].dump(), j["m_nSamples"].dump(), j["m_platformFlag"].dump()) m_intTimeLines = j["m_intTimeLines"].get>(); m_intTimeStartTimes = j["m_intTimeStartTimes"].get>(); m_intTimes = j["m_intTimes"].get>(); m_startingEphemerisTime = j["m_startingEphemerisTime"]; m_centerEphemerisTime = j["m_centerEphemerisTime"]; m_detectorSampleSumming = j["m_detectorSampleSumming"]; m_startingSample = j["m_startingDetectorSample"]; m_ikCode = j["m_ikCode"]; MESSAGE_LOG(m_logger, "m_startingEphemerisTime: {} " "m_centerEphemerisTime: {} " "m_detectorSampleSumming: {} " "m_startingSample: {} " "m_ikCode: {} ", j["m_startingEphemerisTime"].dump(), j["m_centerEphemerisTime"].dump(), j["m_detectorSampleSumming"].dump(), j["m_startingSample"].dump(), j["m_ikCode"].dump()) m_focalLength = j["m_focalLength"]; m_zDirection = j["m_zDirection"]; m_distortionType = (DistortionType)j["m_distortionType"].get(); m_opticalDistCoeffs = j["m_opticalDistCoeffs"].get>(); MESSAGE_LOG(m_logger, "m_focalLength: {} " "m_zDirection: {} " "m_distortionType: {} ", j["m_focalLength"].dump(), j["m_zDirection"].dump(), j["m_distortionType"].dump()) for (int i = 0; i < 3; i++) { m_iTransS[i] = j["m_iTransS"][i]; m_iTransL[i] = j["m_iTransL"][i]; } m_detectorSampleOrigin = j["m_detectorSampleOrigin"]; m_detectorLineOrigin = j["m_detectorLineOrigin"]; m_majorAxis = j["m_majorAxis"]; m_minorAxis = j["m_minorAxis"]; MESSAGE_LOG(m_logger, "m_detectorSampleOrigin: {} " "m_detectorLineOrigin: {} " "m_majorAxis: {} " "m_minorAxis: {} ", j["m_detectorSampleOrigin"].dump(), j["m_detectorLineOrigin"].dump(), j["m_majorAxis"].dump(), j["m_minorAxis"].dump()) m_platformIdentifier = j["m_platformIdentifier"]; m_sensorIdentifier = j["m_sensorIdentifier"]; MESSAGE_LOG(m_logger, "m_platformIdentifier: {} " "m_sensorIdentifier: {} ", j["m_platformIdentifier"].dump(), j["m_sensorIdentifier"].dump()) m_minElevation = j["m_minElevation"]; m_maxElevation = j["m_maxElevation"]; MESSAGE_LOG(m_logger, "m_minElevation: {} " "m_maxElevation: {} ", j["m_minElevation"].dump(), j["m_maxElevation"].dump()) m_dtEphem = j["m_dtEphem"]; m_t0Ephem = j["m_t0Ephem"]; m_dtQuat = j["m_dtQuat"]; m_t0Quat = j["m_t0Quat"]; m_numPositions = j["m_numPositions"]; MESSAGE_LOG(m_logger, "m_dtEphem: {} " "m_t0Ephem: {} " "m_dtQuat: {} " "m_t0Quat: {} ", j["m_dtEphem"].dump(), j["m_t0Ephem"].dump(), j["m_dtQuat"].dump(), j["m_t0Quat"].dump()) m_numQuaternions = j["m_numQuaternions"]; m_referencePointXyz.x = j["m_referencePointXyz"][0]; m_referencePointXyz.y = j["m_referencePointXyz"][1]; m_referencePointXyz.z = j["m_referencePointXyz"][2]; MESSAGE_LOG(m_logger, "m_numQuaternions: {} " "m_referencePointX: {} " "m_referencePointY: {} " "m_referencePointZ: {} ", j["m_numQuaternions"].dump(), j["m_referencePointXyz"][0].dump(), j["m_referencePointXyz"][1].dump(), j["m_referencePointXyz"][2].dump()) m_gsd = j["m_gsd"]; m_flyingHeight = j["m_flyingHeight"]; m_halfSwath = j["m_halfSwath"]; m_halfTime = j["m_halfTime"]; MESSAGE_LOG(m_logger, "m_gsd: {} " "m_flyingHeight: {} " "m_halfSwath: {} " "m_halfTime: {} ", j["m_gsd"].dump(), j["m_flyingHeight"].dump(), j["m_halfSwath"].dump(), j["m_halfTime"].dump()) // Vector = is overloaded so explicit get with type required. m_positions = j["m_positions"].get>(); m_velocities = j["m_velocities"].get>(); m_quaternions = j["m_quaternions"].get>(); m_currentParameterValue = j["m_currentParameterValue"].get>(); m_covariance = j["m_covariance"].get>(); m_logFile = j["m_logFile"].get(); if (m_logFile.empty()) { m_logger.reset(); } else { m_logger = spdlog::get(m_logFile); if (!m_logger) { m_logger = spdlog::basic_logger_mt(m_logFile, m_logFile); } } for (int i = 0; i < num_params; i++) { for (int k = 0; k < NUM_PARAM_TYPES; k++) { if (j["m_parameterType"][i] == PARAM_STRING_ALL[k]) { m_parameterType[i] = PARAM_CHAR_ALL[k]; break; } } } // If computed state values are still default, then compute them if (m_gsd == 1.0 && m_flyingHeight == 1000.0) { updateState(); } try { setLinearApproximation(); } catch (...) { _linear = false; } } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getModelNameFromModelState //*************************************************************************** std::string UsgsAstroLsSensorModel::getModelNameFromModelState( const std::string& model_state) { // Parse the string to JSON auto j = json::parse(model_state); // If model name cannot be determined, return a blank string std::string model_name; if (j.find("m_modelName") != j.end()) { model_name = j["m_modelName"]; } else { csm::Error::ErrorType aErrorType = csm::Error::INVALID_SENSOR_MODEL_STATE; std::string aMessage = "No 'm_modelName' key in the model state object."; std::string aFunction = "UsgsAstroLsPlugin::getModelNameFromModelState"; csm::Error csmErr(aErrorType, aMessage, aFunction); throw(csmErr); } if (model_name != _SENSOR_MODEL_NAME){ csm::Error::ErrorType aErrorType = csm::Error::SENSOR_MODEL_NOT_SUPPORTED; std::string aMessage = "Sensor model not supported."; std::string aFunction = "UsgsAstroLsPlugin::getModelNameFromModelState()"; csm::Error csmErr(aErrorType, aMessage, aFunction); throw(csmErr); } return model_name; } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getModelState //*************************************************************************** std::string UsgsAstroLsSensorModel::getModelState() const { MESSAGE_LOG(m_logger, "Running getModelState") json state; state["m_modelName"] = _SENSOR_MODEL_NAME; state["m_startingDetectorSample"] = m_startingSample; state["m_imageIdentifier"] = m_imageIdentifier; state["m_sensorName"] = m_sensorName; state["m_nLines"] = m_nLines; state["m_nSamples"] = m_nSamples; state["m_platformFlag"] = m_platformFlag; MESSAGE_LOG(m_logger, "m_imageIdentifier: {} " "m_sensorName: {} " "m_nLines: {} " "m_nSamples: {} " "m_platformFlag: {} ", m_imageIdentifier, m_sensorName, m_nLines, m_nSamples, m_platformFlag) state["m_intTimeLines"] = m_intTimeLines; state["m_intTimeStartTimes"] = m_intTimeStartTimes; state["m_intTimes"] = m_intTimes; state["m_startingEphemerisTime"] = m_startingEphemerisTime; state["m_centerEphemerisTime"] = m_centerEphemerisTime; MESSAGE_LOG(m_logger, "m_startingEphemerisTime: {} " "m_centerEphemerisTime: {} ", m_startingEphemerisTime, m_centerEphemerisTime) state["m_detectorSampleSumming"] = m_detectorSampleSumming; state["m_startingSample"] = m_startingSample; state["m_ikCode"] = m_ikCode; MESSAGE_LOG(m_logger, "m_detectorSampleSumming: {} " "m_startingSample: {} " "m_ikCode: {} ", m_detectorSampleSumming, m_startingSample, m_ikCode) state["m_focalLength"] = m_focalLength; state["m_zDirection"] = m_zDirection; state["m_distortionType"] = m_distortionType; state["m_opticalDistCoeffs"] = m_opticalDistCoeffs; MESSAGE_LOG(m_logger, "m_focalLength: {} " "m_zDirection: {} " "m_distortionType (0-Radial, 1-Transverse): {} ", m_focalLength, m_zDirection, m_distortionType) state["m_iTransS"] = std::vector(m_iTransS, m_iTransS+3); state["m_iTransL"] = std::vector(m_iTransL, m_iTransL+3); state["m_detectorSampleOrigin"] = m_detectorSampleOrigin; state["m_detectorLineOrigin"] = m_detectorLineOrigin; state["m_majorAxis"] = m_majorAxis; state["m_minorAxis"] = m_minorAxis; MESSAGE_LOG(m_logger, "m_detectorSampleOrigin: {} " "m_detectorLineOrigin: {} " "m_majorAxis: {} " "m_minorAxis: {} ", m_detectorSampleOrigin, m_detectorLineOrigin, m_majorAxis, m_minorAxis) state["m_platformIdentifier"] = m_platformIdentifier; state["m_sensorIdentifier"] = m_sensorIdentifier; state["m_minElevation"] = m_minElevation; state["m_maxElevation"] = m_maxElevation; MESSAGE_LOG(m_logger, "m_platformIdentifier: {} " "m_sensorIdentifier: {} " "m_minElevation: {} " "m_maxElevation: {} ", m_platformIdentifier, m_sensorIdentifier, m_minElevation, m_maxElevation) state["m_dtEphem"] = m_dtEphem; state["m_t0Ephem"] = m_t0Ephem; state["m_dtQuat"] = m_dtQuat; state["m_t0Quat"] = m_t0Quat; MESSAGE_LOG(m_logger, "m_dtEphem: {} " "m_t0Ephem: {} " "m_dtQuat: {} " "m_t0Quat: {} ", m_dtEphem, m_t0Ephem, m_dtQuat, m_t0Quat) state["m_numPositions"] = m_numPositions; state["m_numQuaternions"] = m_numQuaternions; state["m_positions"] = m_positions; state["m_velocities"] = m_velocities; state["m_quaternions"] = m_quaternions; MESSAGE_LOG(m_logger, "m_numPositions: {} " "m_numQuaternions: {} ", m_numPositions, m_numQuaternions) state["m_currentParameterValue"] = m_currentParameterValue; state["m_parameterType"] = m_parameterType; state["m_gsd"] = m_gsd; state["m_flyingHeight"] = m_flyingHeight; state["m_halfSwath"] = m_halfSwath; state["m_halfTime"] = m_halfTime; state["m_covariance"] = m_covariance; MESSAGE_LOG(m_logger, "m_gsd: {} " "m_flyingHeight: {} " "m_halfSwath: {} " "m_halfTime: {} ", m_gsd, m_flyingHeight, m_halfSwath, m_halfTime) state["m_referencePointXyz"] = json(); state["m_referencePointXyz"][0] = m_referencePointXyz.x; state["m_referencePointXyz"][1] = m_referencePointXyz.y; state["m_referencePointXyz"][2] = m_referencePointXyz.z; MESSAGE_LOG(m_logger, "m_referencePointXyz: {} " "m_referencePointXyz: {} " "m_referencePointXyz: {} ", m_referencePointXyz.x, m_referencePointXyz.y, m_referencePointXyz.z) state["m_logFile"] = m_logFile; return state.dump(); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::reset //*************************************************************************** void UsgsAstroLsSensorModel::reset() { MESSAGE_LOG(m_logger, "Running reset()") _linear = false; // default until a linear model is made _u0 = 0.0; _du_dx = 0.0; _du_dy = 0.0; _du_dz = 0.0; _v0 = 0.0; _dv_dx = 0.0; _dv_dy = 0.0; _dv_dz = 0.0; _no_adjustment.assign(UsgsAstroLsSensorModel::NUM_PARAMETERS, 0.0); m_imageIdentifier = ""; // 1 m_sensorName = "USGSAstroLineScanner"; // 2 m_nLines = 0; // 3 m_nSamples = 0; // 4 m_platformFlag = 1; // 9 m_intTimeLines.clear(); m_intTimeStartTimes.clear(); m_intTimes.clear(); m_startingEphemerisTime = 0.0; // 13 m_centerEphemerisTime = 0.0; // 14 m_detectorSampleSumming = 1.0; // 15 m_startingSample = 1.0; // 16 m_ikCode = -85600; // 17 m_focalLength = 350.0; // 18 m_zDirection = 1.0; // 19 m_distortionType = DistortionType::RADIAL; m_opticalDistCoeffs = std::vector(3, 0.0); m_iTransS[0] = 0.0; // 21 m_iTransS[1] = 0.0; // 21 m_iTransS[2] = 150.0; // 21 m_iTransL[0] = 0.0; // 22 m_iTransL[1] = 150.0; // 22 m_iTransL[2] = 0.0; // 22 m_detectorSampleOrigin = 2500.0; // 23 m_detectorLineOrigin = 0.0; // 24 m_majorAxis = 3400000.0; // 27 m_minorAxis = 3350000.0; // 28 m_platformIdentifier = ""; // 31 m_sensorIdentifier = ""; // 32 m_minElevation = -8000.0; // 34 m_maxElevation = 8000.0; // 35 m_dtEphem = 2.0; // 36 m_t0Ephem = -70.0; // 37 m_dtQuat = 0.1; // 38 m_t0Quat = -40.0; // 39 m_numPositions = 0; // 40 m_numQuaternions = 0; // 41 m_positions.clear(); // 42 m_velocities.clear(); // 43 m_quaternions.clear(); // 44 m_currentParameterValue.assign(NUM_PARAMETERS,0.0); m_parameterType.assign(NUM_PARAMETERS,csm::param::REAL); m_referencePointXyz.x = 0.0; m_referencePointXyz.y = 0.0; m_referencePointXyz.z = 0.0; m_gsd = 1.0; m_flyingHeight = 1000.0; m_halfSwath = 1000.0; m_halfTime = 10.0; m_covariance = std::vector(NUM_PARAMETERS * NUM_PARAMETERS,0.0); // 52 m_logFile = ""; m_logger.reset(); } //***************************************************************************** // UsgsAstroLsSensorModel Constructor //***************************************************************************** UsgsAstroLsSensorModel::UsgsAstroLsSensorModel() { _no_adjustment.assign(UsgsAstroLsSensorModel::NUM_PARAMETERS, 0.0); } //***************************************************************************** // UsgsAstroLsSensorModel Destructor //***************************************************************************** UsgsAstroLsSensorModel::~UsgsAstroLsSensorModel() { } //***************************************************************************** // UsgsAstroLsSensorModel updateState //***************************************************************************** void UsgsAstroLsSensorModel::updateState() { // If sensor model is being created for the first time // This routine will set some parameters not found in the ISD. MESSAGE_LOG(m_logger, "Updating State") // Reference point (image center) double lineCtr = m_nLines / 2.0; double sampCtr = m_nSamples / 2.0; csm::ImageCoord ip(lineCtr, sampCtr); MESSAGE_LOG(m_logger, "updateState: center image coordinate set to {} {}", lineCtr, sampCtr) double refHeight = 0; m_referencePointXyz = imageToGround(ip, refHeight); MESSAGE_LOG(m_logger, "updateState: reference point (x, y, z) {} {} {}", m_referencePointXyz.x, m_referencePointXyz.y, m_referencePointXyz.z) // Compute ground sample distance ip.line += 1; ip.samp += 1; csm::EcefCoord delta = imageToGround(ip, refHeight); double dx = delta.x - m_referencePointXyz.x; double dy = delta.y - m_referencePointXyz.y; double dz = delta.z - m_referencePointXyz.z; m_gsd = sqrt((dx*dx + dy*dy + dz*dz) / 2.0); MESSAGE_LOG(m_logger, "updateState: ground sample distance set to {} " "based on dx {} dy {} dz {}", m_gsd, dx, dy, dz) // Compute flying height csm::EcefCoord sensorPos = getSensorPosition(0.0); dx = sensorPos.x - m_referencePointXyz.x; dy = sensorPos.y - m_referencePointXyz.y; dz = sensorPos.z - m_referencePointXyz.z; m_flyingHeight = sqrt(dx*dx + dy*dy + dz*dz); MESSAGE_LOG(m_logger, "updateState: flight height set to {}" "based on dx {} dy {} dz {}", m_flyingHeight, dx, dy, dz) // Compute half swath m_halfSwath = m_gsd * m_nSamples / 2.0; MESSAGE_LOG(m_logger, "updateState: half swath set to {}", m_halfSwath) // Compute half time duration double fullImageTime = m_intTimeStartTimes.back() - m_intTimeStartTimes.front() + m_intTimes.back() * (m_nLines - m_intTimeLines.back()); m_halfTime = fullImageTime / 2.0; MESSAGE_LOG(m_logger, "updateState: half time duration set to {}", m_halfTime) // Parameter covariance, hardcoded accuracy values int num_params = NUM_PARAMETERS; int num_paramsSquare = num_params * num_params; double variance = m_gsd * m_gsd; for (int i = 0; i < num_paramsSquare; i++) { m_covariance[i] = 0.0; } for (int i = 0; i < num_params; i++) { m_covariance[i * num_params + i] = variance; } } //--------------------------------------------------------------------------- // Core Photogrammetry //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::groundToImage //*************************************************************************** csm::ImageCoord UsgsAstroLsSensorModel::groundToImage( const csm::EcefCoord& ground_pt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing groundToImage(No adjustments) for {}, {}, {}, with desired precision {}", ground_pt.x, ground_pt.y, ground_pt.z, desired_precision); // The public interface invokes the private interface with no adjustments. return groundToImage( ground_pt, _no_adjustment, desired_precision, achieved_precision, warnings); } //*************************************************************************** // UsgsAstroLsSensorModel::groundToImage (internal version) //*************************************************************************** csm::ImageCoord UsgsAstroLsSensorModel::groundToImage( const csm::EcefCoord& ground_pt, const std::vector& adj, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing groundToImage (with adjustments) for {}, {}, {}, with desired precision {}", ground_pt.x, ground_pt.y, ground_pt.z, desired_precision); // Search for the line, sample coordinate that viewed a given ground point. // This method uses an iterative secant method to search for the image // line. // Convert the ground precision to pixel precision so we can // check for convergence without re-intersecting csm::ImageCoord approxPoint; computeLinearApproximation(ground_pt, approxPoint); csm::ImageCoord approxNextPoint = approxPoint; if (approxNextPoint.line + 1 < m_nLines) { ++approxNextPoint.line; } else { --approxNextPoint.line; } double height, aPrec; computeElevation(ground_pt.x, ground_pt.y, ground_pt.z, height, aPrec, desired_precision); csm::EcefCoord approxIntersect = imageToGround(approxPoint, height); csm::EcefCoord approxNextIntersect = imageToGround(approxNextPoint, height); double lineDX = approxNextIntersect.x - approxIntersect.x; double lineDY = approxNextIntersect.y - approxIntersect.y; double lineDZ = approxNextIntersect.z - approxIntersect.z; double approxLineRes = sqrt(lineDX * lineDX + lineDY * lineDY + lineDZ * lineDZ); // Increase the precision by a small amount to ensure the desired precision is met double pixelPrec = desired_precision / approxLineRes * 0.9; // Start secant method search on the image lines double sampCtr = m_nSamples / 2.0; double firstTime = getImageTime(csm::ImageCoord(0.0, sampCtr)); double lastTime = getImageTime(csm::ImageCoord(m_nLines, sampCtr)); double firstOffset = computeViewingPixel(firstTime, ground_pt, adj, pixelPrec/2).line - 0.5; double lastOffset = computeViewingPixel(lastTime, ground_pt, adj, pixelPrec/2).line - 0.5; // Start secant method search for (int it = 0; it < 30; it++) { double nextTime = ((firstTime * lastOffset) - (lastTime * firstOffset)) / (lastOffset - firstOffset); // Because time across the image is not continuous, find the exposure closest // to the computed nextTime and use that. // I.E. if the computed nextTime is 0.3, and the middle exposure times for // lines are 0.07, 0.17, 0.27, 0.37, and 0.47; then use 0.27 because it is // the closest middle exposure time. auto referenceTimeIt = std::upper_bound(m_intTimeStartTimes.begin(), m_intTimeStartTimes.end(), nextTime); if (referenceTimeIt != m_intTimeStartTimes.begin()) { --referenceTimeIt; } size_t referenceIndex = std::distance(m_intTimeStartTimes.begin(), referenceTimeIt); double computedLine = (nextTime - m_intTimeStartTimes[referenceIndex]) / m_intTimes[referenceIndex] + m_intTimeLines[referenceIndex] - 0.5; // subtract 0.5 for ISIS -> CSM pixel conversion double closestLine = floor(computedLine + 0.5); nextTime = getImageTime(csm::ImageCoord(closestLine, sampCtr)); double nextOffset = computeViewingPixel(nextTime, ground_pt, adj, pixelPrec/2).line - 0.5; // remove the farthest away node if (fabs(firstTime - nextTime) > fabs(lastTime - nextTime)) { firstTime = nextTime; firstOffset = nextOffset; } else { lastTime = nextTime; lastOffset = nextOffset; } if (fabs(lastOffset - firstOffset) < pixelPrec) { break; } } // Avoid division by 0 if the first and last nodes are the same double computedTime = firstTime; if (fabs(lastOffset - firstOffset) > 10e-15) { computedTime = ((firstTime * lastOffset) - (lastTime * firstOffset)) / (lastOffset - firstOffset); } auto referenceTimeIt = std::upper_bound(m_intTimeStartTimes.begin(), m_intTimeStartTimes.end(), computedTime); if (referenceTimeIt != m_intTimeStartTimes.begin()) { --referenceTimeIt; } size_t referenceIndex = std::distance(m_intTimeStartTimes.begin(), referenceTimeIt); double computedLine = (computedTime - m_intTimeStartTimes[referenceIndex]) / m_intTimes[referenceIndex] + m_intTimeLines[referenceIndex] - 0.5; // subtract 0.5 for ISIS -> CSM pixel conversion double closestLine = floor(computedLine + 0.5); // This assumes pixels are the interval [n, n+1) computedTime = getImageTime(csm::ImageCoord(closestLine, sampCtr)); csm::ImageCoord calculatedPixel = computeViewingPixel(computedTime, ground_pt, adj, pixelPrec/2); // The computed pioxel is the detector pixel, so we need to convert that to image lines calculatedPixel.line += closestLine; // Reintersect to ensure the image point actually views the ground point. csm::EcefCoord calculatedPoint = imageToGround(calculatedPixel, height); double dx = ground_pt.x - calculatedPoint.x; double dy = ground_pt.y - calculatedPoint.y; double dz = ground_pt.z - calculatedPoint.z; double len = dx * dx + dy * dy + dz * dz; if (achieved_precision) { *achieved_precision = sqrt(len); } double preSquare = desired_precision * desired_precision; if (warnings && (desired_precision > 0.0) && (preSquare < len)) { std::stringstream msg; msg << "Desired precision not achieved. "; msg << len << " " << preSquare << "\n"; warnings->push_back( csm::Warning(csm::Warning::PRECISION_NOT_MET, msg.str().c_str(), "UsgsAstroLsSensorModel::groundToImage()")); } return calculatedPixel; } //*************************************************************************** // UsgsAstroLsSensorModel::groundToImage //*************************************************************************** csm::ImageCoordCovar UsgsAstroLsSensorModel::groundToImage( const csm::EcefCoordCovar& groundPt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing groundToImage(Covar) for {}, {}, {}, with desired precision {}", groundPt.x, groundPt.y, groundPt.z, desired_precision); // Ground to image with error propagation // Compute corresponding image point csm::EcefCoord gp; gp.x = groundPt.x; gp.y = groundPt.y; gp.z = groundPt.z; csm::ImageCoord ip = groundToImage( gp, desired_precision, achieved_precision, warnings); csm::ImageCoordCovar result(ip.line, ip.samp); // Compute partials ls wrt XYZ std::vector prt(6, 0.0); prt = computeGroundPartials(groundPt); // Error propagation double ltx, lty, ltz; double stx, sty, stz; ltx = prt[0] * groundPt.covariance[0] + prt[1] * groundPt.covariance[3] + prt[2] * groundPt.covariance[6]; lty = prt[0] * groundPt.covariance[1] + prt[1] * groundPt.covariance[4] + prt[2] * groundPt.covariance[7]; ltz = prt[0] * groundPt.covariance[2] + prt[1] * groundPt.covariance[5] + prt[2] * groundPt.covariance[8]; stx = prt[3] * groundPt.covariance[0] + prt[4] * groundPt.covariance[3] + prt[5] * groundPt.covariance[6]; sty = prt[3] * groundPt.covariance[1] + prt[4] * groundPt.covariance[4] + prt[5] * groundPt.covariance[7]; stz = prt[3] * groundPt.covariance[2] + prt[4] * groundPt.covariance[5] + prt[5] * groundPt.covariance[8]; double gp_cov[4]; // Input gp cov in image space gp_cov[0] = ltx * prt[0] + lty * prt[1] + ltz * prt[2]; gp_cov[1] = ltx * prt[3] + lty * prt[4] + ltz * prt[5]; gp_cov[2] = stx * prt[0] + sty * prt[1] + stz * prt[2]; gp_cov[3] = stx * prt[3] + sty * prt[4] + stz * prt[5]; std::vector unmodeled_cov = getUnmodeledError(ip); double sensor_cov[4]; // sensor cov in image space determineSensorCovarianceInImageSpace(gp, sensor_cov); result.covariance[0] = gp_cov[0] + unmodeled_cov[0] + sensor_cov[0]; result.covariance[1] = gp_cov[1] + unmodeled_cov[1] + sensor_cov[1]; result.covariance[2] = gp_cov[2] + unmodeled_cov[2] + sensor_cov[2]; result.covariance[3] = gp_cov[3] + unmodeled_cov[3] + sensor_cov[3]; return result; } //*************************************************************************** // UsgsAstroLsSensorModel::imageToGround //*************************************************************************** csm::EcefCoord UsgsAstroLsSensorModel::imageToGround( const csm::ImageCoord& image_pt, double height, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing imageToGround for {}, {}, {}, with desired precision {}", image_pt.line, image_pt.samp, height, desired_precision); double xc, yc, zc; double vx, vy, vz; double xl, yl, zl; double dxl, dyl, dzl; losToEcf( image_pt.line, image_pt.samp, _no_adjustment, xc, yc, zc, vx, vy, vz, xl, yl, zl); double aPrec; double x, y, z; losEllipsoidIntersect( height, xc, yc, zc, xl, yl, zl, x, y, z, aPrec, desired_precision); if (achieved_precision) *achieved_precision = aPrec; if (warnings && (desired_precision > 0.0) && (aPrec > desired_precision)) { warnings->push_back( csm::Warning( csm::Warning::PRECISION_NOT_MET, "Desired precision not achieved.", "UsgsAstroLsSensorModel::imageToGround()")); } /* MESSAGE_LOG(m_logger, "imageToGround for {} {} {} achieved precision {}", image_pt.line, image_pt.samp, height, achieved_precision) */ return csm::EcefCoord(x, y, z); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::determineSensorCovarianceInImageSpace //*************************************************************************** void UsgsAstroLsSensorModel::determineSensorCovarianceInImageSpace( csm::EcefCoord &gp, double sensor_cov[4] ) const { MESSAGE_LOG(m_logger, "Calculating determineSensorCovarianceInImageSpace for {} {} {}", gp.x, gp.y, gp.z) int i, j, totalAdjParams; totalAdjParams = getNumParameters(); std::vector sensor_partials = computeAllSensorPartials(gp); sensor_cov[0] = 0.0; sensor_cov[1] = 0.0; sensor_cov[2] = 0.0; sensor_cov[3] = 0.0; for (i = 0; i < totalAdjParams; i++) { for (j = 0; j < totalAdjParams; j++) { sensor_cov[0] += sensor_partials[i].first * getParameterCovariance(i, j) * sensor_partials[j].first; sensor_cov[1] += sensor_partials[i].second * getParameterCovariance(i, j) * sensor_partials[j].first; sensor_cov[2] += sensor_partials[i].first * getParameterCovariance(i, j) * sensor_partials[j].second; sensor_cov[3] += sensor_partials[i].second * getParameterCovariance(i, j) * sensor_partials[j].second; } } } //*************************************************************************** // UsgsAstroLsSensorModel::imageToGround //*************************************************************************** csm::EcefCoordCovar UsgsAstroLsSensorModel::imageToGround( const csm::ImageCoordCovar& image_pt, double height, double heightVariance, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Calculating imageToGround (with error propagation) for {}, {}, {} with height varinace {} and desired precision {}", image_pt.line, image_pt.samp, height, heightVariance, desired_precision) // Image to ground with error propagation // Use numerical partials const double DELTA_IMAGE = 1.0; const double DELTA_GROUND = m_gsd; csm::ImageCoord ip(image_pt.line, image_pt.samp); csm::EcefCoord gp = imageToGround( ip, height, desired_precision, achieved_precision, warnings); // Compute numerical partials xyz wrt to lsh ip.line = image_pt.line + DELTA_IMAGE; ip.samp = image_pt.samp; csm::EcefCoord gpl = imageToGround(ip, height, desired_precision); double xpl = (gpl.x - gp.x) / DELTA_IMAGE; double ypl = (gpl.y - gp.y) / DELTA_IMAGE; double zpl = (gpl.z - gp.z) / DELTA_IMAGE; ip.line = image_pt.line; ip.samp = image_pt.samp + DELTA_IMAGE; csm::EcefCoord gps = imageToGround(ip, height, desired_precision); double xps = (gps.x - gp.x) / DELTA_IMAGE; double yps = (gps.y - gp.y) / DELTA_IMAGE; double zps = (gps.z - gp.z) / DELTA_IMAGE; ip.line = image_pt.line; ip.samp = image_pt.samp; // +DELTA_IMAGE; csm::EcefCoord gph = imageToGround(ip, height + DELTA_GROUND, desired_precision); double xph = (gph.x - gp.x) / DELTA_GROUND; double yph = (gph.y - gp.y) / DELTA_GROUND; double zph = (gph.z - gp.z) / DELTA_GROUND; // Convert sensor covariance to image space double sCov[4]; determineSensorCovarianceInImageSpace(gp, sCov); std::vector unmod = getUnmodeledError(image_pt); double iCov[4]; iCov[0] = image_pt.covariance[0] + sCov[0] + unmod[0]; iCov[1] = image_pt.covariance[1] + sCov[1] + unmod[1]; iCov[2] = image_pt.covariance[2] + sCov[2] + unmod[2]; iCov[3] = image_pt.covariance[3] + sCov[3] + unmod[3]; // Temporary matrix product double t00, t01, t02, t10, t11, t12, t20, t21, t22; t00 = xpl * iCov[0] + xps * iCov[2]; t01 = xpl * iCov[1] + xps * iCov[3]; t02 = xph * heightVariance; t10 = ypl * iCov[0] + yps * iCov[2]; t11 = ypl * iCov[1] + yps * iCov[3]; t12 = yph * heightVariance; t20 = zpl * iCov[0] + zps * iCov[2]; t21 = zpl * iCov[1] + zps * iCov[3]; t22 = zph * heightVariance; // Ground covariance csm::EcefCoordCovar result; result.x = gp.x; result.y = gp.y; result.z = gp.z; result.covariance[0] = t00 * xpl + t01 * xps + t02 * xph; result.covariance[1] = t00 * ypl + t01 * yps + t02 * yph; result.covariance[2] = t00 * zpl + t01 * zps + t02 * zph; result.covariance[3] = t10 * xpl + t11 * xps + t12 * xph; result.covariance[4] = t10 * ypl + t11 * yps + t12 * yph; result.covariance[5] = t10 * zpl + t11 * zps + t12 * zph; result.covariance[6] = t20 * xpl + t21 * xps + t22 * xph; result.covariance[7] = t20 * ypl + t21 * yps + t22 * yph; result.covariance[8] = t20 * zpl + t21 * zps + t22 * zph; return result; } //*************************************************************************** // UsgsAstroLsSensorModel::imageToProximateImagingLocus //*************************************************************************** csm::EcefLocus UsgsAstroLsSensorModel::imageToProximateImagingLocus( const csm::ImageCoord& image_pt, const csm::EcefCoord& ground_pt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing imageToProximateImagingLocus (ground {}, {}, {}) for image point {}, {} with desired precision {}", ground_pt.x, ground_pt.y, ground_pt.z, image_pt.line, image_pt.samp, desired_precision); // Object ray unit direction near given ground location const double DELTA_GROUND = m_gsd; double x = ground_pt.x; double y = ground_pt.y; double z = ground_pt.z; // Elevation at input ground point double height, aPrec; computeElevation(x, y, z, height, aPrec, desired_precision); // Ground point on object ray with the same elevation csm::EcefCoord gp1 = imageToGround( image_pt, height, desired_precision, achieved_precision); // Vector between 2 ground points above double dx1 = x - gp1.x; double dy1 = y - gp1.y; double dz1 = z - gp1.z; // Unit vector along object ray csm::EcefCoord gp2 = imageToGround( image_pt, height - DELTA_GROUND, desired_precision, achieved_precision); double dx2 = gp2.x - gp1.x; double dy2 = gp2.y - gp1.y; double dz2 = gp2.z - gp1.z; double mag2 = sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2); dx2 /= mag2; dy2 /= mag2; dz2 /= mag2; // Point on object ray perpendicular to input point // Locus csm::EcefLocus locus; double scale = dx1 * dx2 + dy1 * dy2 + dz1 * dz2; gp2.x = gp1.x + scale * dx2; gp2.y = gp1.y + scale * dy2; gp2.z = gp1.z + scale * dz2; double hLocus; computeElevation(gp2.x, gp2.y, gp2.z, hLocus, aPrec, desired_precision); locus.point = imageToGround( image_pt, hLocus, desired_precision, achieved_precision, warnings); locus.direction.x = dx2; locus.direction.y = dy2; locus.direction.z = dz2; return locus; } //*************************************************************************** // UsgsAstroLsSensorModel::imageToRemoteImagingLocus //*************************************************************************** csm::EcefLocus UsgsAstroLsSensorModel::imageToRemoteImagingLocus( const csm::ImageCoord& image_pt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Calculating imageToRemoteImagingLocus for point {}, {} with desired precision {}", image_pt.line, image_pt.samp, desired_precision) double vx, vy, vz; csm::EcefLocus locus; losToEcf( image_pt.line, image_pt.samp, _no_adjustment, locus.point.x, locus.point.y, locus.point.z, vx, vy, vz, locus.direction.x, locus.direction.y, locus.direction.z); // losToEcf computes the negative look vector, so negate it locus.direction.x = -locus.direction.x; locus.direction.y = -locus.direction.y; locus.direction.z = -locus.direction.z; return locus; } //--------------------------------------------------------------------------- // Uncertainty Propagation //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::computeGroundPartials //*************************************************************************** std::vector UsgsAstroLsSensorModel::computeGroundPartials( const csm::EcefCoord& ground_pt) const { MESSAGE_LOG(m_logger, "Computing computeGroundPartials for point {}, {}, {}", ground_pt.x, ground_pt.y, ground_pt.z) double GND_DELTA = m_gsd; // Partial of line, sample wrt X, Y, Z double x = ground_pt.x; double y = ground_pt.y; double z = ground_pt.z; csm::ImageCoord ipB = groundToImage(ground_pt); csm::ImageCoord ipX = groundToImage(csm::EcefCoord(x + GND_DELTA, y, z)); csm::ImageCoord ipY = groundToImage(csm::EcefCoord(x, y + GND_DELTA, z)); csm::ImageCoord ipZ = groundToImage(csm::EcefCoord(x, y, z + GND_DELTA)); std::vector partials(6, 0.0); partials[0] = (ipX.line - ipB.line) / GND_DELTA; partials[3] = (ipX.samp - ipB.samp) / GND_DELTA; partials[1] = (ipY.line - ipB.line) / GND_DELTA; partials[4] = (ipY.samp - ipB.samp) / GND_DELTA; partials[2] = (ipZ.line - ipB.line) / GND_DELTA; partials[5] = (ipZ.samp - ipB.samp) / GND_DELTA; return partials; } //*************************************************************************** // UsgsAstroLsSensorModel::computeSensorPartials //*************************************************************************** csm::RasterGM::SensorPartials UsgsAstroLsSensorModel::computeSensorPartials( int index, const csm::EcefCoord& ground_pt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Calculating computeSensorPartials for ground point {}, {}, {} with desired precision {}", ground_pt.x, ground_pt.y, ground_pt.z, desired_precision) // Compute image coordinate first csm::ImageCoord img_pt = groundToImage( ground_pt, desired_precision, achieved_precision); // Call overloaded function return computeSensorPartials( index, img_pt, ground_pt, desired_precision, achieved_precision, warnings); } //*************************************************************************** // UsgsAstroLsSensorModel::computeSensorPartials //*************************************************************************** csm::RasterGM::SensorPartials UsgsAstroLsSensorModel::computeSensorPartials( int index, const csm::ImageCoord& image_pt, const csm::EcefCoord& ground_pt, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Calculating computeSensorPartials (with image points {}, {}) for ground point {}, {}, {} with desired precision {}", image_pt.line, image_pt.samp, ground_pt.x, ground_pt.y, ground_pt.z, desired_precision) // Compute numerical partials ls wrt specific parameter const double DELTA = m_gsd; std::vector adj(UsgsAstroLsSensorModel::NUM_PARAMETERS, 0.0); adj[index] = DELTA; csm::ImageCoord img1 = groundToImage( ground_pt, adj, desired_precision, achieved_precision, warnings); double line_partial = (img1.line - image_pt.line) / DELTA; double sample_partial = (img1.samp - image_pt.samp) / DELTA; return csm::RasterGM::SensorPartials(line_partial, sample_partial); } //*************************************************************************** // UsgsAstroLsSensorModel::computeAllSensorPartials //*************************************************************************** std::vector UsgsAstroLsSensorModel::computeAllSensorPartials( const csm::EcefCoord& ground_pt, csm::param::Set pSet, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing computeAllSensorPartials for ground point {}, {}, {} with desired precision {}", ground_pt.x, ground_pt.y, ground_pt.z, desired_precision) csm::ImageCoord image_pt = groundToImage( ground_pt, desired_precision, achieved_precision, warnings); return computeAllSensorPartials( image_pt, ground_pt, pSet, desired_precision, achieved_precision, warnings); } //*************************************************************************** // UsgsAstroLsSensorModel::computeAllSensorPartials //*************************************************************************** std::vector UsgsAstroLsSensorModel::computeAllSensorPartials( const csm::ImageCoord& image_pt, const csm::EcefCoord& ground_pt, csm::param::Set pSet, double desired_precision, double* achieved_precision, csm::WarningList* warnings) const { MESSAGE_LOG(m_logger, "Computing computeAllSensorPartials for image {} {} and ground {}, {}, {} with desired precision {}", image_pt.line, image_pt.samp, ground_pt.x, ground_pt.y, ground_pt.z, desired_precision) std::vector indices = getParameterSetIndices(pSet); size_t num = indices.size(); std::vector partials; for (int index = 0; index < num; index++) { partials.push_back( computeSensorPartials( indices[index], image_pt, ground_pt, desired_precision, achieved_precision, warnings)); } return partials; } //*************************************************************************** // UsgsAstroLsSensorModel::getParameterCovariance //*************************************************************************** double UsgsAstroLsSensorModel::getParameterCovariance( int index1, int index2) const { int index = UsgsAstroLsSensorModel::NUM_PARAMETERS * index1 + index2; MESSAGE_LOG(m_logger, "getParameterCovariance for {} {} is {}", index1, index2, m_covariance[index]) return m_covariance[index]; } //*************************************************************************** // UsgsAstroLsSensorModel::setParameterCovariance //*************************************************************************** void UsgsAstroLsSensorModel::setParameterCovariance( int index1, int index2, double covariance) { int index = UsgsAstroLsSensorModel::NUM_PARAMETERS * index1 + index2; MESSAGE_LOG(m_logger, "setParameterCovariance for {} {} is {}", index1, index2, m_covariance[index]) m_covariance[index] = covariance; } //--------------------------------------------------------------------------- // Time and Trajectory //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::getTrajectoryIdentifier //*************************************************************************** std::string UsgsAstroLsSensorModel::getTrajectoryIdentifier() const { return "UNKNOWN"; } //*************************************************************************** // UsgsAstroLsSensorModel::getReferenceDateAndTime //*************************************************************************** std::string UsgsAstroLsSensorModel::getReferenceDateAndTime() const { throw csm::Error( csm::Error::UNSUPPORTED_FUNCTION, "Unsupported function", "UsgsAstroLsSensorModel::getReferenceDateAndTime"); } //*************************************************************************** // UsgsAstroLsSensorModel::getImageTime //*************************************************************************** double UsgsAstroLsSensorModel::getImageTime( const csm::ImageCoord& image_pt) const { // Flip image taken backwards double line1 = image_pt.line; // CSM image convention: UL pixel center == (0.5, 0.5) // USGS image convention: UL pixel center == (1.0, 1.0) double lineCSMFull = line1; double lineUSGSFull = floor(lineCSMFull) + 0.5; // These calculation assumes that the values in the integration time // vectors are in terms of ISIS' pixels auto referenceLineIt = std::upper_bound(m_intTimeLines.begin(), m_intTimeLines.end(), lineUSGSFull); if (referenceLineIt != m_intTimeLines.begin()) { --referenceLineIt; } size_t referenceIndex = std::distance(m_intTimeLines.begin(), referenceLineIt); double time = m_intTimeStartTimes[referenceIndex] + m_intTimes[referenceIndex] * (lineUSGSFull - m_intTimeLines[referenceIndex]); MESSAGE_LOG(m_logger, "getImageTime for image line {} is {}", image_pt.line, time) return time; } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorPosition //*************************************************************************** csm::EcefCoord UsgsAstroLsSensorModel::getSensorPosition( const csm::ImageCoord& imagePt) const { MESSAGE_LOG(m_logger, "getSensorPosition at line {}", imagePt.line) return getSensorPosition(getImageTime(imagePt)); } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorPosition //*************************************************************************** csm::EcefCoord UsgsAstroLsSensorModel::getSensorPosition(double time) const { double x, y, z, vx, vy, vz; getAdjSensorPosVel(time, _no_adjustment, x, y, z, vx, vy, vz); MESSAGE_LOG(m_logger, "getSensorPosition at {}", time) return csm::EcefCoord(x, y, z); } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorVelocity //*************************************************************************** csm::EcefVector UsgsAstroLsSensorModel::getSensorVelocity( const csm::ImageCoord& imagePt) const { MESSAGE_LOG(m_logger, "getSensorVelocity at {}", imagePt.line) return getSensorVelocity(getImageTime(imagePt)); } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorVelocity //*************************************************************************** csm::EcefVector UsgsAstroLsSensorModel::getSensorVelocity(double time) const { double x, y, z, vx, vy, vz; getAdjSensorPosVel(time, _no_adjustment, x, y, z, vx, vy, vz); MESSAGE_LOG(m_logger, "getSensorVelocity at {}", time) return csm::EcefVector(vx, vy, vz); } //--------------------------------------------------------------------------- // Sensor Model Parameters //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::setParameterValue //*************************************************************************** void UsgsAstroLsSensorModel::setParameterValue(int index, double value) { m_currentParameterValue[index] = value; } //*************************************************************************** // UsgsAstroLsSensorModel::getParameterValue //*************************************************************************** double UsgsAstroLsSensorModel::getParameterValue(int index) const { return m_currentParameterValue[index]; } //*************************************************************************** // UsgsAstroLsSensorModel::getParameterName //*************************************************************************** std::string UsgsAstroLsSensorModel::getParameterName(int index) const { return PARAMETER_NAME[index]; } std::string UsgsAstroLsSensorModel::getParameterUnits(int index) const { // All parameters are meters or scaled to meters return "m"; } //*************************************************************************** // UsgsAstroLsSensorModel::getNumParameters //*************************************************************************** int UsgsAstroLsSensorModel::getNumParameters() const { return UsgsAstroLsSensorModel::NUM_PARAMETERS; } //*************************************************************************** // UsgsAstroLsSensorModel::getParameterType //*************************************************************************** csm::param::Type UsgsAstroLsSensorModel::getParameterType(int index) const { return m_parameterType[index]; } //*************************************************************************** // UsgsAstroLsSensorModel::setParameterType //*************************************************************************** void UsgsAstroLsSensorModel::setParameterType( int index, csm::param::Type pType) { m_parameterType[index] = pType; } //--------------------------------------------------------------------------- // Sensor Model Information //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::getPedigree //*************************************************************************** std::string UsgsAstroLsSensorModel::getPedigree() const { return "USGS_LINE_SCANNER"; } //*************************************************************************** // UsgsAstroLsSensorModel::getImageIdentifier //*************************************************************************** std::string UsgsAstroLsSensorModel::getImageIdentifier() const { return m_imageIdentifier; } //*************************************************************************** // UsgsAstroLsSensorModel::setImageIdentifier //*************************************************************************** void UsgsAstroLsSensorModel::setImageIdentifier( const std::string& imageId, csm::WarningList* warnings) { // Image id should include the suffix without the path name m_imageIdentifier = imageId; } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorIdentifier //*************************************************************************** std::string UsgsAstroLsSensorModel::getSensorIdentifier() const { return m_sensorIdentifier; } //*************************************************************************** // UsgsAstroLsSensorModel::getPlatformIdentifier //*************************************************************************** std::string UsgsAstroLsSensorModel::getPlatformIdentifier() const { return m_platformIdentifier; } //*************************************************************************** // UsgsAstroLsSensorModel::setReferencePoint //*************************************************************************** void UsgsAstroLsSensorModel::setReferencePoint(const csm::EcefCoord& ground_pt) { m_referencePointXyz = ground_pt; } //*************************************************************************** // UsgsAstroLsSensorModel::getReferencePoint //*************************************************************************** csm::EcefCoord UsgsAstroLsSensorModel::getReferencePoint() const { // Return ground point at image center return m_referencePointXyz; } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorModelName //*************************************************************************** std::string UsgsAstroLsSensorModel::getModelName() const { return UsgsAstroLsSensorModel::_SENSOR_MODEL_NAME; } //*************************************************************************** // UsgsAstroLsSensorModel::getImageStart //*************************************************************************** csm::ImageCoord UsgsAstroLsSensorModel::getImageStart() const { return csm::ImageCoord(0.0, 0.0); } //*************************************************************************** // UsgsAstroLsSensorModel::getImageSize //*************************************************************************** csm::ImageVector UsgsAstroLsSensorModel::getImageSize() const { return csm::ImageVector(m_nLines, m_nSamples); } //--------------------------------------------------------------------------- // Sensor Model State //--------------------------------------------------------------------------- // // //*************************************************************************** // // UsgsAstroLsSensorModel::getSensorModelState // //*************************************************************************** // std::string UsgsAstroLsSensorModel::setModelState(std::string stateString) const // { // auto j = json::parse(stateString); // int num_params = NUM_PARAMETERS; // int num_paramsSq = num_params * num_params; // // m_imageIdentifier = j["m_imageIdentifier"]; // m_sensorName = j["m_sensorName"]; // m_nLines = j["m_nLines"]; // m_nSamples = j["m_nSamples"]; // m_platformFlag = j["m_platformFlag"]; // m_intTimeLines = j["m_intTimeLines"].get>(); // m_intTimeStartTimes = j["m_intTimeStartTimes"].get>(); // m_intTimes = j["m_intTimes"].get>(); // m_startingEphemerisTime = j["m_startingEphemerisTime"]; // m_centerEphemerisTime = j["m_centerEphemerisTime"]; // m_detectorSampleSumming = j["m_detectorSampleSumming"]; // m_startingSample = j["m_startingSample"]; // m_ikCode = j["m_ikCode"]; // m_focalLength = j["m_focalLength"]; // m_isisZDirection = j["m_isisZDirection"]; // for (int i = 0; i < 3; i++) { // m_opticalDistCoef[i] = j["m_opticalDistCoef"][i]; // m_iTransS[i] = j["m_iTransS"][i]; // m_iTransL[i] = j["m_iTransL"][i]; // } // m_detectorSampleOrigin = j["m_detectorSampleOrigin"]; // m_detectorLineOrigin = j["m_detectorLineOrigin"]; // for (int i = 0; i < 9; i++) { // m_mountingMatrix[i] = j["m_mountingMatrix"][i]; // } // m_majorAxis = j["m_majorAxis"]; // m_minorAxis = j["m_minorAxis"]; // m_platformIdentifier = j["m_platformIdentifier"]; // m_sensorIdentifier = j["m_sensorIdentifier"]; // m_minElevation = j["m_minElevation"]; // m_maxElevation = j["m_maxElevation"]; // m_dtEphem = j["m_dtEphem"]; // m_t0Ephem = j["m_t0Ephem"]; // m_dtQuat = j["m_dtQuat"]; // m_t0Quat = j["m_t0Quat"]; // m_numPositions = j["m_numPositions"]; // m_numQuaternions = j["m_numQuaternions"]; // m_referencePointXyz.x = j["m_referencePointXyz"][0]; // m_referencePointXyz.y = j["m_referencePointXyz"][1]; // m_referencePointXyz.z = j["m_referencePointXyz"][2]; // m_gsd = j["m_gsd"]; // m_flyingHeight = j["m_flyingHeight"]; // m_halfSwath = j["m_halfSwath"]; // m_halfTime = j["m_halfTime"]; // // Vector = is overloaded so explicit get with type required. // m_positions = j["m_positions"].get>(); // m_velocities = j["m_velocities"].get>(); // m_quaternions = j["m_quaternions"].get>(); // m_currentParameterValue = j["m_currentParameterValue"].get>(); // m_covariance = j["m_covariance"].get>(); // // for (int i = 0; i < num_params; i++) { // for (int k = 0; k < NUM_PARAM_TYPES; k++) { // if (j["m_parameterType"][i] == PARAM_STRING_ALL[k]) { // m_parameterType[i] = PARAM_CHAR_ALL[k]; // break; // } // } // } // // } //--------------------------------------------------------------------------- // Monoscopic Mensuration //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::getValidHeightRange //*************************************************************************** std::pair UsgsAstroLsSensorModel::getValidHeightRange() const { return std::pair(m_minElevation, m_maxElevation); } //*************************************************************************** // UsgsAstroLsSensorModel::getValidImageRange //*************************************************************************** std::pair UsgsAstroLsSensorModel::getValidImageRange() const { return std::pair( csm::ImageCoord(0.0, 0.0), csm::ImageCoord(m_nLines, m_nSamples)); } //*************************************************************************** // UsgsAstroLsSensorModel::getIlluminationDirection //*************************************************************************** csm::EcefVector UsgsAstroLsSensorModel::getIlluminationDirection( const csm::EcefCoord& groundPt) const { MESSAGE_LOG(m_logger, "Accessing illimination direction of ground point" "{} {} {}." "Illimination direction is not supported, throwing exception", groundPt.x, groundPt.y, groundPt.z); throw csm::Error( csm::Error::UNSUPPORTED_FUNCTION, "Unsupported function", "UsgsAstroLsSensorModel::getIlluminationDirection"); } //--------------------------------------------------------------------------- // Error Correction //--------------------------------------------------------------------------- //*************************************************************************** // UsgsAstroLsSensorModel::getNumGeometricCorrectionSwitches //*************************************************************************** int UsgsAstroLsSensorModel::getNumGeometricCorrectionSwitches() const { return 0; } //*************************************************************************** // UsgsAstroLsSensorModel::getGeometricCorrectionName //*************************************************************************** std::string UsgsAstroLsSensorModel::getGeometricCorrectionName(int index) const { MESSAGE_LOG(m_logger, "Accessing name of geometric correction switch {}. " "Geometric correction switches are not supported, throwing exception", index); // Since there are no geometric corrections, all indices are out of range throw csm::Error( csm::Error::INDEX_OUT_OF_RANGE, "Index is out of range.", "UsgsAstroLsSensorModel::getGeometricCorrectionName"); } //*************************************************************************** // UsgsAstroLsSensorModel::setGeometricCorrectionSwitch //*************************************************************************** void UsgsAstroLsSensorModel::setGeometricCorrectionSwitch( int index, bool value, csm::param::Type pType) { MESSAGE_LOG(m_logger, "Setting geometric correction switch {} to {} " "with parameter type {}. " "Geometric correction switches are not supported, throwing exception", index, value, pType); // Since there are no geometric corrections, all indices are out of range throw csm::Error( csm::Error::INDEX_OUT_OF_RANGE, "Index is out of range.", "UsgsAstroLsSensorModel::setGeometricCorrectionSwitch"); } //*************************************************************************** // UsgsAstroLsSensorModel::getGeometricCorrectionSwitch //*************************************************************************** bool UsgsAstroLsSensorModel::getGeometricCorrectionSwitch(int index) const { MESSAGE_LOG(m_logger, "Accessing value of geometric correction switch {}. " "Geometric correction switches are not supported, throwing exception", index); // Since there are no geometric corrections, all indices are out of range throw csm::Error( csm::Error::INDEX_OUT_OF_RANGE, "Index is out of range.", "UsgsAstroLsSensorModel::getGeometricCorrectionSwitch"); } //*************************************************************************** // UsgsAstroLsSensorModel::getCrossCovarianceMatrix //*************************************************************************** std::vector UsgsAstroLsSensorModel::getCrossCovarianceMatrix( const csm::GeometricModel& comparisonModel, csm::param::Set pSet, const csm::GeometricModel::GeometricModelList& otherModels) const { // No correlation between models. const std::vector& indices = getParameterSetIndices(pSet); size_t num_rows = indices.size(); const std::vector& indices2 = comparisonModel.getParameterSetIndices(pSet); size_t num_cols = indices.size(); return std::vector(num_rows * num_cols, 0.0); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getCorrelationModel //*************************************************************************** const csm::CorrelationModel& UsgsAstroLsSensorModel::getCorrelationModel() const { // All Line Scanner images are assumed uncorrelated return _no_corr_model; } //*************************************************************************** // UsgsAstroLsSensorModel::getUnmodeledCrossCovariance //*************************************************************************** std::vector UsgsAstroLsSensorModel::getUnmodeledCrossCovariance( const csm::ImageCoord& pt1, const csm::ImageCoord& pt2) const { // No unmodeled error return std::vector(4, 0.0); } //*************************************************************************** // UsgsAstroLsSensorModel::getCollectionIdentifier //*************************************************************************** std::string UsgsAstroLsSensorModel::getCollectionIdentifier() const { return "UNKNOWN"; } //*************************************************************************** // UsgsAstroLsSensorModel::hasShareableParameters //*************************************************************************** bool UsgsAstroLsSensorModel::hasShareableParameters() const { // Parameter sharing is not supported for this sensor return false; } //*************************************************************************** // UsgsAstroLsSensorModel::isParameterShareable //*************************************************************************** bool UsgsAstroLsSensorModel::isParameterShareable(int index) const { // Parameter sharing is not supported for this sensor return false; } //*************************************************************************** // UsgsAstroLsSensorModel::getParameterSharingCriteria //*************************************************************************** csm::SharingCriteria UsgsAstroLsSensorModel::getParameterSharingCriteria( int index) const { MESSAGE_LOG(m_logger, "Checking sharing criteria for parameter {}. " "Sharing is not supported, throwing exception", index); // Parameter sharing is not supported for this sensor, // all indices are out of range throw csm::Error( csm::Error::INDEX_OUT_OF_RANGE, "Index out of range.", "UsgsAstroLsSensorModel::getParameterSharingCriteria"); } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorType //*************************************************************************** std::string UsgsAstroLsSensorModel::getSensorType() const { return CSM_SENSOR_TYPE_EO; } //*************************************************************************** // UsgsAstroLsSensorModel::getSensorMode //*************************************************************************** std::string UsgsAstroLsSensorModel::getSensorMode() const { return CSM_SENSOR_MODE_PB; } //*************************************************************************** // UsgsAstroLsSensorModel::getVersion //*************************************************************************** csm::Version UsgsAstroLsSensorModel::getVersion() const { return csm::Version(1, 0, 0); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getEllipsoid //*************************************************************************** csm::Ellipsoid UsgsAstroLsSensorModel::getEllipsoid() const { return csm::Ellipsoid(m_majorAxis, m_minorAxis); } void UsgsAstroLsSensorModel::setEllipsoid( const csm::Ellipsoid &ellipsoid) { m_majorAxis = ellipsoid.getSemiMajorRadius(); m_minorAxis = ellipsoid.getSemiMinorRadius(); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getValue //*************************************************************************** double UsgsAstroLsSensorModel::getValue( int index, const std::vector &adjustments) const { return m_currentParameterValue[index] + adjustments[index]; } //*************************************************************************** // Functions pulled out of losToEcf and computeViewingPixel // ************************************************************************** void UsgsAstroLsSensorModel::getQuaternions(const double& time, double q[4]) const{ int nOrder = 8; if (m_platformFlag == 0) nOrder = 4; int nOrderQuat = nOrder; if (m_numQuaternions < 6 && nOrder == 8) nOrderQuat = 4; MESSAGE_LOG(m_logger, "Calculating getQuaternions for time {} with {}" "order lagrange", time, nOrder) lagrangeInterp( m_numQuaternions/4, &m_quaternions[0], m_t0Quat, m_dtQuat, time, 4, nOrderQuat, q); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::calculateAttitudeCorrection //*************************************************************************** void UsgsAstroLsSensorModel::calculateAttitudeCorrection( const double& time, const std::vector& adj, double attCorr[9]) const { MESSAGE_LOG(m_logger, "Computing calculateAttitudeCorrection (with adjustment)" "for time {}", time) double aTime = time - m_t0Quat; double euler[3]; double nTime = aTime / m_halfTime; double nTime2 = nTime * nTime; euler[0] = (getValue(6, adj) + getValue(9, adj)* nTime + getValue(12, adj)* nTime2) / m_flyingHeight; euler[1] = (getValue(7, adj) + getValue(10, adj)* nTime + getValue(13, adj)* nTime2) / m_flyingHeight; euler[2] = (getValue(8, adj) + getValue(11, adj)* nTime + getValue(14, adj)* nTime2) / m_halfSwath; MESSAGE_LOG(m_logger, "calculateAttitudeCorrection: euler {} {} {}", euler[0], euler[1], euler[2]) calculateRotationMatrixFromEuler(euler, attCorr); } //*************************************************************************** // UsgsAstroLsSensorModel::losToEcf //*************************************************************************** void UsgsAstroLsSensorModel::losToEcf( const double& line, // CSM image convention const double& sample, // UL pixel center == (0.5, 0.5) const std::vector& adj, // Parameter Adjustments for partials double& xc, // output sensor x coordinate double& yc, // output sensor y coordinate double& zc, // output sensor z coordinate double& vx, // output sensor x velocity double& vy, // output sensor y velocity double& vz, // output sensor z velocity double& bodyLookX, // output line-of-sight x coordinate double& bodyLookY, // output line-of-sight y coordinate double& bodyLookZ) const // output line-of-sight z coordinate { //# private_func_description // Computes image ray (look vector) in ecf coordinate system. // Compute adjusted sensor position and velocity MESSAGE_LOG(m_logger, "Computing losToEcf (with adjustments) for" "line {} sample {}", line, sample) double time = getImageTime(csm::ImageCoord(line, sample)); getAdjSensorPosVel(time, adj, xc, yc, zc, vx, vy, vz); // CSM image image convention: UL pixel center == (0.5, 0.5) // USGS image convention: UL pixel center == (1.0, 1.0) double sampleCSMFull = sample; double sampleUSGSFull = sampleCSMFull; double fractionalLine = line - floor(line); // Compute distorted image coordinates in mm (sample, line on image (pixels) -> focal plane double distortedFocalPlaneX, distortedFocalPlaneY; computeDistortedFocalPlaneCoordinates( fractionalLine, sampleUSGSFull, m_detectorSampleOrigin, m_detectorLineOrigin, m_detectorSampleSumming, 1.0, m_startingSample, 0.0, m_iTransS, m_iTransL, distortedFocalPlaneX, distortedFocalPlaneY); // Remove lens double undistortedFocalPlaneX, undistortedFocalPlaneY; removeDistortion(distortedFocalPlaneX, distortedFocalPlaneY, undistortedFocalPlaneX, undistortedFocalPlaneY, m_opticalDistCoeffs, m_distortionType); // Define imaging ray (look vector) in camera space double cameraLook[3]; createCameraLookVector(undistortedFocalPlaneX, undistortedFocalPlaneY, m_zDirection, m_focalLength, cameraLook); // Apply attitude correction double attCorr[9]; calculateAttitudeCorrection(time, adj, attCorr); double correctedCameraLook[3]; correctedCameraLook[0] = attCorr[0] * cameraLook[0] + attCorr[1] * cameraLook[1] + attCorr[2] * cameraLook[2]; correctedCameraLook[1] = attCorr[3] * cameraLook[0] + attCorr[4] * cameraLook[1] + attCorr[5] * cameraLook[2]; correctedCameraLook[2] = attCorr[6] * cameraLook[0] + attCorr[7] * cameraLook[1] + attCorr[8] * cameraLook[2]; MESSAGE_LOG(m_logger, "losToEcf: corrected camera look vector {} {} {}", correctedCameraLook[0], correctedCameraLook[1], correctedCameraLook[2]) // Rotate the look vector into the body fixed frame from the camera reference frame by applying the rotation matrix from the sensor quaternions double quaternions[4]; getQuaternions(time, quaternions); double cameraToBody[9]; calculateRotationMatrixFromQuaternions(quaternions, cameraToBody); bodyLookX = cameraToBody[0] * correctedCameraLook[0] + cameraToBody[1] * correctedCameraLook[1] + cameraToBody[2] * correctedCameraLook[2]; bodyLookY = cameraToBody[3] * correctedCameraLook[0] + cameraToBody[4] * correctedCameraLook[1] + cameraToBody[5] * correctedCameraLook[2]; bodyLookZ = cameraToBody[6] * correctedCameraLook[0] + cameraToBody[7] * correctedCameraLook[1] + cameraToBody[8] * correctedCameraLook[2]; MESSAGE_LOG(m_logger, "losToEcf: body look vector {} {} {}", bodyLookX, bodyLookY, bodyLookZ) } //*************************************************************************** // UsgsAstroLsSensorModel::lightAberrationCorr //************************************************************************** void UsgsAstroLsSensorModel::lightAberrationCorr( const double& vx, const double& vy, const double& vz, const double& xl, const double& yl, const double& zl, double& dxl, double& dyl, double& dzl) const { MESSAGE_LOG(m_logger, "Computing lightAberrationCorr for camera velocity" "{} {} {} and image ray {} {} {}", vx, vy, vz, xl, yl, zl) //# func_description // Computes light aberration correction vector // Compute angle between the image ray and the velocity vector double dotP = xl * vx + yl * vy + zl * vz; double losMag = sqrt(xl * xl + yl * yl + zl * zl); double velocityMag = sqrt(vx * vx + vy * vy + vz * vz); double cosThetap = dotP / (losMag * velocityMag); double sinThetap = sqrt(1.0 - cosThetap * cosThetap); // Image ray is parallel to the velocity vector if (1.0 == fabs(cosThetap)) { dxl = 0.0; dyl = 0.0; dzl = 0.0; MESSAGE_LOG(m_logger, "lightAberrationCorr: image ray is parallel" "to velocity vector") } // Compute the angle between the corrected image ray and spacecraft // velocity. This key equation is derived using Lorentz transform. double speedOfLight = 299792458.0; // meters per second double beta = velocityMag / speedOfLight; double cosTheta = (beta - cosThetap) / (beta * cosThetap - 1.0); double sinTheta = sqrt(1.0 - cosTheta * cosTheta); // Compute line-of-sight correction double cfac = ((cosTheta * sinThetap - sinTheta * cosThetap) * losMag) / (sinTheta * velocityMag); dxl = cfac * vx; dyl = cfac * vy; dzl = cfac * vz; MESSAGE_LOG(m_logger, "lightAberrationCorr: light of sight correction" "{} {} {}", dxl, dyl, dzl) } //*************************************************************************** // UsgsAstroLsSensorModel::computeElevation //*************************************************************************** void UsgsAstroLsSensorModel::computeElevation( const double& x, const double& y, const double& z, double& height, double& achieved_precision, const double& desired_precision) const { MESSAGE_LOG(m_logger, "Calculating computeElevation for {} {} {}" "with desired precision {}", x, y, z, desired_precision) // Compute elevation given xyz // Requires semi-major-axis and eccentricity-square const int MKTR = 10; double ecc_sqr = 1.0 - m_minorAxis * m_minorAxis / m_majorAxis / m_majorAxis; double ep2 = 1.0 - ecc_sqr; double d2 = x * x + y * y; double d = sqrt(d2); double h = 0.0; int ktr = 0; double hPrev, r; // Suited for points near equator if (d >= z) { double tt, zz, n; double tanPhi = z / d; do { hPrev = h; tt = tanPhi * tanPhi; r = m_majorAxis / sqrt(1.0 + ep2 * tt); zz = z + r * ecc_sqr * tanPhi; n = r * sqrt(1.0 + tt); h = sqrt(d2 + zz * zz) - n; tanPhi = zz / d; ktr++; } while (MKTR > ktr && fabs(h - hPrev) > desired_precision); MESSAGE_LOG(m_logger, "computeElevation: point is near equator") } // Suited for points near the poles else { double cc, dd, nn; double cotPhi = d / z; do { hPrev = h; cc = cotPhi * cotPhi; r = m_majorAxis / sqrt(ep2 + cc); dd = d - r * ecc_sqr * cotPhi; nn = r * sqrt(1.0 + cc) * ep2; h = sqrt(dd * dd + z * z) - nn; cotPhi = dd / z; ktr++; } while (MKTR > ktr && fabs(h - hPrev) > desired_precision); MESSAGE_LOG(m_logger, "computeElevation: point is near poles") } height = h; achieved_precision = fabs(h - hPrev); MESSAGE_LOG(m_logger, "computeElevation: height {} with achieved" "precision of {}", height, achieved_precision) } //*************************************************************************** // UsgsAstroLsSensorModel::losEllipsoidIntersect //************************************************************************** void UsgsAstroLsSensorModel::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, double& achieved_precision, const double& desired_precision) const { MESSAGE_LOG(m_logger, "Computing losEllipsoidIntersect for camera position" "{} {} {} looking {} {} {} with desired precision" "{}", xc, yc, zc, xl, yl, zl, desired_precision) // Helper function which computes the intersection of the image ray // with the ellipsoid. All vectors are in earth-centered-fixed // coordinate system with origin at the center of the earth. const int MKTR = 10; double ap, bp, k; ap = m_majorAxis + height; bp = m_minorAxis + height; k = ap * ap / (bp * bp); // Solve quadratic equation for scale factor // applied to image ray to compute ground point double at, bt, ct, quadTerm; at = xl * xl + yl * yl + k * zl * zl; bt = 2.0 * (xl * xc + yl * yc + k * zl * zc); ct = xc * xc + yc * yc + k * zc * zc - ap * ap; quadTerm = bt * bt - 4.0 * at * ct; // If quadTerm is negative, the image ray does not // intersect the ellipsoid. Setting the quadTerm to // zero means solving for a point on the ray nearest // the surface of the ellisoid. if (0.0 > quadTerm) { quadTerm = 0.0; } double scale, scale1, h, slope; double sprev, hprev; double aPrec, sTerm; int ktr = 0; // Compute ground point vector sTerm = sqrt(quadTerm); scale = (-bt - sTerm); scale1 = (-bt + sTerm); if (fabs(scale1) < fabs(scale)) scale = scale1; scale /= (2.0 * at); x = xc + scale * xl; y = yc + scale * yl; z = zc + scale * zl; computeElevation(x, y, z, h, aPrec, desired_precision); slope = -1; achieved_precision = fabs(height - h); MESSAGE_LOG(m_logger, "losEllipsoidIntersect: found intersect at {} {} {}" "with achieved precision of {}", x, y, z, achieved_precision) } //*************************************************************************** // UsgsAstroLsSensorModel::losPlaneIntersect //************************************************************************** void UsgsAstroLsSensorModel::losPlaneIntersect( const double& xc, // input: camera x coordinate const double& yc, // input: camera y coordinate const double& zc, // input: camera z coordinate const double& xl, // input: component x image ray const double& yl, // input: component y image ray const double& zl, // input: component z image ray double& x, // input/output: ground x coordinate double& y, // input/output: ground y coordinate double& z, // input/output: ground z coordinate int& mode) const // input: -1 fixed component to be computed // 0(X), 1(Y), or 2(Z) fixed // output: 0(X), 1(Y), or 2(Z) fixed { MESSAGE_LOG(m_logger, "Calculating losPlaneIntersect for camera position" "{} {} {} and image ray {} {} {}", xc, yc, zc, xl, yl, zl) //# func_description // Computes 2 of the 3 coordinates of a ground point given the 3rd // coordinate. The 3rd coordinate that is held fixed corresponds // to the largest absolute component of the image ray. // Define fixed or largest component if (-1 == mode) { if (fabs(xl) > fabs(yl) && fabs(xl) > fabs(zl)) { mode = 0; } else if (fabs(yl) > fabs(xl) && fabs(yl) > fabs(zl)) { mode = 1; } else { mode = 2; } } MESSAGE_LOG(m_logger, "losPlaneIntersect: largest/fixed image ray component" "{} (1-x, 2-y, 3-z)", mode) // X is the fixed or largest component if (0 == mode) { y = yc + (x - xc) * yl / xl; z = zc + (x - xc) * zl / xl; } // Y is the fixed or largest component else if (1 == mode) { x = xc + (y - yc) * xl / yl; z = zc + (y - yc) * zl / yl; } // Z is the fixed or largest component else { x = xc + (z - zc) * xl / zl; y = yc + (z - zc) * yl / zl; } MESSAGE_LOG(m_logger, "ground coordinate {} {} {}", x, y, z) } //*************************************************************************** // UsgsAstroLsSensorModel::imageToPlane //*************************************************************************** void UsgsAstroLsSensorModel::imageToPlane( const double& line, // CSM Origin UL corner of UL pixel const double& sample, // CSM Origin UL corner of UL pixel const double& height, const std::vector &adj, double& x, double& y, double& z, int& mode) const { MESSAGE_LOG(m_logger, "Computing imageToPlane") //# func_description // Computes ground coordinates by intersecting image ray with // a plane perpendicular to the coordinate axis with the largest // image ray component. This routine is primarily called by // groundToImage(). // *** Computes camera position and image ray in ecf cs. double xc, yc, zc; double vx, vy, vz; double xl, yl, zl; double dxl, dyl, dzl; losToEcf(line, sample, adj, xc, yc, zc, vx, vy, vz, xl, yl, zl); losPlaneIntersect(xc, yc, zc, xl, yl, zl, x, y, z, mode); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getAdjSensorPosVel //*************************************************************************** void UsgsAstroLsSensorModel::getAdjSensorPosVel( const double& time, const std::vector &adj, double& xc, double& yc, double& zc, double& vx, double& vy, double& vz) const { MESSAGE_LOG(m_logger, "Calculating getAdjSensorPosVel at time {}", time) // Sensor position and velocity (4th or 8th order Lagrange). int nOrder = 8; if (m_platformFlag == 0) nOrder = 4; double sensPosNom[3]; lagrangeInterp(m_numPositions/3, &m_positions[0], m_t0Ephem, m_dtEphem, time, 3, nOrder, sensPosNom); double sensVelNom[3]; lagrangeInterp(m_numPositions/3, &m_velocities[0], m_t0Ephem, m_dtEphem, time, 3, nOrder, sensVelNom); MESSAGE_LOG(m_logger, "getAdjSensorPosVel: using {} order Lagrange", nOrder) // Compute rotation matrix from ICR to ECF double radialUnitVec[3]; double radMag = sqrt(sensPosNom[0] * sensPosNom[0] + sensPosNom[1] * sensPosNom[1] + sensPosNom[2] * sensPosNom[2]); for (int i = 0; i < 3; i++) radialUnitVec[i] = sensPosNom[i] / radMag; double crossTrackUnitVec[3]; crossTrackUnitVec[0] = sensPosNom[1] * sensVelNom[2] - sensPosNom[2] * sensVelNom[1]; crossTrackUnitVec[1] = sensPosNom[2] * sensVelNom[0] - sensPosNom[0] * sensVelNom[2]; crossTrackUnitVec[2] = sensPosNom[0] * sensVelNom[1] - sensPosNom[1] * sensVelNom[0]; double crossMag = sqrt(crossTrackUnitVec[0] * crossTrackUnitVec[0] + crossTrackUnitVec[1] * crossTrackUnitVec[1] + crossTrackUnitVec[2] * crossTrackUnitVec[2]); for (int i = 0; i < 3; i++) crossTrackUnitVec[i] /= crossMag; double inTrackUnitVec[3]; inTrackUnitVec[0] = crossTrackUnitVec[1] * radialUnitVec[2] - crossTrackUnitVec[2] * radialUnitVec[1]; inTrackUnitVec[1] = crossTrackUnitVec[2] * radialUnitVec[0] - crossTrackUnitVec[0] * radialUnitVec[2]; inTrackUnitVec[2] = crossTrackUnitVec[0] * radialUnitVec[1] - crossTrackUnitVec[1] * radialUnitVec[0]; double ecfFromIcr[9]; ecfFromIcr[0] = inTrackUnitVec[0]; ecfFromIcr[1] = crossTrackUnitVec[0]; ecfFromIcr[2] = radialUnitVec[0]; ecfFromIcr[3] = inTrackUnitVec[1]; ecfFromIcr[4] = crossTrackUnitVec[1]; ecfFromIcr[5] = radialUnitVec[1]; ecfFromIcr[6] = inTrackUnitVec[2]; ecfFromIcr[7] = crossTrackUnitVec[2]; ecfFromIcr[8] = radialUnitVec[2]; // Apply position and velocity corrections double aTime = time - m_t0Ephem; double dvi = getValue(3, adj) / m_halfTime; double dvc = getValue(4, adj) / m_halfTime; double dvr = getValue(5, adj) / m_halfTime; vx = sensVelNom[0] + ecfFromIcr[0] * dvi + ecfFromIcr[1] * dvc + ecfFromIcr[2] * dvr; vy = sensVelNom[1] + ecfFromIcr[3] * dvi + ecfFromIcr[4] * dvc + ecfFromIcr[5] * dvr; vz = sensVelNom[2] + ecfFromIcr[6] * dvi + ecfFromIcr[7] * dvc + ecfFromIcr[8] * dvr; double di = getValue(0, adj) + dvi * aTime; double dc = getValue(1, adj) + dvc * aTime; double dr = getValue(2, adj) + dvr * aTime; xc = sensPosNom[0] + ecfFromIcr[0] * di + ecfFromIcr[1] * dc + ecfFromIcr[2] * dr; yc = sensPosNom[1] + ecfFromIcr[3] * di + ecfFromIcr[4] * dc + ecfFromIcr[5] * dr; zc = sensPosNom[2] + ecfFromIcr[6] * di + ecfFromIcr[7] * dc + ecfFromIcr[8] * dr; MESSAGE_LOG(m_logger, "getAdjSensorPosVel: postition {} {} {}" "and velocity {} {} {}", xc, yc, zc, vx, vy, vz) } //*************************************************************************** // UsgsAstroLineScannerSensorModel::computeViewingPixel //*************************************************************************** csm::ImageCoord UsgsAstroLsSensorModel::computeViewingPixel( const double& time, const csm::EcefCoord& groundPoint, const std::vector& adj, const double& desiredPrecision) const { MESSAGE_LOG(m_logger, "Computing computeViewingPixel (with adjusments)" "for ground point {} {} {} at time {} ", groundPoint.x, groundPoint.y, groundPoint.z, time) // Helper function to compute the CCD pixel that views a ground point based // on the exterior orientation at a given time. // Get the exterior orientation double xc, yc, zc, vx, vy, vz; getAdjSensorPosVel(time, adj, xc, yc, zc, vx, vy, vz); // Compute the look vector double bodyLookX = groundPoint.x - xc; double bodyLookY = groundPoint.y - yc; double bodyLookZ = groundPoint.z - zc; MESSAGE_LOG(m_logger, "computeViewingPixel: look vector {} {} {}", bodyLookX, bodyLookY, bodyLookZ) // Rotate the look vector into the camera reference frame double quaternions[4]; getQuaternions(time, quaternions); double bodyToCamera[9]; calculateRotationMatrixFromQuaternions(quaternions, bodyToCamera); // Apply transpose of matrix to rotate body->camera double cameraLookX = bodyToCamera[0] * bodyLookX + bodyToCamera[3] * bodyLookY + bodyToCamera[6] * bodyLookZ; double cameraLookY = bodyToCamera[1] * bodyLookX + bodyToCamera[4] * bodyLookY + bodyToCamera[7] * bodyLookZ; double cameraLookZ = bodyToCamera[2] * bodyLookX + bodyToCamera[5] * bodyLookY + bodyToCamera[8] * bodyLookZ; MESSAGE_LOG(m_logger, "computeViewingPixel: look vector (camrea ref frame)" "{} {} {}", cameraLookX, cameraLookY, cameraLookZ) // Invert the attitude correction double attCorr[9]; calculateAttitudeCorrection(time, adj, attCorr); // Apply transpose of matrix to invert the attidue correction double adjustedLookX = attCorr[0] * cameraLookX + attCorr[3] * cameraLookY + attCorr[6] * cameraLookZ; double adjustedLookY = attCorr[1] * cameraLookX + attCorr[4] * cameraLookY + attCorr[7] * cameraLookZ; double adjustedLookZ = attCorr[2] * cameraLookX + attCorr[5] * cameraLookY + attCorr[8] * cameraLookZ; MESSAGE_LOG(m_logger, "computeViewingPixel: adjusted look vector" "{} {} {}", adjustedLookX, adjustedLookY, adjustedLookZ) // Convert to focal plane coordinate double lookScale = m_focalLength / adjustedLookZ; double focalX = adjustedLookX * lookScale; double focalY = adjustedLookY * lookScale; double distortedFocalX, distortedFocalY; MESSAGE_LOG(m_logger, "computeViewingPixel: focal plane coordinates" "x:{} y:{} scale:{}", focalX, focalY, lookScale) // Invert distortion applyDistortion(focalX, focalY, distortedFocalX, distortedFocalY, m_opticalDistCoeffs, m_distortionType, desiredPrecision); // Convert to detector line and sample double detectorLine = m_iTransL[0] + m_iTransL[1] * distortedFocalX + m_iTransL[2] * distortedFocalY; double detectorSample = m_iTransS[0] + m_iTransS[1] * distortedFocalX + m_iTransS[2] * distortedFocalY; // Convert to image sample line double line = detectorLine + m_detectorLineOrigin; double sample = (detectorSample + m_detectorSampleOrigin - m_startingSample) / m_detectorSampleSumming; MESSAGE_LOG(m_logger, "computeViewingPixel: image line sample {} {}", line, sample) return csm::ImageCoord(line, sample); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::computeLinearApproximation //*************************************************************************** void UsgsAstroLsSensorModel::computeLinearApproximation( const csm::EcefCoord &gp, csm::ImageCoord &ip) const { if (_linear) { ip.line = _u0 + _du_dx * gp.x + _du_dy * gp.y + _du_dz * gp.z; ip.samp = _v0 + _dv_dx * gp.x + _dv_dy * gp.y + _dv_dz * gp.z; // Since this is valid only over image, // don't let result go beyond the image border. double numRows = m_nLines; double numCols = m_nSamples; if (ip.line < 0.0) ip.line = 0.0; if (ip.line > numRows) ip.line = numRows; if (ip.samp < 0.0) ip.samp = 0.0; if (ip.samp > numCols) ip.samp = numCols; MESSAGE_LOG(m_logger, "Computing computeLinearApproximation" "with linear approximation") } else { ip.line = m_nLines / 2.0; ip.samp = m_nSamples / 2.0; MESSAGE_LOG(m_logger, "Computing computeLinearApproximation" "nonlinear approx line/2 and sample/2") } } //*************************************************************************** // UsgsAstroLineScannerSensorModel::setLinearApproximation //*************************************************************************** void UsgsAstroLsSensorModel::setLinearApproximation() { MESSAGE_LOG(m_logger, "Calculating setLinearApproximation") double u_factors[4] = { 0.0, 0.0, 1.0, 1.0 }; double v_factors[4] = { 0.0, 1.0, 0.0, 1.0 }; csm::EcefCoord refPt = getReferencePoint(); double height, aPrec; double desired_precision = 0.01; computeElevation(refPt.x, refPt.y, refPt.z, height, aPrec, desired_precision); if (isnan(height)) { MESSAGE_LOG(m_logger, "setLinearApproximation: computeElevation of" "reference point {} {} {} with desired precision" "{} returned nan height; nonlinear", refPt.x, refPt.y, refPt.z, desired_precision) _linear = false; return; } MESSAGE_LOG(m_logger, "setLinearApproximation: computeElevation of" "reference point {} {} {} with desired precision" "{} returned {} height", refPt.x, refPt.y, refPt.z, desired_precision, height) double numRows = m_nLines; double numCols = m_nSamples; csm::ImageCoord imagePt; csm::EcefCoord gp[8]; int i; for (i = 0; i < 4; i++) { imagePt.line = u_factors[i] * numRows; imagePt.samp = v_factors[i] * numCols; gp[i] = imageToGround(imagePt, height); } double delz = 100.0; height += delz; for (i = 0; i < 4; i++) { imagePt.line = u_factors[i] * numRows; imagePt.samp = v_factors[i] * numCols; gp[i + 4] = imageToGround(imagePt, height); } csm::EcefCoord d_du; d_du.x = ( (gp[2].x + gp[3].x + gp[6].x + gp[7].x) - (gp[0].x + gp[1].x + gp[4].x + gp[5].x)) / numRows / 4.0; d_du.y = ( (gp[2].y + gp[3].y + gp[6].y + gp[7].y) - (gp[0].y + gp[1].y + gp[4].y + gp[5].y)) / numRows / 4.0; d_du.z = ( (gp[2].z + gp[3].z + gp[6].z + gp[7].z) - (gp[0].z + gp[1].z + gp[4].z + gp[5].z)) / numRows / 4.0; csm::EcefCoord d_dv; d_dv.x = ( (gp[1].x + gp[3].x + gp[5].x + gp[7].x) - (gp[0].x + gp[2].x + gp[4].x + gp[6].x)) / numCols / 4.0; d_dv.y = ( (gp[1].y + gp[3].y + gp[5].y + gp[7].y) - (gp[0].y + gp[2].y + gp[4].y + gp[6].y)) / numCols / 4.0; d_dv.z = ( (gp[1].z + gp[3].z + gp[5].z + gp[7].z) - (gp[0].z + gp[2].z + gp[4].z + gp[6].z)) / numCols / 4.0; double mat3x3[9]; mat3x3[0] = d_du.x; mat3x3[1] = d_dv.x; mat3x3[2] = 1.0; mat3x3[3] = d_du.y; mat3x3[4] = d_dv.y; mat3x3[5] = 1.0; mat3x3[6] = d_du.z; mat3x3[7] = d_dv.z; mat3x3[8] = 1.0; double denom = determinant3x3(mat3x3); if (fabs(denom) < 1.0e-8) // can not get derivatives this way { MESSAGE_LOG(m_logger, "setLinearApproximation: determinant3x3 of" "matrix of partials is {}; nonlinear", denom) _linear = false; return; } mat3x3[0] = 1.0; mat3x3[3] = 0.0; mat3x3[6] = 0.0; _du_dx = determinant3x3(mat3x3) / denom; mat3x3[0] = 0.0; mat3x3[3] = 1.0; mat3x3[6] = 0.0; _du_dy = determinant3x3(mat3x3) / denom; mat3x3[0] = 0.0; mat3x3[3] = 0.0; mat3x3[6] = 1.0; _du_dz = determinant3x3(mat3x3) / denom; mat3x3[0] = d_du.x; mat3x3[3] = d_du.y; mat3x3[6] = d_du.z; mat3x3[1] = 1.0; mat3x3[4] = 0.0; mat3x3[7] = 0.0; _dv_dx = determinant3x3(mat3x3) / denom; mat3x3[1] = 0.0; mat3x3[4] = 1.0; mat3x3[7] = 0.0; _dv_dy = determinant3x3(mat3x3) / denom; mat3x3[1] = 0.0; mat3x3[4] = 0.0; mat3x3[7] = 1.0; _dv_dz = determinant3x3(mat3x3) / denom; _u0 = -gp[0].x * _du_dx - gp[0].y * _du_dy - gp[0].z * _du_dz; _v0 = -gp[0].x * _dv_dx - gp[0].y * _dv_dy - gp[0].z * _dv_dz; _linear = true; MESSAGE_LOG(m_logger, "Completed setLinearApproximation") } //*************************************************************************** // UsgsAstroLineScannerSensorModel::determinant3x3 //*************************************************************************** double UsgsAstroLsSensorModel::determinant3x3(double mat[9]) const { return mat[0] * (mat[4] * mat[8] - mat[7] * mat[5]) - mat[1] * (mat[3] * mat[8] - mat[6] * mat[5]) + mat[2] * (mat[3] * mat[7] - mat[6] * mat[4]); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::constructStateFromIsd //*************************************************************************** std::string UsgsAstroLsSensorModel::constructStateFromIsd(const std::string imageSupportData, csm::WarningList *warnings) const { MESSAGE_LOG(m_logger, "Constructing state from Isd") // Instantiate UsgsAstroLineScanner sensor model json isd = json::parse(imageSupportData); json state = {}; csm::WarningList* parsingWarnings = new csm::WarningList; int num_params = NUM_PARAMETERS; state["m_modelName"] = getSensorModelName(isd, parsingWarnings); state["m_imageIdentifier"] = getImageId(isd, parsingWarnings); state["m_sensorName"] = getSensorName(isd, parsingWarnings); state["m_platformName"] = getPlatformName(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_modelName: {} " "m_imageIdentifier: {} " "m_sensorName: {} " "m_platformName: {} ", state["m_modelName"].dump(), state["m_imageIdentifier"].dump(), state["m_sensorName"].dump(), state["m_platformName"].dump()) state["m_focalLength"] = getFocalLength(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_focalLength: {} ", state["m_focalLength"].dump()) state["m_nLines"] = getTotalLines(isd, parsingWarnings); state["m_nSamples"] = getTotalSamples(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_nLines: {} " "m_nSamples: {} ", state["m_nLines"].dump(), state["m_nSamples"].dump()) state["m_iTransS"] = getFocal2PixelSamples(isd, parsingWarnings); state["m_iTransL"] = getFocal2PixelLines(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_iTransS: {} " "m_iTransL: {} ", state["m_iTransS"].dump(), state["m_iTransL"].dump()) state["m_platformFlag"] = 1; state["m_ikCode"] = 0; state["m_zDirection"] = 1; MESSAGE_LOG(m_logger, "m_platformFlag: {} " "m_ikCode: {} " "m_zDirection: {} ", state["m_platformFlag"].dump(), state["m_ikCode"].dump(), state["m_zDirection"].dump()) state["m_distortionType"] = getDistortionModel(isd, parsingWarnings); state["m_opticalDistCoeffs"] = getDistortionCoeffs(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_distortionType: {} " "m_opticalDistCoeffs: {} ", state["m_distortionType"].dump(), state["m_opticalDistCoeffs"].dump()) // Zero computed state values state["m_referencePointXyz"] = std::vector(3, 0.0); MESSAGE_LOG(m_logger, "m_referencePointXyz: {} ", state["m_referencePointXyz"].dump()) // leave these be for now. state["m_gsd"] = 1.0; state["m_flyingHeight"] = 1000.0; state["m_halfSwath"] = 1000.0; state["m_halfTime"] = 10.0; MESSAGE_LOG(m_logger, "m_gsd: {} " "m_flyingHeight: {} " "m_halfSwath: {} " "m_halfTime: {} ", state["m_gsd"].dump(), state["m_flyingHeight"].dump(), state["m_halfSwath"].dump(), state["m_halfTime"].dump()) state["m_centerEphemerisTime"] = getCenterTime(isd, parsingWarnings); state["m_startingEphemerisTime"] = getStartingTime(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_centerEphemerisTime: {} " "m_startingEphemerisTime: {} ", state["m_centerEphemerisTime"].dump(), state["m_startingEphemerisTime"].dump()) state["m_intTimeLines"] = getIntegrationStartLines(isd, parsingWarnings); state["m_intTimeStartTimes"] = getIntegrationStartTimes(isd, parsingWarnings); state["m_intTimes"] = getIntegrationTimes(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_intTimeLines: {} " "m_intTimeStartTimes: {} " "m_intTimes: {} ", state["m_intTimeLines"].dump(), state["m_intTimeStartTimes"].dump(), state["m_intTimes"].dump()) state["m_detectorSampleSumming"] = getSampleSumming(isd, parsingWarnings); state["m_startingDetectorSample"] = getDetectorStartingSample(isd, parsingWarnings); state["m_startingDetectorLine"] = getDetectorStartingLine(isd, parsingWarnings); state["m_detectorSampleOrigin"] = getDetectorCenterSample(isd, parsingWarnings); state["m_detectorLineOrigin"] = getDetectorCenterLine(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_detectorSampleSumming: {} " "m_startingDetectorSample: {} " "m_startingDetectorLine: {} " "m_detectorSampleOrigin: {} " "m_detectorLineOrigin: {} ", state["m_detectorSampleSumming"].dump(), state["m_startingDetectorSample"].dump(), state["m_startingDetectorLine"].dump(), state["m_detectorSampleOrigin"].dump(), state["m_detectorLineOrigin"].dump()) // These are exlusive to LineScanners, leave them here for now. try { state["m_dtEphem"] = isd.at("dt_ephemeris"); MESSAGE_LOG(m_logger, "m_dtEphem: {} ", state["m_dtEphem"].dump()) } catch(...) { parsingWarnings->push_back( csm::Warning( csm::Warning::DATA_NOT_AVAILABLE, "dt_ephemeris not in ISD", "UsgsAstroFrameSensorModel::constructStateFromIsd()")); MESSAGE_LOG(m_logger, "m_dtEphem not in ISD") } try { state["m_t0Ephem"] = isd.at("t0_ephemeris"); MESSAGE_LOG(m_logger, "t0_ephemeris: {}", state["m_t0Ephem"].dump()) } catch(...) { parsingWarnings->push_back( csm::Warning( csm::Warning::DATA_NOT_AVAILABLE, "t0_ephemeris not in ISD", "UsgsAstroFrameSensorModel::constructStateFromIsd()")); MESSAGE_LOG(m_logger, "t0_ephemeris not in ISD") } try{ state["m_dtQuat"] = isd.at("dt_quaternion"); MESSAGE_LOG(m_logger, "dt_quaternion: {}", state["m_dtQuat"].dump()) } catch(...) { parsingWarnings->push_back( csm::Warning( csm::Warning::DATA_NOT_AVAILABLE, "dt_quaternion not in ISD", "UsgsAstroFrameSensorModel::constructStateFromIsd()")); MESSAGE_LOG(m_logger, "dt_quaternion not in ISD") } try{ state["m_t0Quat"] = isd.at("t0_quaternion"); MESSAGE_LOG(m_logger, "m_t0Quat: {}", state["m_t0Quat"].dump()) } catch(...) { parsingWarnings->push_back( csm::Warning( csm::Warning::DATA_NOT_AVAILABLE, "t0_quaternion not in ISD", "UsgsAstroFrameSensorModel::constructStateFromIsd()")); MESSAGE_LOG(m_logger, "t0_quaternion not in ISD") } std::vector positions = getSensorPositions(isd, parsingWarnings); state["m_positions"] = positions; state["m_numPositions"] = positions.size(); MESSAGE_LOG(m_logger, "m_positions: {}" "m_numPositions: {}", state["m_positions"].dump(), state["m_numPositions"].dump()) state["m_velocities"] = getSensorVelocities(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_velocities: {}", state["m_velocities"].dump()) std::vector quaternions = getSensorOrientations(isd, parsingWarnings); state["m_quaternions"] = quaternions; state["m_numQuaternions"] = quaternions.size(); MESSAGE_LOG(m_logger, "m_quaternions: {}" "m_numQuaternions: {}", state["m_quaternions"].dump(), state["m_numQuaternions"].dump()) state["m_currentParameterValue"] = std::vector(NUM_PARAMETERS, 0.0); MESSAGE_LOG(m_logger, "m_currentParameterValue: {}", state["m_currentParameterValue"].dump()) // get radii state["m_minorAxis"] = getSemiMinorRadius(isd, parsingWarnings); state["m_majorAxis"] = getSemiMajorRadius(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_minorAxis: {}" "m_majorAxis: {}", state["m_minorAxis"].dump(), state["m_majorAxis"].dump()) // set identifiers state["m_platformIdentifier"] = getPlatformName(isd, parsingWarnings); state["m_sensorIdentifier"] = getSensorName(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_platformIdentifier: {}" "m_sensorIdentifier: {}", state["m_platformIdentifier"].dump(), state["m_sensorIdentifier"].dump()) // get reference_height state["m_minElevation"] = getMinHeight(isd, parsingWarnings); state["m_maxElevation"] = getMaxHeight(isd, parsingWarnings); MESSAGE_LOG(m_logger, "m_minElevation: {}" "m_maxElevation: {}", state["m_minElevation"].dump(), state["m_maxElevation"].dump()) // Default to identity covariance state["m_covariance"] = std::vector(NUM_PARAMETERS * NUM_PARAMETERS, 0.0); for (int i = 0; i < NUM_PARAMETERS; i++) { state["m_covariance"][i * NUM_PARAMETERS + i] = 1.0; } // Get the optional logging file state["m_logFile"] = getLogFile(isd); // The state data will still be updated when a sensor model is created since // some state data is notin the ISD and requires a SM to compute them. return state.dump(); } //*************************************************************************** // UsgsAstroLineScannerSensorModel::getLogger //*************************************************************************** std::shared_ptr UsgsAstroLsSensorModel::getLogger() { // MESSAGE_LOG(m_logger, "Getting log pointer, logger is {}", // m_logger) return m_logger; } void UsgsAstroLsSensorModel::setLogger(std::shared_ptr logger) { m_logger = logger; }