diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f1ecd465a..1e322c6c97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ release. ## [Unreleased] ### Added +- Added adjusted XYZ point coordinate sigmas to the points.csv jigsaw output file. Modified +ctest FunctionalTestJigsawApollo to validate this output. [#5710](https://github.com/DOI-USGS/ISIS3/issues/5710) ### Changed diff --git a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp index 512dc2de7b..fddd8a8df0 100755 --- a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp +++ b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp @@ -1611,32 +1611,47 @@ namespace Isis { double dLat, dLon, dRadius; double dX, dY, dZ; - double dSigmaLat, dSigmaLong, dSigmaRadius; QString strStatus; double cor_lat_dd = 0.0; // lat correction, decimal degrees double cor_lon_dd = 0.0; // lon correction, decimal degrees double cor_rad_km = 0.0; // radius correction, kilometers + double cor_lat_m = 0.0; // lat correction, meters double cor_lon_m = 0.0; // lon correction, meters double cor_rad_m = 0.0; // radius correction, meters + + double cor_x_km = 0.0; // x correction, kilometers + double cor_y_km = 0.0; // y correction, kilometers + double cor_z_km = 0.0; // z correction, kilometers + double latInit = Isis::Null; double lonInit = Isis::Null; double radInit = Isis::Null; + int numMeasures, numRejectedMeasures; double dResidualRms; + // bundle coordinate type (Lat, Lon, Radius or XYZ) + bool bundleLatLonRadius = true; + if ( m_settings->controlPointCoordTypeBundle() == SurfacePoint::Rectangular ) { + bundleLatLonRadius = false; + } + // print column headers if (m_settings->errorPropagation()) { - snprintf(buf, sizeof(buf), ",,,,,3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction,Coordinate," - "Coordinate,Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude," - "Radius,Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\nLabel,Status," - "Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km)\n"); + snprintf(buf, sizeof(buf), ",,,,,3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction," + "Coordinate,Coordinate,Coordinate,Sigma,Sigma,Sigma\n" + "Point,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius,Latitude,Longitude," + "Radius,Latitude,Longitude,Radius,X,Y,Z,X,Y,Z\n" + "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km)," + "(m),(m),(m)\n"); } else { - snprintf(buf, sizeof(buf), ",,,,,3-d,3-d,3-d,Correction,Correction,Correction,Coordinate,Coordinate," - "Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius," - "Latitude,Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures,RMS,(dd),(dd),(km)," - "(m),(m),(m),(km),(km),(km)\n"); + snprintf(buf, sizeof(buf), ",,,,,3-d,3-d,3-d,Correction,Correction,Correction,Coordinate," + "Coordinate,Coordinate\n" + "Point,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius,Latitude,Longitude," + "Radius,X,Y,Z\n" + "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(km),(km),(km)\n"); } fpOut << buf; @@ -1651,53 +1666,53 @@ namespace Isis { continue; } - dLat = bundlecontrolpoint->adjustedSurfacePoint().GetLatitude().degrees(); - dLon = bundlecontrolpoint->adjustedSurfacePoint().GetLongitude().degrees(); - dRadius = bundlecontrolpoint->adjustedSurfacePoint().GetLocalRadius().kilometers(); - dX = bundlecontrolpoint->adjustedSurfacePoint().GetX().kilometers(); - dY = bundlecontrolpoint->adjustedSurfacePoint().GetY().kilometers(); - dZ = bundlecontrolpoint->adjustedSurfacePoint().GetZ().kilometers(); + dLat = bundlecontrolpoint->adjustedSurfacePoint().GetLatitude().degrees(); + dLon = bundlecontrolpoint->adjustedSurfacePoint().GetLongitude().degrees(); + dRadius = bundlecontrolpoint->adjustedSurfacePoint().GetLocalRadius().kilometers(); + dX = bundlecontrolpoint->adjustedSurfacePoint().GetX().kilometers(); + dY = bundlecontrolpoint->adjustedSurfacePoint().GetY().kilometers(); + dZ = bundlecontrolpoint->adjustedSurfacePoint().GetZ().kilometers(); numMeasures = bundlecontrolpoint->numberOfMeasures(); numRejectedMeasures = bundlecontrolpoint->numberOfRejectedMeasures(); - dResidualRms = bundlecontrolpoint->residualRms(); + dResidualRms = bundlecontrolpoint->residualRms(); // Use the local radius in meters, rad*1000., to convert radians to meters now instead of the // target body equatorial radius (DAC 09/17/2018; from BundleControlPoint.cpp) double rtm = dRadius * 1000.; - // point corrections and initial sigmas + // point corrections + // Latitude, Longitude corrections are decimal degrees; + // Radius correction is kilometers boost::numeric::ublas::bounded_vector< double, 3 > corrections = bundlecontrolpoint-> corrections(); - if (m_settings->controlPointCoordTypeBundle() == SurfacePoint::Rectangular) { - double xCor = corrections(0); // km - double yCor = corrections(1); // km - double zCor = corrections(2); // km + // solution is rectangular (point coordinates are X,Y,Z) + // must compute latitudinal initial coordinates and corrections + if (bundleLatLonRadius == false) { + cor_x_km = corrections(0); + cor_y_km = corrections(1); + cor_z_km = corrections(2); if (!IsSpecial(dX) && !IsSpecial(dY) && !IsSpecial(dZ)) { - SurfacePoint rectPoint(Displacement(dX - xCor, Displacement::Kilometers), - Displacement(dY - yCor, Displacement::Kilometers), - Displacement(dZ - zCor, Displacement::Kilometers)); + SurfacePoint rectInitPoint(Displacement(dX - cor_x_km, Displacement::Kilometers), + Displacement(dY - cor_y_km, Displacement::Kilometers), + Displacement(dZ - cor_z_km, Displacement::Kilometers)); - latInit = rectPoint.GetLatitude().degrees(); - lonInit = rectPoint.GetLongitude().degrees(); - radInit = rectPoint.GetLocalRadius().kilometers(); + latInit = rectInitPoint.GetLatitude().degrees(); + lonInit = rectInitPoint.GetLongitude().degrees(); + radInit = rectInitPoint.GetLocalRadius().kilometers(); - if (!IsSpecial(dLat)) { - cor_lat_dd = (dLat - latInit); // degrees - cor_lat_m = cor_lat_dd * DEG2RAD * rtm; - } - if (!IsSpecial(dLon)) { - cor_lon_dd = (dLon - lonInit); // degrees - cor_lon_m = cor_lon_dd * DEG2RAD * rtm * cos(dLat*DEG2RAD); // lon corrections meters - } - if (!IsSpecial(dRadius)) { - cor_rad_km = dRadius - radInit; - cor_rad_m = cor_rad_km * 1000.; - } + cor_lat_dd = (dLat - latInit); // degrees + cor_lon_dd = (dLon - lonInit); // degrees + cor_rad_km = dRadius - radInit; + + cor_lat_m = cor_lat_dd * DEG2RAD * rtm; + cor_lon_m = cor_lon_dd * DEG2RAD * rtm * cos(dLat*DEG2RAD); // lon corrections meters + cor_rad_m = cor_rad_km * 1000.; } } - else if (m_settings->controlPointCoordTypeBundle() == SurfacePoint::Latitudinal) { + // solution is latitudinal (point coordinates are Latitude, Longitude, Radius) + else if (bundleLatLonRadius == true) { cor_lat_dd = corrections(0) * RAD2DEG; // lat correction, decimal degs cor_lon_dd = corrections(1) * RAD2DEG; // lon correction, decimal degs cor_rad_m = corrections(2) * 1000.0; // radius correction, meters @@ -1706,16 +1721,14 @@ namespace Isis { cor_lon_m = bundlecontrolpoint->adjustedSurfacePoint().LongitudeToMeters(corrections(1)); cor_rad_km = corrections(2); - if (!IsSpecial(dLat)) { - latInit = dLat - cor_lat_dd; - } - - if (!IsSpecial(dLon)) { - lonInit = dLon - cor_lon_dd; - } + if (!IsSpecial(dLat) && !IsSpecial(dLon) && !IsSpecial(dRadius)) { + SurfacePoint latInitPoint(Latitude(dLat - cor_lat_dd, Angle::Degrees), + Longitude(dLon - cor_lon_dd, Angle::Degrees), + Distance(dRadius - corrections(2), Distance::Kilometers)); - if (!IsSpecial(dRadius)) { - radInit = dRadius - corrections(2); // km + latInit = latInitPoint.GetLatitude().degrees(); + lonInit = latInitPoint.GetLongitude().degrees(); + radInit = latInitPoint.GetLocalRadius().kilometers(); } } @@ -1733,22 +1746,31 @@ namespace Isis { } if (m_settings->errorPropagation()) { + double dSigmaLat, dSigmaLong, dSigmaRadius; + double dSigmaX, dSigmaY, dSigmaZ; + dSigmaLat = bundlecontrolpoint->adjustedSurfacePoint().GetLatSigmaDistance().meters(); dSigmaLong = bundlecontrolpoint->adjustedSurfacePoint().GetLonSigmaDistance().meters(); dSigmaRadius = bundlecontrolpoint->adjustedSurfacePoint().GetLocalRadiusSigma().meters(); - snprintf(buf, sizeof(buf), "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," - "%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf\n", - bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(), - numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, dSigmaLat, - dSigmaLong, dSigmaRadius, cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ); + dSigmaX = bundlecontrolpoint->adjustedSurfacePoint().GetXSigma().meters(); + dSigmaY = bundlecontrolpoint->adjustedSurfacePoint().GetYSigma().meters(); + dSigmaZ = bundlecontrolpoint->adjustedSurfacePoint().GetZSigma().meters(); + + snprintf(buf, sizeof(buf), "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," + "%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," + "%16.8lf\n", + bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(), + numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, dSigmaLat, + dSigmaLong, dSigmaRadius, cor_lat_m, cor_lon_m, cor_rad_m, dX, dY, dZ, + dSigmaX,dSigmaY,dSigmaZ); } else - snprintf(buf, sizeof(buf), "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," - "%16.8lf,%16.8lf\n", - bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(), - numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, cor_lat_m, - cor_lon_m, cor_rad_m, dX, dY, dZ); + snprintf(buf, sizeof(buf), "%s,%s,%d,%d,%6.2lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf,%16.8lf," + "%16.8lf,%16.8lf,%16.8lf\n", + bundlecontrolpoint->id().toLatin1().data(), strStatus.toLatin1().data(), + numMeasures, numRejectedMeasures, dResidualRms, dLat, dLon, dRadius, cor_lat_m, + cor_lon_m, cor_rad_m, dX, dY, dZ); fpOut << buf; } diff --git a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h index 170efe0311..c1e6be6c1c 100755 --- a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h +++ b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h @@ -168,6 +168,8 @@ namespace Isis { * bundle adjustment, the Lat/Lon/Radius point corrections written * to the points.csv file are incorrect and do not match those written * to the bundleout.txt file. + * @history 2025-01-19 Ken Edmundson - Added three columns to the end of each line in the + * points.csv file for the adjusted XYZ point sigmas. */ class BundleSolutionInfo : public QObject { Q_OBJECT diff --git a/isis/tests/FunctionalTestsJigsaw.cpp b/isis/tests/FunctionalTestsJigsaw.cpp index 9ec8ba322c..50008ebe62 100644 --- a/isis/tests/FunctionalTestsJigsaw.cpp +++ b/isis/tests/FunctionalTestsJigsaw.cpp @@ -69,18 +69,18 @@ TEST_F(ApolloNetwork, FunctionalTestJigsawApollo) { int numColumns = line.columns(); int numRows = line.rows(); - ASSERT_EQ(numColumns, 12); + ASSERT_EQ(numColumns, 15); ASSERT_EQ(numRows, 398); // Validate the line information is correct csvLine = line.getRow(0); - compareCsvLine(csvLine, "3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction,Coordinate,Coordinate,Coordinate"); + compareCsvLine(csvLine, "3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction,Coordinate,Coordinate,Coordinate,Sigma,Sigma,Sigma"); csvLine = line.getRow(1); - compareCsvLine(csvLine, "Point,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius,Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z"); + compareCsvLine(csvLine, "Point,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius,Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z,X,Y,Z"); csvLine = line.getRow(2); - compareCsvLine(csvLine, "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km)"); + compareCsvLine(csvLine, "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km),(m),(m),(m)"); // Compare all of the values from the network against the values in the CSV QList points = outputNet.GetPoints(); @@ -115,14 +115,14 @@ TEST_F(ApolloNetwork, FunctionalTestJigsawApollo) { // Spot check a few points for hard-coded values // A few "Free" points: - compareCsvLine(line.getRow(30), "AS15_000031957,FREE,3,0,0.33,24.25013429,6.15097050,1735.93990543,270.68671676,265.71819251,500.96944842,860.25781493,-1823.63228489,-677.74533463,1573.65050943,169.59077243,712.98695596"); - compareCsvLine(line.getRow(185), "AS15_000055107,FREE,2,0,2.22,24.26598395,6.75841991,1735.27498710,303.08885516,295.63588060,562.91712019,876.14367347,-1869.62276530,-708.50440630,1570.96622187,186.17020493,713.15150243"); - compareCsvLine(line.getRow(396), "AS15_Tie14,FREE,4,0,0.76,23.34007344,4.52764905,1737.15233677,245.96412227,251.30260955,443.11518635,1022.08062058,-1897.32816475,-372.27330000,1590.02287614,125.90958874,688.23852695"); + compareCsvLine(line.getRow(30), "AS15_000031957,FREE,3,0,0.33,24.25013429,6.15097050,1735.93990543,270.68671676,265.71819251,500.96944842,860.25781493,-1823.63228489,-677.74533463,1573.65050943,169.59077243,712.98695596, 465.66755434, 267.66330908, 326.12562996"); + compareCsvLine(line.getRow(185), "AS15_000055107,FREE,2,0,2.22,24.26598395,6.75841991,1735.27498710,303.08885516,295.63588060,562.91712019,876.14367347,-1869.62276530,-708.50440630,1570.96622187,186.17020493,713.15150243, 522.79515846, 298.42172842, 365.74418181"); + compareCsvLine(line.getRow(396), "AS15_Tie14,FREE,4,0,0.76,23.34007344,4.52764905,1737.15233677,245.96412227,251.30260955,443.11518635,1022.08062058,-1897.32816475,-372.27330000,1590.02287614,125.90958874,688.23852695, 414.98905206, 251.82613853, 290.46531976"); // A few "Constrained" points: - compareCsvLine(line.getRow(352), "AS15_SocetPAN_01,CONSTRAINED,3,0,0.27,27.61487917,2.18951566,1735.78407271,160.95596643,162.33483092,285.90375398,103.62041173,223.18286146,306.44770820,1536.92627520,58.76110229,804.58132250", 2); - compareCsvLine(line.getRow(360), "AS15_SocetPAN_10,CONSTRAINED,4,0,1.14,25.96587004,3.54262524,1735.72172102,113.85794037,113.34020561,189.03901900,-54.11385318,174.35206231,4.97102217,1557.52735013,96.42556502,759.96089165", 2); - compareCsvLine(line.getRow(380), "AS15_SocetPAN_40,CONSTRAINED,2,0,0.42,25.77498986,1.88090884,1735.56132012,133.81392881,132.83513465,230.53187100,23.85721304,82.06385794,171.57011514,1562.04594097,51.29735448,754.68811810", 2); + compareCsvLine(line.getRow(352), "AS15_SocetPAN_01,CONSTRAINED,3,0,0.27,27.61487917,2.18951566,1735.78407271,160.95596643,162.33483092,285.90375398,103.62041173,223.18286146,306.44770820,1536.92627520,58.76110229,804.58132250, 265.9686138, 162.53199952, 191.94901028", 2); + compareCsvLine(line.getRow(360), "AS15_SocetPAN_10,CONSTRAINED,4,0,1.14,25.96587004,3.54262524,1735.72172102,113.85794037,113.34020561,189.03901900,-54.11385318,174.35206231,4.97102217,1557.52735013,96.42556502,759.96089165, 176.89344204, 113.71419, 131.61753927", 2); + compareCsvLine(line.getRow(380), "AS15_SocetPAN_40,CONSTRAINED,2,0,0.42,25.77498986,1.88090884,1735.56132012,133.81392881,132.83513465,230.53187100,23.85721304,82.06385794,171.57011514,1562.04594097,51.29735448,754.68811810, 214.5688998, 133.00415652, 158.00748601", 2); // Check for the correct line output format and csv file structure for the images.csv file line = CSVReader(imagesOutput,